@@ -4058,24+4058,46 @@ CONFIG_SCSI_NCR53C406A say M here and read Documentation/modules.txt. The module will be
called NCR53c406.o.
-Tekram DC390(T) (AMD PCscsi) SCSI support
+Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
CONFIG_SCSI_DC390T
- This driver supports the Tekram DC390(T) PCI SCSI host adapter with
- the Am53C974A chip, and perhaps other cards using the same chip.
- This driver does _not_ support the DC390W/U/F adaptor with the
- NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one.
+ This driver supports PCI SCSI host adapters based on the Am53C974A
+ chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
+ PCscsi/PCnet (Am53/79C974) solutions.
+ Documentation can be found in linux/drivers/scsi/README.tmscsim.
+
+ Note that this driver does NOT support Tekram DC390W/U/F, which are
+ based on NCR/Symbios chips. Use the NCR53C8XX driver for those.
+ Also note, that there is another generic Am53C974 driver.
If you want to compile this driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read Documentation/modules.txt. The module will be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
called tmscsim.o.
+Skip support for other Am53/79C974 based SCSI adapters
+CONFIG_SCSI_DC390T_NOGENSUPP
+ Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get
+ initial values for its settings, such as speed, termination, etc.
+ If it can't find this EEPROM, it will use defaults or the user
+ supplied boot/module parameters. For details on driver configuration
+ see linux/drivers/scsi/README.tmscsim.
+
+ With this option set, if no EEPROM is found, the driver gives up and
+ thus only supports Tekram DC390(T) adapters. This can be useful if
+ you have a DC390(T) and another Am53C974 based adapter, which, for
+ some reason, you want to drive with the other AM53C974 driver.
+
+ If unsure, say N.
+
AM53/79C974 PCI SCSI support
CONFIG_SCSI_AM53C974
This is support for the AM53/79C974 SCSI host adapters. Please read
drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
available via FTP (user: anonymous) at
- ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+ ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+
+ Note that there is another driver for AM53C974 based adapters: The
+ Tekram DC390(T) driver.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
@@ -186,6+186,12 @@ W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu
S: Maintained
+DC390/AM53C974 SCSI driver
+P: Kurt Garloff
+M: K.Garloff@ping.de
+W: ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+S: Maintained
+
DECnet NETWORK LAYER
P: Steven Whitehouse
M: SteveW@ACM.org
@@ -110,6+110,9 @@ alphabook1_init_arch(unsigned long *mem_start, unsigned long *mem_end) *
* This probably ought to be configurable via MILO. For
* example, sound boards seem to like using IRQ 9.
+ *
+ * This is NOT how we should do it. PIRQ0-X should have
+ * their own IRQ's, the way intel uses the IO-APIC irq's.
*/
static unsigned long sio_route_tab __initdata = 0;
@@ -238,7+241,7 @@ static inline void __init avanti_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE);
- sio_pci_fixup(noname_map_irq, 0x0b0a090f);
+ sio_pci_fixup(noname_map_irq, 0x0b0a0e0f);
sio_fixup_irq_levels(sio_collect_irq_levels());
enable_ide(0x26e);
}
@@ -107,7+107,7 @@ ENOSYS = 38 2: popl %es; \
addl $4,%esp; \
3: iret; \
-.section fixup,"ax"; \
+.section .fixup,"ax"; \
4: movl $0,(%esp); \
jmp 1b; \
5: movl $0,(%esp); \
@@ -163,7+163,7 @@ good_area: * the fault.
*/
if (!handle_mm_fault(tsk, vma, address, write))
- goto bad_area;
+ goto do_sigbus;
/*
* Did it hit the DOS screen memory VA from vm86 mode?
@@ -250,4+250,24 @@ no_context: }
die("Oops", regs, error_code);
do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+do_sigbus:
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->tss.cr2 = address;
+ tsk->tss.error_code = error_code;
+ tsk->tss.trap_no = 14;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(error_code & 4))
+ goto no_context;
}
-# $Id: Makefile,v 1.8 1998/09/16 12:24:51 jj Exp $
+# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $
# Makefile for the Sparc boot stuff.
#
# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6+26,10 @@ BTOBJS := $(HEAD) init/main.o init/version.o \ $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
$(NETWORKS) $(DRIVERS)
+# I wanted to make this depend upon BTOBJS so that a parallel
+# build would work, but this fails because $(HEAD) cannot work
+# properly as it will cause head.o to be built with the implicit
+# rules not the ones in kernel/Makefile. Someone please fix. --DaveM
vmlinux.o: dummy
$(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
@@ -21,6+21,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y
# CONFIG_AP1000 is not set
# CONFIG_SUN4 is not set
+# CONFIG_PCI is not set
#
# Console drivers
@@ -67,6+68,7 @@ CONFIG_SUN_MOSTEK_RTC=y # CONFIG_SPARCAUDIO is not set
# CONFIG_SPARCAUDIO_AMD7930 is not set
# CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
CONFIG_SUN_OPENPROMFS=m
CONFIG_NET=y
CONFIG_SYSVIPC=y
@@ -74,7+76,7 @@ CONFIG_SYSVIPC=y CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
+CONFIG_BINFMT_MISC=m
CONFIG_BINFMT_JAVA=m
#
@@ -82,51+84,32 @@ CONFIG_BINFMT_JAVA=m #
CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
CONFIG_MD_MIRRORING=m
CONFIG_MD_RAID5=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
#
# Networking options
#
CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_FIREWALL=y
-CONFIG_NET_ALIAS=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-CONFIG_IP_FIREWALL=y
-# CONFIG_IP_FIREWALL_NETLINK is not set
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_ICMP is not set
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_MASQUERADE_MOD is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
# CONFIG_SYN_COOKIES is not set
#
@@ -135,7+118,7 @@ CONFIG_IP_ALIAS=y CONFIG_INET_RARP=m
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
-CONFIG_IPV6=y
+CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
#
@@ -145,7+128,7 @@ CONFIG_IPX=m # CONFIG_IPX_INTERN is not set
# CONFIG_SPX is not set
CONFIG_ATALK=m
-CONFIG_X25=m
+# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
@@ -154,18+137,7 @@ CONFIG_X25=m # CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=y
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-# CONFIG_NET_SCH_TEQL is not set
-CONFIG_NET_SCH_TBF=y
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
#
# ISDN subsystem
@@ -184,7+156,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SG=m
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -235,21+207,22 @@ CONFIG_MYRI_SBUS=m #
# Filesystems
#
-CONFIG_QUOTA=y
+# CONFIG_QUOTA is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
@@ -267,13+240,12 @@ CONFIG_AFFS_FS=m CONFIG_ROMFS_FS=m
CONFIG_AUTOFS_FS=m
CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=y
+CONFIG_UFS_FS=m
CONFIG_BSD_DISKLABEL=y
CONFIG_SMD_DISKLABEL=y
-# CONFIG_SOLARIS_X86_PARTITION is not set
+CONFIG_SOLARIS_X86_PARTITION=y
# CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
/* devices.c: Initial scan of the prom device tree for important
- * Sparc device nodes which we need to find.
+ * Sparc device nodes which we need to find.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
#include <asm/smp.h>
#include <asm/system.h>
-struct prom_cpuinfo linux_cpus[NR_CPUS];
-int linux_num_cpus;
+struct prom_cpuinfo linux_cpus[32];
+int linux_num_cpus = 0;
extern void cpu_probe(void);
extern void clock_stop_probe(void); /* tadpole.c */
@@ -25,64+25,55 @@ __initfunc(unsigned long device_scan(unsigned long mem_start))
{
char node_str[128];
- int nd, prom_node_cpu, thismid;
- int cpu_nds[NR_CPUS]; /* One node for each cpu */
- int cpu_ctr = 0;
+ int thismid;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
- cpu_nds[0] = prom_root_node;
- cpu_ctr++;
+ linux_num_cpus++;
} else {
int scan;
scan = prom_getchild(prom_root_node);
prom_printf("root child is %08lx\n", (unsigned long) scan);
- nd = 0;
while((scan = prom_getsibling(scan)) != 0) {
prom_getstring(scan, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
- cpu_nds[cpu_ctr] = scan;
- linux_cpus[cpu_ctr].prom_node = scan;
+ linux_cpus[linux_num_cpus].prom_node = scan;
prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
- linux_cpus[cpu_ctr].mid = thismid;
+ linux_cpus[linux_num_cpus].mid = thismid;
prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- cpu_ctr, (unsigned long) scan,
+ linux_num_cpus, (unsigned long) scan,
thismid);
- cpu_ctr++;
+ linux_num_cpus++;
}
};
- if(cpu_ctr == 0) {
+ if(linux_num_cpus == 0) {
if (sparc_cpu_model == sun4d) {
scan = prom_getchild(prom_root_node);
for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
int node = prom_getchild(scan);
-
+
prom_getstring(node, "device_type", node_str, sizeof(node_str));
if (strcmp(node_str, "cpu") == 0) {
prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
- cpu_nds[cpu_ctr] = node;
- linux_cpus[cpu_ctr].prom_node = node;
- linux_cpus[cpu_ctr].mid = thismid;
+ linux_cpus[linux_num_cpus].prom_node = node;
+ linux_cpus[linux_num_cpus].mid = thismid;
prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- cpu_ctr, (unsigned long) node,
+ linux_num_cpus, (unsigned long) node,
thismid);
- cpu_ctr++;
+ linux_num_cpus++;
}
}
}
}
- if(cpu_ctr == 0) {
+ if(linux_num_cpus == 0) {
printk("No CPU nodes found, cannot continue.\n");
/* Probably a sun4e, Sun is trying to trick us ;-) */
halt();
}
- printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+ printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
};
- prom_node_cpu = cpu_nds[0];
-
- linux_num_cpus = cpu_ctr;
cpu_probe();
#ifdef CONFIG_SUN_AUXIO
-/* $Id: ebus.c,v 1.1 1998/09/18 10:43:43 jj Exp $
+/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -141,6+141,9 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
regs[i].reg_size,
dev->prom_name, 0, 0);
+ /* Some drivers call 'check_region', so we release it */
+ release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE);
+
if (dev->base_address[i] == 0 ) {
panic("ebus: unable sparc_alloc_io for dev %s",
dev->prom_name);
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
-/* $Id: irq.c,v 1.89 1998/09/21 05:05:12 jj Exp $
+/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj 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
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#include <linux/config.h>
@@ -191,13+192,9 @@ void free_irq(unsigned int irq, void *dev_id) restore_flags(flags);
}
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-atomic_t __sparc_bh_counter = ATOMIC_INIT(0);
-#else
-int __sparc_bh_counter = 0;
-#endif
#ifdef __SMP__
/* SMP interrupt locking on Sparc. */
@@ -208,14+205,33 @@ 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(0);
+atomic_t global_bh_count = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED;
+
#ifdef DEBUG_IRQLOCK
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; }
+
+static inline void wait_on_bh(int cpu, unsigned long where)
+{
+ int stuck = INIT_STUCK;
+ do {
+ STUCK;
+ /* nothing .. wait for the other bh's to go away */
+ } while (atomic_read(&global_bh_count) != 0);
+}
+
static unsigned long previous_irqholder;
#undef INIT_STUCK
@@ -225,36+241,83 @@ static unsigned long previous_irqholder; #define STUCK \
if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+/*
+ * We have to allow irqs to arrive between __sti and __cli
+ */
+#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+
static inline void wait_on_irq(int cpu, unsigned long where)
{
int stuck = INIT_STUCK;
int local_count = local_irq_count[cpu];
- /* Are we the only one in an interrupt context? */
- while (local_count != atomic_read(&global_irq_count)) {
+ for (;;) {
+
/*
- * No such luck. Now we need to release the lock,
- * _and_ release our interrupt context, because
- * otherwise we'd have dead-locks and live-locks
- * and other fun things.
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
*/
- atomic_sub(local_count, &global_irq_count);
+ if (!atomic_read(&global_irq_count)) {
+ if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ break;
+ }
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
spin_unlock(&global_irq_lock);
- /*
- * Wait for everybody else to go away and release
- * their things before trying to get the lock again.
- */
for (;;) {
STUCK;
+
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+
if (atomic_read(&global_irq_count))
continue;
if (*((unsigned char *)&global_irq_lock))
continue;
+ if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ continue;
if (spin_trylock(&global_irq_lock))
break;
}
- atomic_add(local_count, &global_irq_count);
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+void synchronize_bh(void)
+{
+ unsigned long where;
+
+ __asm__("mov %%i7, %0" : "=r" (where));
+
+ if (atomic_read(&global_bh_count) && !in_interrupt()) {
+ int cpu = smp_processor_id();
+ wait_on_bh(cpu, where);
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+ if (atomic_read(&global_irq_count)) {
+ /* Stupid approach */
+ cli();
+ sti();
}
}
@@ -281,54+344,106 @@ static inline void get_irqlock(int cpu, unsigned long where) } while (*((volatile unsigned char *)&global_irq_lock));
} while (!spin_trylock(&global_irq_lock));
}
- /*
- * Ok, we got the lock bit.
- * But that's actually just the easy part.. Now
- * we need to make sure that nobody else is running
+ /*
+ * We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu, where);
/*
- * Finally.
+ * Ok, finally..
*/
global_irq_holder = cpu;
previous_irqholder = where;
}
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
void __global_cli(void)
{
- int cpu = smp_processor_id();
+ unsigned int flags;
unsigned long where;
__asm__("mov %%i7, %0" : "=r" (where));
- __cli();
- get_irqlock(cpu, where);
+
+ __save_flags(flags);
+
+ if ((flags & PSR_PIL) != PSR_PIL) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!local_irq_count[cpu])
+ get_irqlock(cpu, where);
+ }
}
void __global_sti(void)
{
- release_irqlock(smp_processor_id());
+ int cpu = smp_processor_id();
+
+ if (!local_irq_count[cpu])
+ release_irqlock(cpu);
__sti();
}
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
unsigned long __global_save_flags(void)
{
- return global_irq_holder == (unsigned char) smp_processor_id();
+ int retval;
+ int local_enabled = 0;
+ unsigned long flags;
+
+ __save_flags(flags);
+
+ if ((flags & PSR_PIL) != PSR_PIL)
+ local_enabled = 1;
+
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!local_irq_count[smp_processor_id()]) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == (unsigned char) smp_processor_id())
+ retval = 0;
+ }
+ return retval;
}
void __global_restore_flags(unsigned long flags)
{
- if(flags & 1) {
+ switch (flags) {
+ case 0:
__global_cli();
- } else {
- /* release_irqlock() */
- if(global_irq_holder == smp_processor_id()) {
- global_irq_holder = NO_PROC_ID;
- spin_unlock(&global_irq_lock);
- }
- if(!(flags & 2))
- __sti();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
}
}
@@ -353,7+468,7 @@ void irq_enter(int cpu, int irq, void *_opaque) while (*((volatile unsigned char *)&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder) {
struct pt_regs *regs = _opaque;
- int sbh_cnt = atomic_read(&__sparc_bh_counter);
+ int sbh_cnt = atomic_read(&global_bh_count);
int globl_locked = *((unsigned char *)&global_irq_lock);
int globl_icount = atomic_read(&global_irq_count);
int local_count = local_irq_count[cpu];
@@ -386,24+501,6 @@ void irq_exit(int cpu, int irq) }
#endif /* DEBUG_IRQLOCK */
-
-/* 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);
- }
-}
-
#endif /* __SMP__ */
void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -511,12+608,13 @@ int request_fast_irq(unsigned int irq, /* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if (irqflags & SA_STATIC_ALLOC)
+ if (irqflags & SA_STATIC_ALLOC) {
if (static_irq_count < MAX_STATIC_ALLOC)
action = &static_irqaction[static_irq_count++];
else
printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
irq, devname);
+ }
if (action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
@@ -604,11+702,12 @@ int request_irq(unsigned int irq, /* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
- if (irqflags & SA_STATIC_ALLOC)
+ 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, devname);
+ }
if (action == NULL)
action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
-/* $Id: pcic.c,v 1.2 1998/09/29 03:21:56 jj Exp $
+/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -83,7+83,7 @@ __initfunc(void pcic_probe(void)) int node;
int err;
- if (pci_present()) {
+ if (pcibios_present()) {
prom_printf("PCIC: called twice!\n");
prom_halt();
}
@@ -426,7+426,7 @@ __initfunc(void pci_time_init(void)) /* A hack until do_gettimeofday prototype is moved to arch specific headers
and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
((unsigned int *)do_gettimeofday)[0] =
- 0x10800000 | (((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) & 0x003fffff);
+ 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
((unsigned int *)do_gettimeofday)[1] =
0x01000000;
BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
-/* $Id: signal.c,v 1.86 1998/09/29 09:46:04 davem Exp $
+/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -75,6+75,7 @@ struct new_signal_frame { __siginfo_fpu_t *fpu_save;
unsigned long insns [2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -86,6+87,7 @@ struct rt_signal_frame { __siginfo_fpu_t *fpu_save;
unsigned int insns [2];
stack_t stack;
+ unsigned int extra_size; /* Should be 0 */
__siginfo_fpu_t fpu_state;
};
@@ -203,16+205,19 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) #endif
current->used_math = 1;
current->flags &= ~PF_USEDFPU;
+
+ if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
- err = copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
+ err = __copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
err |= __get_user(current->tss.fsr, &fpu->si_fsr);
err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- err |= copy_from_user(¤t->tss.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_from_user(¤t->tss.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
return err;
}
@@ -241,7+246,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs)
/* 2. Restore the state */
up_psr = regs->psr;
- err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
+ err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
/* User can only change condition codes and FPU enabling in %psr. */
regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
@@ -250,14+255,14 @@ static inline void do_new_sigreturn (struct pt_regs *regs) err |= __get_user(fpu_save, &sf->fpu_save);
if (fpu_save)
- err |= restore_fpu_state(regs, sf->fpu_save);
+ err |= restore_fpu_state(regs, fpu_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
*/
err |= __get_user(set.sig[0], &sf->info.si_mask);
- err |= copy_from_user(&set.sig[1], &sf->extramask,
- (_NSIG_WORDS-1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], &sf->extramask,
+ (_NSIG_WORDS-1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -270,8+275,6 @@ static inline void do_new_sigreturn (struct pt_regs *regs) return;
segv_and_exit:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -305,8+308,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) */
err |= __get_user(set.sig[0], &scptr->sigc_mask);
/* Note that scptr + 1 points to extramask */
- err |= copy_from_user(&set.sig[1], scptr + 1,
- (_NSIG_WORDS - 1) * sizeof(unsigned int));
+ err |= __copy_from_user(&set.sig[1], scptr + 1,
+ (_NSIG_WORDS - 1) * sizeof(unsigned int));
if (err)
goto segv_and_exit;
@@ -352,7+355,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) (((unsigned long) sf) & 0x03))
goto segv;
- err = get_user(pc, &sf->regs.pc);
+ err = __get_user(pc, &sf->regs.pc);
err |= __get_user(npc, &sf->regs.npc);
err |= ((pc | npc) & 0x03);
@@ -366,8+369,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) err |= __get_user(fpu_save, &sf->fpu_save);
if(fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
- err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t));
+ err |= restore_fpu_state(regs, fpu_save);
+ err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
@@ -459,13+462,13 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, for(window = 0; window < current->tss.w_saved; window++) {
sc->sigc_spbuf[window] =
(char *)current->tss.rwbuf_stkptrs[window];
- err |= copy_to_user(&sc->sigc_wbuf[window],
- ¤t->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= __copy_to_user(&sc->sigc_wbuf[window],
+ ¤t->tss.reg_window[window],
+ sizeof(struct reg_window));
}
else
- err |= copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
- sizeof(struct reg_window));
+ err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+ sizeof(struct reg_window));
current->tss.w_saved = 0; /* So process is allowed to execute. */
err |= __put_user(signr, &sframep->sig_num);
@@ -490,11+493,8 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, return;
sigill_and_return:
- /* Ugh, we need to grab master lock in these rare cases ;-( */
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -520,13+520,13 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) regs->psr &= ~(PSR_EF);
}
#endif
- err |= copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0],
- (sizeof(unsigned long) * 32));
+ err |= __copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0],
+ (sizeof(unsigned long) * 32));
err |= __put_user(current->tss.fsr, &fpu->si_fsr);
err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- err |= copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0],
- ((sizeof(unsigned long) +
+ err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0],
+ ((sizeof(unsigned long) +
(sizeof(unsigned long *)))*16));
current->used_math = 0;
return err;
@@ -560,7+560,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, }
/* 2. Save the current process state */
- err = copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+ err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+
+ err |= __put_user(0, &sf->extra_size);
if (current->used_math) {
err |= save_fpu_state(regs, &sf->fpu_state);
@@ -572,8+574,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, err |= __put_user(oldset->sig[0], &sf->info.si_mask);
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
(_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
if (err)
goto sigsegv;
@@ -606,10+608,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -620,7+620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, struct rt_signal_frame *sf;
int sigframe_size;
unsigned int psr;
- int i, err;
+ int err;
synchronize_user_stack();
sigframe_size = RT_ALIGNEDSZ;
@@ -632,15+632,16 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, if(current->tss.w_saved != 0)
goto sigill;
- err = put_user(regs->pc, &sf->regs.pc);
+ err = __put_user(regs->pc, &sf->regs.pc);
err |= __put_user(regs->npc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
psr = regs->psr;
if(current->used_math)
psr |= PSR_EF;
err |= __put_user(psr, &sf->regs.psr);
- for(i = 0; i < 16; i++)
- err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+ err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs));
+ err |= __put_user(0, &sf->extra_size);
+
if(psr & PSR_EF) {
err |= save_fpu_state(regs, &sf->fpu_state);
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
@@ -654,8+655,8 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
- sizeof (struct reg_window));
+ err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
if (err)
goto sigsegv;
@@ -685,10+686,8 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return;
sigill:
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -717,7+716,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, }
/* Start with a clean frame pointer and fill it */
- err = clear_user(sfp, sizeof (*sfp));
+ err = __clear_user(sfp, sizeof (*sfp));
/* Setup convenience variables */
si = &sfp->si;
@@ -746,8+745,8 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
/* Copy g [1..7] and o [0..7] registers */
- err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7);
- err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8);
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -775,9+774,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, */
for(window = 0; window < current->tss.w_saved; window++) {
err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
- err |= copy_to_user(&gw->win [window],
- ¤t->tss.reg_window [window],
- sizeof (svr4_rwindow_t));
+ err |= __copy_to_user(&gw->win [window],
+ ¤t->tss.reg_window [window],
+ sizeof (svr4_rwindow_t));
err |= __put_user(0, gw->winptr [window]);
}
@@ -819,10+818,8 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, return;
sigill_and_return:
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -839,6+836,8 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) goto sigsegv_and_return;
err = clear_user(uc, sizeof (*uc));
+ if (err)
+ return -EFAULT;
/* Setup convenience variables */
mc = &uc->mcontext;
@@ -860,8+859,8 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
/* Copy g [1..7] and o [0..7] registers */
- err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7);
- err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8);
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
@@ -874,7+873,6 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -950,14+948,13 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) regs->psr |= (psr & PSR_ICC);
/* Restore g[1..7] and o[0..7] registers */
- err |= copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+ err |= __copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1],
sizeof (long) * 7);
- err |= copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+ err |= __copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0],
sizeof (long) * 8);
return (err ? -EFAULT : 0);
sigsegv_and_return:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -1110,7+1107,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
- if(current->binfmt->core_dump(signr, regs))
+ if(current->binfmt &&
+ current->binfmt->core_dump &&
+ current->binfmt->core_dump(signr, regs))
exit_code |= 0x80;
unlock_kernel();
}
@@ -64,6+64,9 @@ volatile int __cpu_logical_map[NR_CPUS]; /* Kernel spinlock */
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+/* Used to make bitops atomic */
+unsigned char bitops_spinlock = 0;
+
volatile unsigned long ipi_count;
volatile int smp_process_available=0;
-/* $Id: sparc_ksyms.c,v 1.70 1998/09/17 11:04:55 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,10 @@ extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
+#ifdef __SMP__
+extern spinlock_t kernel_flag;
+#endif
+
/* One thing to note is that the way the symbols of the mul/div
* support routines are named is a mess, they all start with
* a '.' which makes it a bitch to export, here is the trick:
@@ -87,33+91,21 @@ __attribute__((section("__ksymtab"))) = \ EXPORT_SYMBOL(sparc_cpu_model);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
#ifdef SPIN_LOCK_DEBUG
-EXPORT_SYMBOL(_spin_lock);
-EXPORT_SYMBOL(_spin_unlock);
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
EXPORT_SYMBOL(_spin_trylock);
-EXPORT_SYMBOL(_spin_lock_irq);
-EXPORT_SYMBOL(_spin_unlock_irq);
-EXPORT_SYMBOL(_spin_lock_irqsave);
-EXPORT_SYMBOL(_spin_unlock_irqrestore);
-EXPORT_SYMBOL(_read_lock);
-EXPORT_SYMBOL(_read_unlock);
-EXPORT_SYMBOL(_read_lock_irq);
-EXPORT_SYMBOL(_read_unlock_irq);
-EXPORT_SYMBOL(_read_lock_irqsave);
-EXPORT_SYMBOL(_read_unlock_irqrestore);
-EXPORT_SYMBOL(_write_lock);
-EXPORT_SYMBOL(_write_unlock);
-EXPORT_SYMBOL(_write_lock_irq);
-EXPORT_SYMBOL(_write_unlock_irq);
-EXPORT_SYMBOL(_write_lock_irqsave);
-EXPORT_SYMBOL(_write_unlock_irqrestore);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
#else
EXPORT_SYMBOL_PRIVATE(_rw_read_enter);
EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
#endif
-EXPORT_SYMBOL(__sparc_bh_counter);
#ifdef __SMP__
#ifdef DEBUG_IRQLOCK
+EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_cli);
@@ -142,14+134,19 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit); EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
/* IRQ implementation. */
-EXPORT_SYMBOL(local_irq_count);
#ifdef __SMP__
+EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(sparc_bh_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(synchronize_bh);
#endif
+EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(udelay);
EXPORT_SYMBOL(mstk48t02_regs);
-/* $Id: sun4d_irq.c,v 1.15 1998/09/29 09:46:12 davem Exp $
+/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -438,8+438,13 @@ __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct int cpu;
/* Map the User Timer registers. */
- sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0,
+#ifdef __SMP__
+ sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0,
+ PAGE_SIZE, "user timer", 0xf, 0x0);
+#else
+ sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0,
PAGE_SIZE, "user timer", 0xf, 0x0);
+#endif
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
master_l10_counter = &sun4d_timers->l10_cur_count;
-/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $
+/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $
* sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -218,7+218,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) }
#if 0
- if (cmd & 0xff00 == ('k' << 8)){
+ if ((cmd & 0xff00) == ('k' << 8)) {
printk ("[[KBIO: %8.8x\n", (unsigned int) cmd);
}
#endif
-/* $Id: sys_sparc.c,v 1.48 1998/09/07 09:19:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -181,6+181,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, struct file * file = NULL;
unsigned long retval = -EBADF;
+ down(¤t->mm->mmap_sem);
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
@@ -214,6+215,7 @@ out_putf: fput(file);
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return retval;
}
-/* $Id: sys_sunos.c,v 1.92 1998/08/31 03:40:53 davem Exp $
+/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, struct file * file = NULL;
unsigned long retval, ret_type;
+ down(¤t->mm->mmap_sem);
lock_kernel();
current->personality |= PER_BSD;
if(flags & MAP_NORESERVE) {
@@ -128,6+129,7 @@ out_putf: fput(file);
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return retval;
}
@@ -147,6+149,7 @@ asmlinkage int sunos_brk(unsigned long brk) unsigned long rlim;
unsigned long newbrk, oldbrk;
+ down(¤t->mm->mmap_sem);
lock_kernel();
if(ARCH_SUN4C_SUN4) {
if(brk >= 0x20000000 && brk < 0xe0000000) {
@@ -213,6+216,7 @@ asmlinkage int sunos_brk(unsigned long brk) retval = 0;
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return retval;
}
@@ -579,20+583,16 @@ struct sunos_utsname {
asmlinkage int sunos_uname(struct sunos_utsname *name)
{
- int ret = -EFAULT;
-
+ int ret;
down(&uts_sem);
- if(!name)
- goto out;
- if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1))
- goto out;
- copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
- put_user('\0', &name->nname[8]);
- copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
- copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
- copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
- ret = 0;
-out:
+ ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+ if (!ret) {
+ ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+ ret |= __put_user('\0', &name->nname[8]);
+ ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+ ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+ ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+ }
up(&uts_sem);
return ret;
}
@@ -843,7+843,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) strncpy (linux_nfs_mount.hostname, the_name, 254);
linux_nfs_mount.hostname [255] = 0;
putname (the_name);
-
+
dev = get_unnamed_dev ();
ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount);
@@ -860,6+860,9 @@ sunos_mount(char *type, char *dir, int flags, void *data) int ret = -EINVAL;
char *dev_fname = 0;
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
+
lock_kernel();
/* We don't handle the integer fs type */
if ((flags & SMNT_NEWTYPE) == 0)
@@ -26,12+26,26 @@ ___set_bit: wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
or %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -48,12+62,26 @@ ___clear_bit: wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
andn %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -70,12+98,26 @@ ___change_bit: wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ld [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ld [%g1], %g7
xor %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ st %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
st %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -92,12+134,26 @@ ___set_le_bit: wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ldub [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ldub [%g1], %g7
or %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ stb %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
stb %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
@@ -113,12+169,26 @@ ___clear_le_bit: wr %g3, PSR_PIL, %psr
nop; nop; nop
1:
- ldub [%g1], %g7
+#ifdef __SMP__
+ set C_LABEL(bitops_spinlock), %g5
+2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
+ orcc %g7, 0x0, %g0 ! Did we get it?
+ bne 2b ! Nope...
+#endif
+ ldub [%g1], %g7
andn %g7, %g2, %g5
- andcc %g3, PSR_PIL, %g0
and %g7, %g2, %g2
+#ifdef __SMP__
+ stb %g5, [%g1]
+ set C_LABEL(bitops_spinlock), %g5
+ andcc %g3, PSR_PIL, %g0
+ bne 1f
+ stb %g0, [%g5]
+#else
+ andcc %g3, PSR_PIL, %g0
bne 1f
stb %g5, [%g1]
+#endif
wr %g3, 0x0, %psr
nop; nop; nop
1:
-/* $Id: debuglocks.c,v 1.3 1998/09/29 09:46:22 davem Exp $
+/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $
* debuglocks.c: Debugging versions of SMP locking primitives.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -120,29+120,17 @@ wlock_again: if(val) {
while(rw->lock & 0xff) {
if (!--stuck) {
- show(str, (spinlock_t *)rw, caller);
- stuck = INIT_STUCK;
- }
- barrier();
- }
- goto wlock_again;
- }
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
- if(val) {
- while(rw->lock & 0xff00) {
- if (!--stuck) {
show_read(str, rw, caller);
stuck = INIT_STUCK;
}
barrier();
}
- goto clock_again;
+ goto wlock_again;
}
- (*((unsigned short *)&rw->lock))++;
+
rw->reader_pc[cpu] = caller;
barrier();
- (*(((unsigned short *)&rw->lock)+1)) = 0;
+ rw->lock++;
}
#undef INIT_STUCK
@@ -157,22+145,22 @@ void _do_read_unlock(rwlock_t *rw, char *str)
STORE_CALLER(caller);
-clock_again:
- __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
+wlock_again:
+ __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
if(val) {
- while(rw->lock & 0xff00) {
+ while(rw->lock & 0xff) {
if (!--stuck) {
show_read(str, rw, caller);
stuck = INIT_STUCK;
}
barrier();
}
- goto clock_again;
+ goto wlock_again;
}
- (*((unsigned short *)&rw->lock))--;
+
rw->reader_pc[cpu] = 0;
barrier();
- (*(((unsigned char *)&rw->lock)+2))=0;
+ rw->lock -= 0x1ff;
}
#undef INIT_STUCK
@@ -190,7+178,8 @@ void _do_write_lock(rwlock_t *rw, char *str) wlock_again:
__asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
if(val) {
- while(rw->lock & 0xff) {
+wlock_wait:
+ while(rw->lock) {
if (!--stuck) {
show_write(str, rw, caller);
stuck = INIT_STUCK;
@@ -199,14+188,15 @@ wlock_again: }
goto wlock_again;
}
- rw->owner_pc = (cpu & 3) | (caller & ~3);
- while(rw->lock & ~0xff) {
- if (!--stuck) {
- show_write(str, rw, caller);
- stuck = INIT_STUCK;
- }
+
+ if (rw->lock & ~0xff) {
+ *(((unsigned char *)&rw->lock)+3) = 0;
barrier();
+ goto wlock_wait;
}
+
+ barrier();
+ rw->owner_pc = (cpu & 3) | (caller & ~3);
}
void _do_write_unlock(rwlock_t *rw)
-/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $
+/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $
* locks.S: SMP low-level lock primitives on Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/cprefix.h>
@@ -43,52+45,48 @@ ___rw_read_enter_spin_on_wlock: ldstub [%g1 + 3], %g2
b ___rw_read_enter_spin_on_wlock
ldub [%g1 + 3], %g2
+___rw_read_exit_spin_on_wlock:
+ orcc %g2, 0x0, %g0
+ be,a ___rw_read_exit
+ ldstub [%g1 + 3], %g2
+ b ___rw_read_exit_spin_on_wlock
+ ldub [%g1 + 3], %g2
___rw_write_enter_spin_on_wlock:
orcc %g2, 0x0, %g0
be,a ___rw_write_enter
ldstub [%g1 + 3], %g2
b ___rw_write_enter_spin_on_wlock
- ldub [%g1 + 3], %g2
+ ld [%g1], %g2
.globl ___rw_read_enter
___rw_read_enter:
orcc %g2, 0x0, %g0
bne,a ___rw_read_enter_spin_on_wlock
ldub [%g1 + 3], %g2
-1:
- ldstub [%g1 + 2], %g7
- orcc %g7, 0x0, %g0
- bne 1b
- ldsh [%g1], %g2
+ ld [%g1], %g2
add %g2, 1, %g2
- sth %g2, [%g1]
- sth %g0, [%g1 + 2]
+ st %g2, [%g1]
retl
mov %g4, %o7
- /* We must be careful here to not blow away wlock. */
.globl ___rw_read_exit
-___rw_read_exit_spin:
- ldstub [%g1 + 2], %g2
___rw_read_exit:
orcc %g2, 0x0, %g0
- bne ___rw_read_exit_spin
- ldsh [%g1], %g7
- sub %g7, 1, %g7
- sth %g7, [%g1]
- stb %g0, [%g1 + 2]
+ bne,a ___rw_read_exit_spin_on_wlock
+ ldub [%g1 + 3], %g2
+ ld [%g1], %g2
+ sub %g2, 0x1ff, %g2
+ st %g2, [%g1]
retl
mov %g4, %o7
.globl ___rw_write_enter
___rw_write_enter:
orcc %g2, 0x0, %g0
- bne,a ___rw_write_enter_spin_on_wlock
- ldub [%g1 + 3], %g2
- ld [%g1], %g2
-1:
- andncc %g2, 0xff, %g0
- bne,a 1b
+ bne ___rw_write_enter_spin_on_wlock
ld [%g1], %g2
+ andncc %g2, 0xff, %g0
+ bne,a ___rw_write_enter_spin_on_wlock
+ stb %g0, [%g1 + 3]
retl
mov %g4, %o7
-# $Id: Makefile,v 1.29 1998/09/16 12:25:20 jj Exp $
+# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
# 64-bit Sparc.
#
-# Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
#
# If the solaris /bin/sh wasn't so broken, I wouldn't need the following
# line...
SHELL =/bin/bash
-CC = sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi)
IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+ifneq ($(CC_HAS_ARGS),y)
+MAKEOVERRIDES := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ')
+override CC := $(CC) -D__KERNEL__ -I$(TOPDIR)/include
+endif
+
ifneq ($(NEW_GAS),y)
AS = sparc64-linux-as
LD = sparc64-linux-ld
@@ -28,7+35,6 @@ LD := $(LD) -m elf64_sparc endif
ELFTOAOUT = elftoaout
-
#
# Uncomment the first CFLAGS if you are doing kgdb source level
# debugging of the kernel to get the proper debugging information.
-ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
endif
+# Uncomment this to get spinlock/rwlock debugging on SMP.
+# DEBUG_SPINLOCK = 1
+
+ifdef SMP
+ ifdef DEBUG_SPINLOCK
+ CFLAGS += -DSPIN_LOCK_DEBUG
+ AFLAGS += -DSPIN_LOCK_DEBUG
+ endif
+endif
+
LINKFLAGS = -T arch/sparc64/vmlinux.lds
HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
@@ -27,6+27,7 @@ CONFIG_VT_CONSOLE=y CONFIG_PROM_CONSOLE=y
CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_MATROX is not set
CONFIG_FB_SBUS=y
CONFIG_FB_CREATOR=y
CONFIG_FB_CGSIX=y
@@ -86,10+87,11 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_MISC=m
CONFIG_BINFMT_JAVA=m
CONFIG_SOLARIS_EMUL=m
-CONFIG_PARPORT=y
-CONFIG_PARPORT_AX=y
+CONFIG_PARPORT=m
+CONFIG_PARPORT_AX=m
+CONFIG_PARPORT_LOWLEVEL_MODULE=y
# CONFIG_PARPORT_OTHER is not set
-CONFIG_PRINTER=y
+CONFIG_PRINTER=m
CONFIG_PRINTER_READBACK=y
CONFIG_ENVCTRL=m
@@ -122,11+124,9 @@ CONFIG_BLK_DEV_CMD646=y # Networking options
#
CONFIG_PACKET=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
+# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -136,8+136,7 @@ CONFIG_INET=y # CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-CONFIG_IP_ALIAS=y
-# CONFIG_ARPD is not set
+# CONFIG_IP_ALIAS is not set
# CONFIG_SYN_COOKIES is not set
#
@@ -165,18+164,7 @@ CONFIG_ATALK=m # CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
-CONFIG_NET_SCHED=y
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_CSZ=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-# CONFIG_NET_QOS is not set
-# CONFIG_NET_CLS is not set
+# CONFIG_NET_SCHED is not set
#
# SCSI support
@@ -249,7+237,7 @@ CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=y
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
-CONFIG_DE4X5=y
+CONFIG_DE4X5=m
CONFIG_VORTEX=m
#
@@ -258,18+246,19 @@ CONFIG_VORTEX=m # CONFIG_QUOTA is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
# CONFIG_JOLIET is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
+CONFIG_CODA_FS=m
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
@@ -292,8+281,7 @@ CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
# CONFIG_ADFS_FS is not set
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
+# CONFIG_QNX4FS_FS is not set
# CONFIG_MAC_PARTITION is not set
CONFIG_NLS=y
-# $Id: Makefile,v 1.40 1998/09/17 11:05:03 jj Exp $
+# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -89,6+89,8 @@ check_asm: dummy @echo "" >> asm_offsets.h
@echo "#else /* __SMP__ */" >> asm_offsets.h
@echo "" >> asm_offsets.h
+ @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
+ @echo "" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -D__SMP__ -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@@ -111,6+113,31 @@ check_asm: dummy ./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
@echo "" >> asm_offsets.h
+ @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#include <linux/sched.h>" > tmp.c
+ $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
+ @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/sched.h>" >> check_asm.c
+ @echo 'struct task_struct _task;' >> check_asm.c
+ @echo 'struct mm_struct _mm;' >> check_asm.c
+ @echo 'struct thread_struct _thread;' >> check_asm.c
+ @echo 'int main(void) {' >> 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 'return 0; }' >> check_asm.c
+ @rm -f tmp.[ci]
+ #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c
+ # <hack> Until we can do this natively, a hack has to take place
+ $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
+ @rm -f check_asm.s
+ # </hack>
+ ./check_asm >> asm_offsets.h
+ @rm -f check_asm check_asm.c
+ @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
@echo "#endif /* __SMP__ */" >> asm_offsets.h
@echo "" >> asm_offsets.h
@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
-/* $Id: entry.S,v 1.90 1998/09/25 01:09:05 davem Exp $
+/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -730,7+730,7 @@ sys_clone: flushw mov %l5, %o7
ret_from_syscall:
/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
- * %o7 for us.
+ * %o7 for us. Check performance counter stuff too.
*/
andn %o7, 0x100, %o7
sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags]
@@ -739,7+739,13 @@ ret_from_syscall: membar #StoreStore | #LoadStore
stb %g0, [%o4 + %lo(scheduler_lock)]
#endif
- b,pt %xcc, ret_sys_call
+ andcc %o7, 0x200, %g0
+ be,pt %icc, 1f
+ nop
+ ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
+ wr %g0, %o7, %pcr
+ wr %g0, %g0, %pic
+1: b,pt %xcc, ret_sys_call
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
sparc_exit: rdpr %otherwin, %g1
rdpr %pstate, %g2
-/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $
+/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -380,6+380,9 @@ setup_tba: or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */
mov 0x40, %g2 /* INTR data 0 register */
+ /* Kill PROM timer */
+ wr %g0, 0, %tick_cmpr
+
/* Ok, we're done setting up all the state our trap mechanims needs,
* now get back into normal globals and let the PROM know what is up.
*/
-/* $Id: ioctl32.c,v 1.52 1998/09/25 17:09:22 jj Exp $
+/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1532,8+1532,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) error = loop_status(fd, cmd, arg);
goto out;
- case AUTOFS_IOC_SETTIMEOUT:
- error = rw_long(fd, cmd, arg);
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+ case AUTOFS_IOC_SETTIMEOUT32:
+ error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
goto out;
case PIO_FONTX:
-/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $
+/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <linux/malloc.h>
#include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -208,7+209,7 @@ unsigned char psycho_ino_to_pil[] = { 13, /* Audio Record */
14, /* Audio Playback */
15, /* PowerFail */
- 9, /* Keyboard/Mouse/Serial */
+ 3, /* second SCSI */
11, /* Floppy */
2, /* Spare Hardware */
9, /* Keyboard */
restore_flags(flags);
}
-/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
- * structure for cache reasons.
+/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it
+ * lives in the per-cpu structure for cache reasons.
*/
#ifndef __SMP__
unsigned int local_irq_count;
-#endif
-
-#ifndef __SMP__
-int __sparc64_bh_counter = 0;
+unsigned int local_bh_count;
#define irq_enter(cpu, irq) (local_irq_count++)
#define irq_exit(cpu, irq) (local_irq_count--)
-
#else
-
-atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED;
/* Who has global_irq_lock. */
unsigned char global_irq_holder = NO_PROC_ID;
@@ -596,136+593,163 @@ 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(0);
-static unsigned long previous_irqholder;
+#define irq_enter(cpu, irq) \
+do { hardirq_enter(cpu); \
+ spin_unlock_wait(&global_irq_lock); \
+} while(0)
+#define irq_exit(cpu, irq) hardirq_exit(cpu)
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+static void show(char * str)
+{
+ int cpu = smp_processor_id();
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [%d %d]\n",
+ atomic_read(&global_irq_count),
+ cpu_data[0].irq_count, cpu_data[1].irq_count);
+ printk("bh: %d [%d %d]\n",
+ (spin_is_locked(&global_bh_count) ? 1 : 0),
+ cpu_data[0].bh_count, cpu_data[1].bh_count);
+}
+
+#define MAXCOUNT 100000000
-static inline void wait_on_irq(int cpu, unsigned long where)
+static inline void wait_on_bh(void)
{
- int stuck = INIT_STUCK;
- int local_count = local_irq_count;
+ int count = MAXCOUNT;
+ do {
+ if(!--count) {
+ show("wait_on_bh");
+ count = 0;
+ }
+ membar("#LoadLoad");
+ } while(spin_is_locked(&global_bh_count));
+}
+
+#define SYNC_OTHER_ULTRAS(x) udelay(x+1)
- while(local_count != atomic_read(&global_irq_count)) {
- atomic_sub(local_count, &global_irq_count);
- spin_unlock(&global_irq_lock);
+static inline void wait_on_irq(int cpu)
+{
+ int count = MAXCOUNT;
+ for(;;) {
+ membar("#LoadLoad");
+ if (!atomic_read (&global_irq_count)) {
+ if (local_bh_count || ! spin_is_locked(&global_bh_count))
+ break;
+ }
+ spin_unlock (&global_irq_lock);
+ membar("#StoreLoad | #StoreStore");
for(;;) {
- STUCK;
- membar("#StoreLoad | #LoadLoad");
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_ULTRAS(cpu);
+ __cli();
if (atomic_read(&global_irq_count))
continue;
- if (*((volatile unsigned char *)&global_irq_lock))
+ if (spin_is_locked (&global_irq_lock))
+ continue;
+ if (!local_bh_count && spin_is_locked (&global_bh_count))
continue;
- membar("#LoadLoad | #LoadStore");
if (spin_trylock(&global_irq_lock))
break;
}
- atomic_add(local_count, &global_irq_count);
}
}
-#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;}
+void synchronize_bh(void)
+{
+ if (spin_is_locked (&global_bh_count) && !in_interrupt())
+ wait_on_bh();
+}
-static inline void get_irqlock(int cpu, unsigned long where)
+void synchronize_irq(void)
{
- int stuck = INIT_STUCK;
+ if (atomic_read(&global_irq_count)) {
+ cli();
+ sti();
+ }
+}
- if (!spin_trylock(&global_irq_lock)) {
- membar("#StoreLoad | #LoadLoad");
+static inline void get_irqlock(int cpu)
+{
+ if (! spin_trylock(&global_irq_lock)) {
if ((unsigned char) cpu == global_irq_holder)
return;
do {
- do {
- STUCK;
+ while (spin_is_locked (&global_irq_lock))
membar("#LoadLoad");
- } while(*((volatile unsigned char *)&global_irq_lock));
- } while (!spin_trylock(&global_irq_lock));
+ } while(! spin_trylock(&global_irq_lock));
}
- wait_on_irq(cpu, where);
+ wait_on_irq(cpu);
global_irq_holder = cpu;
- previous_irqholder = where;
}
void __global_cli(void)
{
- int cpu = smp_processor_id();
- unsigned long where;
+ unsigned long flags;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (where));
- __cli();
- get_irqlock(cpu, where);
+ __save_flags(flags);
+ if(flags == 0) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (! local_irq_count)
+ get_irqlock(cpu);
+ }
}
void __global_sti(void)
{
- release_irqlock(smp_processor_id());
+ int cpu = smp_processor_id();
+
+ if (! local_irq_count)
+ release_irqlock(cpu);
__sti();
}
-void __global_restore_flags(unsigned long flags)
+unsigned long __global_save_flags(void)
{
- if (flags & 1) {
- __global_cli();
- } else {
- if (global_irq_holder == (unsigned char) smp_processor_id()) {
- global_irq_holder = NO_PROC_ID;
- spin_unlock(&global_irq_lock);
- }
- if (!(flags & 2))
- __sti();
+ unsigned long flags, local_enabled, retval;
+
+ __save_flags(flags);
+ local_enabled = ((flags == 0) ? 1 : 0);
+ retval = 2 + local_enabled;
+ if (! local_irq_count) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == (unsigned char) smp_processor_id())
+ retval = 0;
}
+ return retval;
}
-#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;}
-
-void irq_enter(int cpu, int irq)
+void __global_restore_flags(unsigned long flags)
{
- int stuck = INIT_STUCK;
-
- hardirq_enter(cpu);
- while (*((volatile unsigned char *)&global_irq_lock)) {
- if ((unsigned char) cpu == global_irq_holder)
- printk("irq_enter: Frosted Lucky Charms, "
- "they're magically delicious!\n");
- STUCK;
- membar("#LoadLoad");
+ switch (flags) {
+ case 0:
+ __global_cli();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ {
+ unsigned long pc;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (pc));
+ printk("global_restore_flags: Bogon flags(%016lx) caller %016lx\n",
+ flags, pc);
}
-}
-
-void irq_exit(int cpu, int irq)
-{
- hardirq_exit(cpu);
- release_irqlock(cpu);
-}
-
-void synchronize_irq(void)
-{
- int local_count = local_irq_count;
- unsigned long flags;
-
- if (local_count != atomic_read(&global_irq_count)) {
- save_and_cli(flags);
- restore_flags(flags);
}
}
@@ -787,7+811,7 @@ void handler_irq(int irq, struct pt_regs *regs) /*
* Check for TICK_INT on level 14 softint.
*/
- if ((irq == 14) && get_softint() & (1UL << 0))
+ if ((irq == 14) && (get_softint() & (1UL << 0)))
irq = 0;
#endif
clear_softint(1 << irq);
@@ -1004,12+1028,15 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *), /* Called from smp_commence, when we know how many cpus are in the system
* and can have device IRQ's directed at them.
*/
+/* #define SMP_IRQ_VERBOSE */
void distribute_irqs(void)
{
unsigned long flags;
int cpu, level;
+#ifdef SMP_IRQ_VERBOSE
printk("SMP: redistributing interrupts...\n");
+#endif
save_and_cli(flags);
cpu = 0;
for(level = 0; level < NR_IRQS; level++) {
@@ -1020,16+1047,18 @@ void distribute_irqs(void) struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
unsigned int *imap = __imap(bucket);
unsigned int val;
- unsigned long tid = __cpu_logical_map[cpu] << 9;
+ unsigned long tid = __cpu_logical_map[cpu] << 26;
val = *imap;
*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+#ifdef SMP_IRQ_VERBOSE
printk("SMP: Redirecting IGN[%x] INO[%x] "
"to cpu %d [%s]\n",
(val & SYSIO_IMAP_IGN) >> 6,
(val & SYSIO_IMAP_INO), cpu,
p->name);
+#endif
cpu++;
if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
@@ -1114,12+1143,17 @@ void enable_prom_timer(void)
__initfunc(void init_IRQ(void))
{
- int i;
+ static int called = 0;
+
+ if (called == 0) {
+ int i;
- map_prom_timers();
- kill_prom_timer();
- for(i = 0; i < NUM_IVECS; i++)
- ivector_to_mask[i] = 0;
+ called = 1;
+ 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
-/* $Id: process.c,v 1.75 1998/09/23 02:05:15 davem Exp $
+/* $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -71,13+71,16 @@ asmlinkage int cpu_idle(void) {
current->priority = 0;
while(1) {
+ struct task_struct *p;
+
check_pgt_cache();
run_task_queue(&tq_scheduler);
- barrier();
current->counter = 0;
- if(current->need_resched)
+ if (current->need_resched != 0 ||
+ ((p = init_task.next_run) != NULL &&
+ (p->processor == smp_processor_id() ||
+ (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0)))
schedule();
- barrier();
}
}
@@ -386,12+389,32 @@ void exit_thread(void) else
current->tss.utraps[0]--;
}
+
+ /* Turn off performance counters if on. */
+ if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+ current->tss.user_cntd0 =
+ current->tss.user_cntd1 = NULL;
+ current->tss.pcr_reg = 0;
+ current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ write_pcr(0);
+ }
}
void flush_thread(void)
{
+ if (!(current->tss.flags & SPARC_FLAG_KTHREAD))
+ flush_user_windows();
current->tss.w_saved = 0;
+ /* Turn off performance counters if on. */
+ if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+ current->tss.user_cntd0 =
+ current->tss.user_cntd1 = NULL;
+ current->tss.pcr_reg = 0;
+ current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ write_pcr(0);
+ }
+
/* No new signal delivery by default. */
current->tss.new_signal = 0;
current->tss.fpsaved[0] = 0;
@@ -399,18+422,14 @@ void flush_thread(void) /* Now, this task is no longer a kernel thread. */
current->tss.current_ds = USER_DS;
if(current->tss.flags & SPARC_FLAG_KTHREAD) {
- extern spinlock_t scheduler_lock;
-
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
/* exec_mmap() set context to NO_CONTEXT, here is
* where we grab a new one.
*/
- spin_lock(&scheduler_lock);
current->mm->cpu_vm_mask = 0;
activate_context(current);
current->mm->cpu_vm_mask = (1UL<<smp_processor_id());
- spin_unlock(&scheduler_lock);
}
if (current->tss.flags & SPARC_FLAG_32BIT)
__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -524,7+543,6 @@ void fault_in_user_windows(struct pt_regs *regs) current->tss.w_saved = 0;
return;
barf:
- lock_kernel();
do_exit(SIGILL);
}
@@ -552,7+570,19 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
p->tss.fpsaved[0] = 0;
+ p->mm->segments = (void *) 0;
if(regs->tstate & TSTATE_PRIV) {
+ /* Special case, if we are spawning a kernel thread from
+ * a userspace task (via KMOD, NFS, or similar) we must
+ * disable performance counters in the child because the
+ * address space and protection realm are changing.
+ */
+ if (current->tss.flags & SPARC_FLAG_PERFCTR) {
+ p->tss.user_cntd0 =
+ p->tss.user_cntd1 = NULL;
+ p->tss.pcr_reg = 0;
+ p->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ }
p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
p->tss.current_ds = KERNEL_DS;
-/* $Id: psycho.c,v 1.64 1998/09/01 07:24:24 jj Exp $
+/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1639,17+1639,8 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, return;
}
- /* See if we find a matching interrupt-map entry. */
- if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
- pdev->irq = psycho_irq_build(pbm, pdev,
- (pbm->parent->upa_portid << 6)
- | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
/* See if fully specified already (ie. for onboard devices like hme) */
- } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+ if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
#ifdef FIXUP_IRQ_DEBUG
dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
@@ -1664,6+1655,15 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
prom_irq, pdev->irq);
#endif
+ /* See if we find a matching interrupt-map entry. */
+ } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
+ pdev->irq = psycho_irq_build(pbm, pdev,
+ (pbm->parent->upa_portid << 6)
+ | prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
+#endif
} else {
unsigned int bus, slot, line;
@@ -43,6+43,12 @@ static pte_t *get_page(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
+
+ /* Seems non-intuitive but the page copy/clear routines always
+ * check current's value.
+ */
+ current->mm->segments = (void *) (addr & PAGE_SIZE);
+
if (pgd_none(*pgdir)) {
handle_mm_fault(tsk, vma, addr, write);
goto repeat;
@@ -574,7+580,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out;
}
#endif
- if(!(child = find_task_by_pid(pid))) {
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock);
+
+ if(!child) {
pt_error_return(regs, ESRCH);
goto out;
}
@@ -604,9+614,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) }
child->flags |= PF_PTRACED;
if(child->p_pptr != current) {
+ unsigned long flags;
+
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
}
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
@@ -781,11+795,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) cregs->tnpc = npc;
}
cregs->y = y;
- for(i = 1; i < 16; i++)
+ for(i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
goto out;
}
+ }
pt_succ_return(regs, 0);
goto out;
}
@@ -814,11+829,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) cregs->tnpc = tnpc;
}
cregs->y = y;
- for(i = 1; i < 16; i++)
+ for(i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
goto out;
}
+ }
pt_succ_return(regs, 0);
goto out;
}
@@ -1055,23+1071,29 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_succ_return(regs, 0);
goto out;
}
- wake_up_process(child);
child->exit_code = SIGKILL;
+ wake_up_process(child);
pt_succ_return(regs, 0);
goto out;
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
+ unsigned long flags;
+
if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
goto out;
}
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- wake_up_process(child);
child->exit_code = data;
+
+ write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
+ wake_up_process(child);
pt_succ_return(regs, 0);
goto out;
}
-/* $Id: rtrap.S,v 1.40 1998/09/23 02:05:18 davem Exp $
+/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -46,13+46,15 @@ rtrap: sethi %hi(bh_active), %l2 ldub [%l6 + %o0], %l2
sub %l5, 2, %l5
add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1
- andcc %l2, FPRS_FEF, %g0
+ andcc %l2, (FPRS_FEF|FPRS_DU), %g0
be,pt %icc, 2f
and %l2, FPRS_DL, %l6
+ andcc %l2, FPRS_FEF, %g0
+ be,pn %icc, 5f
+ sll %o0, 3, %o5
rd %fprs, %g5
wr %g5, FPRS_FEF, %fprs
ldub [%o1 + %o0], %g5
- sll %o0, 3, %o5
add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
membar #StoreLoad | #LoadLoad
sll %o0, 8, %o2
@@ -130,25+132,49 @@ to_user: ldx [%g6 + AOFF_task_need_resched], %l0 nop
lduw [%g6 + AOFF_task_sigpending], %l0
check_signal: brz,a,pt %l0, check_user_wins
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ nop
clr %o0
mov %l5, %o2
mov %l6, %o3
call do_signal
add %sp, STACK_BIAS + REGWIN_SZ, %o1
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
clr %l6
-check_user_wins:brz,pt %o2, 1f
+
+ /* We must not take any traps between here and the actual
+ * return to user-space. If we do we risk having windows
+ * saved to the thread struct between the test and the
+ * actual return from trap. --DaveM
+ */
+check_user_wins:
+ wrpr %l7, 0x0, %pstate
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ brz,pt %o2, 1f
sethi %hi(TSTATE_PEF), %l6
+ wrpr %l7, PSTATE_IE, %pstate
call fault_in_user_windows
add %sp, STACK_BIAS + REGWIN_SZ, %o0
-
+ /* It is OK to leave interrupts on now because if
+ * fault_in_user_windows has returned it has left us
+ * with a clean user stack state.
+ */
1:
#if 0
call rtrap_check
add %sp, STACK_BIAS + REGWIN_SZ, %o0
#endif
+ lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5
+ andcc %l5, 0x200, %g0
+ be,pt %xcc, 1f
+ nop
+
+ /* Don't forget to preserve user window invariants. */
+ wrpr %l7, PSTATE_IE, %pstate
+ call update_perfctrs
+ nop
+ ba,a,pt %xcc, check_user_wins
+
+1:
andcc %l1, %l6, %g0
be,pt %xcc, rt_continue
stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
@@ -160,4+186,16 @@ check_user_wins:brz,pt %o2, 1f ba,pt %xcc, rt_continue+4
lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+5: wr %g0, FPRS_FEF, %fprs
+ membar #StoreLoad | #LoadLoad
+ sll %o0, 8, %o2
+ add %g6, AOFF_task_fpregs+0x80, %o3
+ add %g6, AOFF_task_fpregs+0xc0, %o4
+ ldda [%o3 + %o2] ASI_BLK_P, %f32
+ ldda [%o4 + %o2] ASI_BLK_P, %f48
+1: membar #Sync
+ wr %g0, FPRS_DU, %fprs
+ ba,pt %xcc, rt_continue
+ stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
+
#undef PTREGS_OFF
-/* $Id: setup.c,v 1.32 1998/09/24 03:21:37 davem Exp $
+/* $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -62,38+62,207 @@ struct screen_info screen_info = { * prints out pretty messages and returns.
*/
-extern unsigned long sparc64_ttable_tl0;
#if CONFIG_SUN_CONSOLE
void (*prom_palette)(int);
#endif
asmlinkage void sys_sync(void); /* it's really int */
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+ prom_printf("%s", s);
+}
+
+static struct console prom_console = {
+ "prom",
+ prom_console_write,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CON_CONSDEV | CON_ENABLED,
+ -1,
+ 0,
+ NULL
+};
+
+#define PROM_TRUE -1
+#define PROM_FALSE 0
+
/* Pretty sick eh? */
-void prom_sync_me(long *args)
+int prom_callback(long *args)
{
- unsigned long prom_tba, flags;
+ struct console *cons, *saved_console = NULL;
+ unsigned long flags;
+ char *cmd;
- save_and_cli(flags);
- __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba));
- __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
+ if (!args)
+ return -1;
+ if (!(cmd = (char *)args[0]))
+ return -1;
-#ifdef CONFIG_SUN_CONSOLE
- if (prom_palette)
- prom_palette (1);
-#endif
- prom_printf("PROM SYNC COMMAND...\n");
- show_free_areas();
- if(current->pid != 0) {
- sti();
- sys_sync();
- cli();
+ save_and_cli(flags);
+ cons = console_drivers;
+ while (cons) {
+ unregister_console(cons);
+ cons->flags &= ~(CON_PRINTBUFFER);
+ cons->next = saved_console;
+ saved_console = cons;
+ cons = console_drivers;
}
- prom_printf("Returning to prom\n");
+ register_console(&prom_console);
+ if (!strcmp(cmd, "sync")) {
+ prom_printf("PROM `%s' command...\n", cmd);
+ show_free_areas();
+ if(current->pid != 0) {
+ sti();
+ sys_sync();
+ cli();
+ }
+ args[2] = 0;
+ args[args[1] + 3] = -1;
+ prom_printf("Returning to PROM\n");
+ } else if (!strcmp(cmd, "va>tte-data")) {
+ unsigned long ctx, va;
+ unsigned long tte = 0;
+ long res = PROM_FALSE;
+
+ ctx = args[3];
+ va = args[4];
+ if (ctx) {
+ /*
+ * Find process owning ctx, lookup mapping.
+ */
+ struct task_struct *p;
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ for_each_task(p)
+ if (p->tss.ctx == ctx)
+ break;
+ if (p->tss.ctx != ctx)
+ goto done;
+
+ pgdp = pgd_offset(p->mm, va);
+ if (pgd_none(*pgdp))
+ goto done;
+ pmdp = pmd_offset(pgdp, va);
+ if (pmd_none(*pmdp))
+ goto done;
+ ptep = pte_offset(pmdp, va);
+ if (!pte_present(*ptep))
+ goto done;
+ tte = pte_val(*ptep);
+ res = PROM_TRUE;
+ goto done;
+ }
- __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba));
- restore_flags(flags);
+ if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+ /*
+ * Locked down tlb entry 63.
+ */
+ tte = spitfire_get_dtlb_data(63);
+ res = PROM_TRUE;
+ goto done;
+ }
+
+ if (va < PGDIR_SIZE) {
+ /*
+ * vmalloc or prom_inherited mapping.
+ */
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ pgdp = pgd_offset_k(va);
+ if (pgd_none(*pgdp))
+ goto done;
+ pmdp = pmd_offset(pgdp, va);
+ if (pmd_none(*pmdp))
+ goto done;
+ ptep = pte_offset(pmdp, va);
+ if (!pte_present(*ptep))
+ goto done;
+ tte = pte_val(*ptep);
+ res = PROM_TRUE;
+ goto done;
+ }
+
+ if (va < PAGE_OFFSET) {
+ /*
+ * No mappings here.
+ */
+ goto done;
+ }
- return;
+ if (va & (1UL << 40)) {
+ /*
+ * I/O page.
+ */
+
+ tte = (__pa(va) & _PAGE_PADDR) |
+ _PAGE_VALID | _PAGE_SZ4MB |
+ _PAGE_E | _PAGE_P | _PAGE_W;
+ res = PROM_TRUE;
+ goto done;
+ }
+
+ /*
+ * Normal page.
+ */
+ tte = (__pa(va) & _PAGE_PADDR) |
+ _PAGE_VALID | _PAGE_SZ4MB |
+ _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W;
+ res = PROM_TRUE;
+
+ done:
+ if (res == PROM_TRUE) {
+ args[2] = 3;
+ args[args[1] + 3] = 0;
+ args[args[1] + 4] = res;
+ args[args[1] + 5] = tte;
+ } else {
+ args[2] = 2;
+ args[args[1] + 3] = 0;
+ args[args[1] + 4] = res;
+ }
+ } else if (!strcmp(cmd, ".soft1")) {
+ unsigned long tte;
+
+ tte = args[3];
+ prom_printf("%lx:\"%s%s%s%s%s\" ",
+ (tte & _PAGE_SOFT) >> 7,
+ tte & _PAGE_MODIFIED ? "M" : "-",
+ tte & _PAGE_ACCESSED ? "A" : "-",
+ tte & _PAGE_READ ? "W" : "-",
+ tte & _PAGE_WRITE ? "R" : "-",
+ tte & _PAGE_PRESENT ? "P" : "-");
+
+ args[2] = 2;
+ args[args[1] + 3] = 0;
+ args[args[1] + 4] = PROM_TRUE;
+ } else if (!strcmp(cmd, ".soft2")) {
+ unsigned long tte;
+
+ tte = args[3];
+ prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50);
+
+ args[2] = 2;
+ args[args[1] + 3] = 0;
+ args[args[1] + 4] = PROM_TRUE;
+ } else {
+ prom_printf("unknown PROM `%s' command...\n", cmd);
+ }
+ unregister_console(&prom_console);
+ while (saved_console) {
+ cons = saved_console;
+ saved_console = cons->next;
+ register_console(cons);
+ }
+ restore_flags(flags);
+ return 0;
}
extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
@@ -250,28+419,6 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
extern struct consw sun_serial_con;
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
- prom_printf("%s", s);
-}
-
-static struct console prom_console = {
- "prom",
- prom_console_write,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- CON_PRINTBUFFER,
- -1,
- 0,
- NULL
-};
-#endif
-
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -279,10+426,6 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long lowest_paddr, end_of_phys_memory = 0;
int total, i;
-#ifdef PROM_DEBUG_CONSOLE
- register_console(&prom_console);
-#endif
-
/* Initialize PROM console and command line. */
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
@@ -316,7+459,13 @@ __initfunc(void setup_arch(char **cmdline_p, }
}
}
- prom_setsync(prom_sync_me);
+ prom_setcallback(prom_callback);
+ prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; "
+ "' linux-va>tte-data to va>tte-data");
+ prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; "
+ "' linux-.soft1 to .soft1");
+ prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; "
+ "' linux-.soft2 to .soft2");
/* 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.
@@ -439,8+588,6 @@ extern int smp_info(char *); extern int smp_bogo(char *);
extern int mmu_info(char *);
-unsigned long dcache_aliases_found = 0;
-
int get_cpuinfo(char *buffer)
{
int cpuid=smp_processor_id();
@@ -454,7+601,6 @@ int get_cpuinfo(char *buffer) "type\t\t: sun4u\n"
"ncpus probed\t: %d\n"
"ncpus active\t: %d\n"
- "d-aliases\t: %lu\n"
#ifndef __SMP__
"BogoMips\t: %lu.%02lu\n"
#endif
@@ -462,7+608,7 @@ int get_cpuinfo(char *buffer) sparc_cpu_type[cpuid],
sparc_fpu_type[cpuid],
prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
- linux_num_cpus, smp_num_cpus, dcache_aliases_found
+ linux_num_cpus, smp_num_cpus
#ifndef __SMP__
, loops_per_sec/500000, (loops_per_sec/5000) % 100
#endif
-/* $Id: signal.c,v 1.37 1998/09/25 01:09:22 davem Exp $
+/* $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -53,7+53,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) unsigned char fenab;
int err;
- __asm__ __volatile__("flushw");
+ flush_user_windows();
if(tp->w_saved ||
(((unsigned long)ucp) & (sizeof(unsigned long)-1)) ||
(!__access_ok((unsigned long)ucp, sizeof(*ucp))))
-/* $Id: signal32.c,v 1.44 1998/09/25 01:09:17 davem Exp $
+/* $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -76,6+76,9 @@ struct new_signal_frame32 { /* __siginfo_fpu32_t * */ u32 fpu_save;
unsigned int insns [2];
unsigned extramask[_NSIG_WORDS32 - 1];
+ unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+ /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+ siginfo_extra_v8plus_t v8plus;
__siginfo_fpu_t fpu_state;
};
@@ -87,6+90,9 @@ struct rt_signal_frame32 { /* __siginfo_fpu32_t * */ u32 fpu_save;
unsigned int insns [2];
stack_t32 stack;
+ unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
+ /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
+ siginfo_extra_v8plus_t v8plus;
__siginfo_fpu_t fpu_state;
};
@@ -209,7+215,7 @@ void do_new_sigreturn32(struct pt_regs *regs) unsigned pc, npc, fpu_save;
sigset_t set;
unsigned seta[_NSIG_WORDS32];
- int err;
+ int err, i;
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
@@ -232,24+238,18 @@ void do_new_sigreturn32(struct pt_regs *regs) err = __get_user(regs->y, &sf->info.si_regs.y);
err |= __get_user(psr, &sf->info.si_regs.psr);
- err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
- err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
- err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
- err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
- err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
- err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
- err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
- err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
- err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
- err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
- err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
- err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
- err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
- err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
- err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
+ for (i = UREG_G1; i <= UREG_I7; i++)
+ err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+ err |= __get_user(i, &sf->v8plus.g_upper[0]);
+ if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+ for (i = UREG_G1; i <= UREG_I7; i++)
+ err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+ }
+ }
/* User can only change condition codes in %tstate. */
- regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
err |= __get_user(fpu_save, &sf->fpu_save);
@@ -273,7+273,6 @@ void do_new_sigreturn32(struct pt_regs *regs) return;
segv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -329,12+328,11 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) err |= __get_user(psr, &scptr->sigc_psr);
if (err)
goto segv;
- regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
return;
segv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -346,7+344,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) sigset_t set;
sigset_t32 seta;
stack_t st;
- int err;
+ int err, i;
synchronize_user_stack();
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
@@ -369,25+367,19 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) /* 2. Restore the state */
err = __get_user(regs->y, &sf->regs.y);
err |= __get_user(psr, &sf->regs.psr);
-
- err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]);
- err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]);
- err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]);
- err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]);
- err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]);
- err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]);
- err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]);
- err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]);
- err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]);
- err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]);
- err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]);
- err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]);
- err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]);
- err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]);
- err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]);
+
+ for (i = UREG_G1; i <= UREG_I7; i++)
+ err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
+ err |= __get_user(i, &sf->v8plus.g_upper[0]);
+ if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
+ for (i = UREG_G1; i <= UREG_I7; i++)
+ err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
+ }
+ }
/* User can only change condition codes in %tstate. */
- regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
err |= __get_user(fpu_save, &sf->fpu_save);
@@ -417,7+409,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock);
return;
segv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -472,7+463,6 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, /* Don't change signal code and address, so that
* post mortem debuggers can have a look.
*/
- lock_kernel ();
do_exit(SIGILL);
}
@@ -544,7+534,6 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, return;
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -614,6+603,10 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg err |= __put_user(psr, &sf->info.si_regs.psr);
for (i = 0; i < 16; i++)
err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+ err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+ err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+ for (i = 1; i < 16; i++)
+ err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
if (psr & PSR_EF) {
err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -682,10+675,8 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg return;
sigill:
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -717,7+708,6 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, #ifdef DEBUG_SIGNALS
printk ("Invalid stack frame\n");
#endif
- lock_kernel ();
do_exit(SIGILL);
}
@@ -833,7+823,6 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, return;
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -850,7+839,6 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
- lock_kernel();
do_exit (SIGSEGV);
}
err = clear_user(uc, sizeof (*uc));
@@ -968,7+956,7 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) regs->tnpc = npc | 1;
err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
err |= __get_user(psr, &((*gr) [SVR4_PSR]));
- regs->tstate &= ~(TSTATE_ICC);
+ regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
regs->tstate |= psr_to_tstate_icc(psr);
#if 0
if(psr & PSR_EF)
@@ -984,7+972,6 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
return -EINTR;
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -1034,6+1021,10 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs err |= __put_user(psr, &sf->regs.psr);
for (i = 0; i < 16; i++)
err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+ err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
+ err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
+ for (i = 1; i < 16; i++)
+ err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
if (psr & PSR_EF) {
err |= save_fpu_state32(regs, &sf->fpu_state);
@@ -1107,10+1098,8 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs return;
sigill:
- lock_kernel();
do_exit(SIGILL);
sigsegv:
- lock_kernel();
do_exit(SIGSEGV);
}
@@ -1304,14+1293,19 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
if(current->binfmt && current->binfmt->core_dump) {
lock_kernel();
- if(current->binfmt->core_dump(signr, regs))
+ if(current->binfmt &&
+ current->binfmt->core_dump &&
+ current->binfmt->core_dump(signr, regs))
exit_code |= 0x80;
unlock_kernel();
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
- show_regs (regs);
+ /* On SMP we are only interested in the current
+ * CPU's registers.
+ */
+ __show_regs (regs);
#ifdef DEBUG_SIGNALS_TLB
do {
extern void sparc_ultra_dump_itlb(void);
@@ -41,7+41,9 @@ int smp_threads_ready = 0;
struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
-static unsigned char boot_cpu_id __initdata = 0;
+/* Please don't make this initdata!!! --DaveM */
+static unsigned char boot_cpu_id = 0;
+
static int smp_activated = 0;
volatile int cpu_number_map[NR_CPUS];
@@ -82,12+84,16 @@ int smp_bogo(char *buf)
__initfunc(void smp_store_cpu_info(int id))
{
- cpu_data[id].udelay_val = loops_per_sec;
cpu_data[id].irq_count = 0;
+ cpu_data[id].bh_count = 0;
+ /* multiplier and counter set by
+ smp_setup_percpu_timer() */
+ cpu_data[id].udelay_val = loops_per_sec;
+
cpu_data[id].pgcache_size = 0;
+ cpu_data[id].pte_cache = NULL;
cpu_data[id].pgdcache_size = 0;
cpu_data[id].pgd_cache = NULL;
- cpu_data[id].pte_cache = NULL;
}
extern void distribute_irqs(void);
@@ -137,6+143,11 @@ __initfunc(void smp_callin(void)) __asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
+ /* Clear this or we will die instantly when we
+ * schedule back to this idler...
+ */
+ current->tss.flags &= ~(SPARC_FLAG_NEWCHILD);
+
while(!smp_processors_ready)
membar("#LoadLoad");
}
@@ -396,6+407,8 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, {
u32 ctx = mm->context & 0x3ff;
+ start &= PAGE_MASK;
+ end &= PAGE_MASK;
if(mm == current->mm && atomic_read(&mm->count) == 1) {
if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
goto local_flush_and_out;
@@ -404,8+417,6 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
local_flush_and_out:
- start &= PAGE_MASK;
- end &= PAGE_MASK;
__flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start));
}
@@ -413,6+424,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) {
u32 ctx = mm->context & 0x3ff;
+ page &= PAGE_MASK;
if(mm == current->mm && atomic_read(&mm->count) == 1) {
if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
goto local_flush_and_out;
@@ -433,11+445,11 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
local_flush_and_out:
- __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT);
+ __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
}
/* CPU capture. */
-#define CAPTURE_DEBUG
+/* #define CAPTURE_DEBUG */
extern unsigned long xcall_capture;
static atomic_t smp_capture_depth = ATOMIC_INIT(0);
@@ -446,37+458,42 @@ static unsigned long penguins_are_doing_time = 0;
void smp_capture(void)
{
- int result = atomic_add_return(1, &smp_capture_depth);
+ if (smp_processors_ready) {
+ int result = atomic_add_return(1, &smp_capture_depth);
- membar("#StoreStore | #LoadStore");
- if(result == 1) {
- int ncpus = smp_num_cpus;
+ membar("#StoreStore | #LoadStore");
+ if(result == 1) {
+ int ncpus = smp_num_cpus;
#ifdef CAPTURE_DEBUG
- printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+ printk("CPU[%d]: Sending penguins to jail...",
+ smp_processor_id());
#endif
- penguins_are_doing_time = 1;
- membar("#StoreStore | #LoadStore");
- atomic_inc(&smp_capture_registry);
- smp_cross_call(&xcall_capture, 0, 0, 0);
- while(atomic_read(&smp_capture_registry) != ncpus)
- membar("#LoadLoad");
+ penguins_are_doing_time = 1;
+ membar("#StoreStore | #LoadStore");
+ atomic_inc(&smp_capture_registry);
+ smp_cross_call(&xcall_capture, 0, 0, 0);
+ while(atomic_read(&smp_capture_registry) != ncpus)
+ membar("#LoadLoad");
#ifdef CAPTURE_DEBUG
- printk("done\n");
+ printk("done\n");
#endif
+ }
}
}
void smp_release(void)
{
- if(atomic_dec_and_test(&smp_capture_depth)) {
+ if(smp_processors_ready) {
+ if(atomic_dec_and_test(&smp_capture_depth)) {
#ifdef CAPTURE_DEBUG
- printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
- smp_processor_id());
+ printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+ smp_processor_id());
#endif
- penguins_are_doing_time = 0;
- membar("#StoreStore | #StoreLoad");
- atomic_dec(&smp_capture_registry);
+ penguins_are_doing_time = 0;
+ membar("#StoreStore | #StoreLoad");
+ atomic_dec(&smp_capture_registry);
+ }
}
}
@@ -539,8+556,12 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) if(!--prof_counter(cpu))
{
if (cpu == boot_cpu_id) {
- extern void irq_enter(int, int);
- extern void irq_exit(int, int);
+/* XXX Keep this in sync with irq.c --DaveM */
+#define irq_enter(cpu, irq) \
+do { hardirq_enter(cpu); \
+ spin_unlock_wait(&global_irq_lock); \
+} while(0)
+#define irq_exit(cpu, irq) hardirq_exit(cpu)
irq_enter(cpu, 0);
kstat.irqs[cpu][0]++;
@@ -548,6+569,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) timer_tick_interrupt(regs);
irq_exit(cpu, 0);
+
+#undef irq_enter
+#undef irq_exit
}
if(current->pid) {
-/* $Id: sparc64_ksyms.c,v 1.42 1998/10/05 03:18:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
#include <asm/oplib.h>
#include <asm/delay.h>
@@ -55,7+57,6 @@ extern void die_if_kernel(char *str, struct pt_regs *regs); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
-extern void *__bzero_1page(void *);
extern void *__bzero(void *, size_t);
extern void *__bzero_noasi(void *, size_t);
extern void *__memscan_zero(void *, size_t);
@@ -63,6+64,7 @@ extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t);
extern int __strncmp(const char *, const char *, __kernel_size_t);
extern __kernel_size_t __strlen(const char *);
+extern __kernel_size_t strlen(const char *);
extern char saved_command_line[];
extern char *getname32(u32 name);
extern void linux_sparc_syscall(void);
@@ -87,6+89,17 @@ extern void dump_thread(struct pt_regs *, struct user *);
#ifdef __SMP__
extern spinlock_t scheduler_lock;
+extern spinlock_t kernel_flag;
+extern int smp_num_cpus;
+#ifdef SPIN_LOCK_DEBUG
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+#endif
#endif
/* One thing to note is that the way the symbols of the mul/div
@@ -102,19+115,46 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
#ifdef __SMP__
+/* Kernel wide locking */
EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(kernel_flag);
+
+/* Software-IRQ BH locking */
EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(synchronize_bh);
+
+/* Hard IRQ locking */
EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(cpu_data);
EXPORT_SYMBOL_PRIVATE(global_cli);
EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_save_flags);
EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+
+/* Per-CPU information table */
+EXPORT_SYMBOL(cpu_data);
+
+/* Misc SMP information */
+EXPORT_SYMBOL(smp_num_cpus);
+
+/* Spinlock debugging library, optional. */
+#ifdef SPIN_LOCK_DEBUG
+EXPORT_SYMBOL(_do_spin_lock);
+EXPORT_SYMBOL(_do_spin_unlock);
+EXPORT_SYMBOL(_spin_trylock);
+EXPORT_SYMBOL(_do_read_lock);
+EXPORT_SYMBOL(_do_read_unlock);
+EXPORT_SYMBOL(_do_write_lock);
+EXPORT_SYMBOL(_do_write_unlock);
+#endif
+
#else
EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(local_bh_count);
#endif
-EXPORT_SYMBOL_PRIVATE(_lock_kernel);
-EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
@@ -124,7+164,6 @@ EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq);
EXPORT_SYMBOL(sparc_alloc_io);
EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(__sparc64_bh_counter);
EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
EXPORT_SYMBOL(mmu_get_scsi_sgl);
EXPORT_SYMBOL(mmu_get_scsi_one);
@@ -185,6+224,9 @@ EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */
EXPORT_SYMBOL(bcopy);
EXPORT_SYMBOL(__strlen);
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+EXPORT_SYMBOL(strlen);
+#endif
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncpy);
@@ -220,7+262,7 @@ EXPORT_SYMBOL(sys32_ioctl); /* Special internal versions of library functions. */
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
-EXPORT_SYMBOL(__bzero_1page);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(__bzero);
EXPORT_SYMBOL(__memscan_zero);
EXPORT_SYMBOL(__memscan_generic);
-/* $Id: sys_sparc.c,v 1.22 1998/09/25 01:09:27 davem Exp $
+/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
#include <asm/uaccess.h>
#include <asm/ipc.h>
#include <asm/utrap.h>
+#include <asm/perfctr.h>
/* 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.
@@ -151,6+152,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, struct file * file = NULL;
unsigned long retval = -EBADF;
+ down(¤t->mm->mmap_sem);
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd);
@@ -189,6+191,7 @@ out_putf: fput(file);
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return retval;
}
@@ -378,3+381,105 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
return ret;
}
+
+/* Invoked by rtrap code to update performance counters in
+ * user space.
+ */
+asmlinkage void
+update_perfctrs(void)
+{
+ unsigned long pic, tmp;
+
+ read_pic(pic);
+ tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+ __put_user(tmp, current->tss.user_cntd0);
+ tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+ __put_user(tmp, current->tss.user_cntd1);
+ reset_pic();
+}
+
+asmlinkage int
+sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2)
+{
+ int err = 0;
+
+ switch(opcode) {
+ case PERFCTR_ON:
+ current->tss.pcr_reg = arg2;
+ current->tss.user_cntd0 = (u64 *) arg0;
+ current->tss.user_cntd1 = (u64 *) arg1;
+ current->tss.kernel_cntd0 =
+ current->tss.kernel_cntd1 = 0;
+ write_pcr(arg2);
+ reset_pic();
+ current->tss.flags |= SPARC_FLAG_PERFCTR;
+ break;
+
+ case PERFCTR_OFF:
+ err = -EINVAL;
+ if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) {
+ current->tss.user_cntd0 =
+ current->tss.user_cntd1 = NULL;
+ current->tss.pcr_reg = 0;
+ write_pcr(0);
+ current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ err = 0;
+ }
+ break;
+
+ case PERFCTR_READ: {
+ unsigned long pic, tmp;
+
+ if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ err = -EINVAL;
+ break;
+ }
+ read_pic(pic);
+ tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
+ err |= __put_user(tmp, current->tss.user_cntd0);
+ tmp = (current->tss.kernel_cntd1 += (pic >> 32));
+ err |= __put_user(tmp, current->tss.user_cntd1);
+ reset_pic();
+ break;
+ }
+
+ case PERFCTR_CLRPIC:
+ if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ err = -EINVAL;
+ break;
+ }
+ current->tss.kernel_cntd0 =
+ current->tss.kernel_cntd1 = 0;
+ reset_pic();
+ break;
+
+ case PERFCTR_SETPCR: {
+ u64 *user_pcr = (u64 *)arg0;
+ if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ err = -EINVAL;
+ break;
+ }
+ err |= __get_user(current->tss.pcr_reg, user_pcr);
+ write_pcr(current->tss.pcr_reg);
+ current->tss.kernel_cntd0 =
+ current->tss.kernel_cntd1 = 0;
+ reset_pic();
+ break;
+ }
+
+ case PERFCTR_GETPCR: {
+ u64 *user_pcr = (u64 *)arg0;
+ if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ err = -EINVAL;
+ break;
+ }
+ err |= __put_user(current->tss.pcr_reg, user_pcr);
+ break;
+ }
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ return err;
+}
-/* $Id: sys_sparc32.c,v 1.95 1998/09/07 09:20:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -224,9+224,6 @@ struct shmid_ds32 { __kernel_ipc_pid_t32 shm_cpid;
__kernel_ipc_pid_t32 shm_lpid;
unsigned short shm_nattch;
- unsigned short shm_npages;
- u32 shm_pages;
- u32 attaches;
};
/*
@@ -1394,7+1391,7 @@ asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned else if(is_smb)
do_smb_super_data_conv((void *)data_page);
else
- panic("Tell DaveM he fucked up...");
+ panic("The problem is here...");
old_fs = get_fs();
set_fs(KERNEL_DS);
err = sys_mount((char *)dev_page, (char *)dir_page,
@@ -2707,10+2704,53 @@ struct module_info32 {
/* Query various bits about modules. */
-extern long get_mod_name(const char *user_name, char **buf);
-extern void put_mod_name(char *buf);
-extern struct module *find_module(const char *name);
-extern struct module kernel_module;
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+ unsigned long page;
+ long retval;
+
+ if ((unsigned long)user_name >= TASK_SIZE
+ && !segment_eq(get_fs (), KERNEL_DS))
+ return -EFAULT;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+ if (retval > 0) {
+ if (retval < PAGE_SIZE) {
+ *buf = (char *)page;
+ return retval;
+ }
+ retval = -ENAMETOOLONG;
+ } else if (!retval)
+ retval = -EINVAL;
+
+ free_page(page);
+ return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+ free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+ struct module *mod;
+
+ for (mod = module_list; mod ; mod = mod->next) {
+ if (mod->flags & MOD_DELETED)
+ continue;
+ if (!strcmp(mod->name, name))
+ break;
+ }
+
+ return mod;
+}
static int
qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
@@ -2720,7+2760,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
nmod = space = 0;
- for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+ for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
len = strlen(mod->name)+1;
if (len > bufsize)
goto calc_space_needed;
@@ -2738,7+2778,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
calc_space_needed:
space += len;
- while ((mod = mod->next) != &kernel_module)
+ while ((mod = mod->next)->next != NULL)
space += strlen(mod->name)+1;
if (put_user(space, ret))
@@ -2752,7+2792,7 @@ qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) {
size_t i, space, len;
- if (mod == &kernel_module)
+ if (mod->next == NULL)
return -EINVAL;
if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
if (put_user(0, ret))
@@ -2796,7+2836,7 @@ qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) size_t nrefs, space, len;
struct module_ref *ref;
- if (mod == &kernel_module)
+ if (mod->next == NULL)
return -EINVAL;
if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
if (put_user(0, ret))
@@ -2898,7+2938,7 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) {
int error = 0;
- if (mod == &kernel_module)
+ if (mod->next == NULL)
return -EINVAL;
if (sizeof(struct module_info32) <= bufsize) {
@@ -2926,9+2966,11 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne int err;
lock_kernel();
- if (name_user == 0)
- mod = &kernel_module;
- else {
+ if (name_user == 0) {
+ /* This finds "kernel_module" which is not exported. */
+ for(mod = module_list; mod->next != NULL; mod = mod->next)
+ ;
+ } else {
long namelen;
char *name;
@@ -2937,9+2979,11 @@ asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kerne goto out;
}
err = -ENOENT;
- if (namelen == 0)
- mod = &kernel_module;
- else if ((mod = find_module(name)) == NULL) {
+ if (namelen == 0) {
+ /* This finds "kernel_module" which is not exported. */
+ for(mod = module_list; mod->next != NULL; mod = mod->next)
+ ;
+ } else if ((mod = find_module(name)) == NULL) {
put_mod_name(name);
goto out;
}
-/* $Id: sys_sunos32.c,v 1.18 1998/08/31 03:41:01 davem Exp $
+/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -68,6+68,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of struct file *file = NULL;
unsigned long retval, ret_type;
+ down(¤t->mm->mmap_sem);
lock_kernel();
current->personality |= PER_BSD;
if(flags & MAP_NORESERVE) {
@@ -117,6+118,7 @@ out_putf: fput(file);
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return (u32) retval;
}
@@ -131,6+133,7 @@ asmlinkage int sunos_brk(u32 baddr) unsigned long rlim;
unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
+ down(¤t->mm->mmap_sem);
lock_kernel();
if (brk < current->mm->end_code)
goto out;
@@ -178,6+181,7 @@ asmlinkage int sunos_brk(u32 baddr) retval = 0;
out:
unlock_kernel();
+ up(¤t->mm->mmap_sem);
return retval;
}
@@ -538,27+542,17 @@ struct sunos_utsname { char mach[9];
};
-asmlinkage int sunos_uname(u32 u_name)
+asmlinkage int sunos_uname(struct sunos_utsname *name)
{
- struct sunos_utsname *name = (struct sunos_utsname *)A(u_name);
- int ret = -EFAULT;
+ int ret;
down(&uts_sem);
- if(!name)
- goto out;
- if(copy_to_user(&name->sname[0],
- &system_utsname.sysname[0],
- sizeof(name->sname) - 1))
- goto out;
- copy_to_user(&name->nname[0],
- &system_utsname.nodename[0],
- sizeof(name->nname) - 1);
- put_user('\0', &name->nname[8]);
- copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
- copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
- copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
- ret = 0;
-out:
+ ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+ ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+ ret |= put_user('\0', &name->nname[8]);
+ ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
+ ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
+ ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
up(&uts_sem);
return ret;
}
@@ -837,6+831,8 @@ sunos_mount(char *type, char *dir, int flags, void *data) int ret = -EINVAL;
char *dev_fname = 0;
+ if (!capable (CAP_SYS_ADMIN))
+ return -EPERM;
lock_kernel();
/* We don't handle the integer fs type */
if ((flags & SMNT_NEWTYPE) == 0)
@@ -1211,9+1207,6 @@ struct shmid_ds32 { __kernel_ipc_pid_t32 shm_cpid;
__kernel_ipc_pid_t32 shm_lpid;
unsigned short shm_nattch;
- unsigned short shm_npages;
- u32 shm_pages;
- u32 attaches;
};
static inline int sunos_shmid_get(struct shmid_ds32 *user,
@@ -1230,8+1223,7 @@ static inline int sunos_shmid_get(struct shmid_ds32 *user, __get_user(kern->shm_ctime, &user->shm_ctime) ||
__get_user(kern->shm_cpid, &user->shm_cpid) ||
__get_user(kern->shm_lpid, &user->shm_lpid) ||
- __get_user(kern->shm_nattch, &user->shm_nattch) ||
- __get_user(kern->shm_npages, &user->shm_npages))
+ __get_user(kern->shm_nattch, &user->shm_nattch))
return -EFAULT;
return 0;
}
@@ -1250,8+1242,7 @@ static inline int sunos_shmid_put(struct shmid_ds32 *user, __put_user(kern->shm_ctime, &user->shm_ctime) ||
__put_user(kern->shm_cpid, &user->shm_cpid) ||
__put_user(kern->shm_lpid, &user->shm_lpid) ||
- __put_user(kern->shm_nattch, &user->shm_nattch) ||
- __put_user(kern->shm_npages, &user->shm_npages))
+ __put_user(kern->shm_nattch, &user->shm_nattch))
return -EFAULT;
return 0;
}
-/* $Id: systbls.S,v 1.49 1998/09/13 04:30:32 davem Exp $
+/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -20,7+20,7 @@ sys_call_table32: /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -79,7+79,7 @@ sys_call_table: /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
-/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
-/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $
+/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -27,6+27,7 @@ sparc64_cpu_startup: stxa %g1, [%g0] ASI_LSU_CONTROL
membar #Sync
wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+ wr %g0, 0, %fprs
wrpr %g0, 15, %pil
sethi %uhi(PAGE_OFFSET), %g4
-/* $Id: traps.c,v 1.54 1998/09/25 01:09:02 davem Exp $
+/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -661,7+661,7 @@ void cache_flush_trap(struct pt_regs *regs) #ifndef __SMP__
unsigned node = linux_cpus[get_cpuid()].prom_node;
#else
-#error SMP not supported on sparc64 yet
+#error cache_flush_trap not supported on sparc64/SMP yet
#endif
#if 0
-/* $Id: unaligned.c,v 1.11 1998/09/22 03:24:52 davem Exp $
+/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -58,9+58,10 @@ static inline int decode_access_size(unsigned int insn) {
unsigned int tmp;
- if (((insn >> 19) & 0xf) == 14)
- return 8; /* stx* */
- tmp = (insn >> 19) & 3;
+ tmp = ((insn >> 19) & 0xf);
+ if (tmp == 11 || tmp == 14) /* ldx/stx */
+ return 8;
+ tmp &= 3;
if(!tmp)
return 4;
else if(tmp == 3)
-# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $
+# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $
# Makefile for Sparc library files..
#
CFLAGS := $(CFLAGS)
-OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \
+OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o
@@ -16,10+16,10 @@ VIScopy.o: VIScopy.S VIS.h VISbzero.o: VISbzero.S VIS.h
.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
dep:
-/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $
+/* $Id: VIScopy.S,v 1.19 1998/10/19 21:52:19 davem Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -480,7+480,7 @@ vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync
FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_JUMP(o0, f48, finish_f0) membar #Sync
vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_SYNC(o0, f48) membar #Sync
- FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7
+ FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync
vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync
FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync
VISLOOP_PAD
@@ -569,18+569,7 @@ finish_f8: FINISH_VISCHUNK(o0, f8, f10, g3) finish_f10: FINISH_VISCHUNK(o0, f10, f12, g3)
finish_f12: FINISH_VISCHUNK(o0, f12, f14, g3)
finish_f14: UNEVEN_VISCHUNK(o0, f14, f0, g3)
-/* This is a special hack to speed up 8K page copy */
-check_finish_f16:
- andcc %g1, 7, %g0
- bne,pn %icc, finish_f16
- cmp %g7, 0x40
- bne,pn %icc, finish_f16
- FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
- membar #Sync
- EXVIS1(STBLK %f48, [%o0] ASIBLK)
- b,pt %xcc, vis_ret
-finish_f16: membar #Sync
- FINISH_VISCHUNK(o0, f16, f18, g3)
+finish_f16: FINISH_VISCHUNK(o0, f16, f18, g3)
finish_f18: FINISH_VISCHUNK(o0, f18, f20, g3)
finish_f20: FINISH_VISCHUNK(o0, f20, f22, g3)
finish_f22: FINISH_VISCHUNK(o0, f22, f24, g3)
-/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $
+/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $
* VISsave.S: Code for saving FPU register state for
* VIS routines. One should not call this directly,
* but use macros provided in <asm/visasm.h>.
@@ -76,11+76,13 @@ vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
sll %g1, 5, %g1
add %g6, AOFF_task_fpregs+0xc0, %g3
+ wr %g0, FPRS_FEF, %fprs
membar #StoreStore | #LoadStore
stda %f32, [%g2 + %g1] ASI_BLK_P
stda %f48, [%g3 + %g1] ASI_BLK_P
membar #Sync
jmpl %g7 + %g0, %g0
+
nop
.align 32
-/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $
+/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $
* blockops.S: UltraSparc block zero optimized routines.
*
* Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
#include "VIS.h"
#include <asm/visasm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/asm_offsets.h>
#define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \
fmovd %reg0, %f48; fmovd %reg1, %f50; \
fmovd %reg4, %f56; fmovd %reg5, %f58; \
fmovd %reg6, %f60; fmovd %reg7, %f62;
+#define TLBTEMP_BASE (8 * 1024 * 1024)
+#define DCACHE_SIZE (PAGE_SIZE * 2)
+#define TLBTEMP_ENT1 (61 << 3)
+#define TLBTEMP_ENT2 (62 << 3)
+#define TLBTEMP_ENTSZ (1 << 3)
+
.text
.align 32
.globl copy_page
.type copy_page,@function
copy_page: /* %o0=dest, %o1=src */
VISEntry
+ ldx [%g6 + AOFF_task_mm], %o2
+ sub %o0, %g4, %g1
+ sethi %uhi(_PAGE_VALID), %g3
+ sub %o1, %g4, %g2
+ sllx %g3, 32, %g3
+ ldx [%o2 + AOFF_mm_segments], %o0
+ or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+ or %g1, %g3, %g1
+ or %g2, %g3, %g2
+ mov TLB_TAG_ACCESS, %o2
+ sethi %hi(TLBTEMP_BASE), %o3
+ sethi %hi(DCACHE_SIZE), %o1
+ add %o0, %o3, %o0
+ add %o0, %o1, %o1
+ sethi %hi(TLBTEMP_ENT1), %o3
+ rdpr %pstate, %g3
+ wrpr %g3, PSTATE_IE, %pstate
+ ldxa [%o3] ASI_DTLB_TAG_READ, %o4
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5
+ stxa %o0, [%o2] ASI_DMMU
+ stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ add %o3, (TLBTEMP_ENTSZ), %o3
+ ldxa [%o3] ASI_DTLB_TAG_READ, %g5
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7
+ stxa %o1, [%o2] ASI_DMMU
+ stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
membar #LoadStore | #StoreStore | #StoreLoad
ldda [%o1] ASI_BLK_P, %f0
add %o1, 0x40, %o1
@@ -50,15+88,44 @@ copy_page: /* %o0=dest, %o1=src */ stda %f0, [%o0] ASI_BLK_P
add %o0, 0x40, %o0
stda %f16, [%o0] ASI_BLK_P
- membar #StoreStore | #StoreLoad
+ membar #Sync
+ VISExit
+
+ mov TLB_TAG_ACCESS, %o2
+ stxa %g5, [%o2] ASI_DMMU
+ stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ sub %o3, (TLBTEMP_ENTSZ), %o3
+ stxa %o4, [%o2] ASI_DMMU
+ stxa %o5, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
jmpl %o7 + 0x8, %g0
- VISExit
+ wrpr %g3, 0x0, %pstate
.align 32
- .globl __bzero_1page
- .type __bzero_1page,@function
-__bzero_1page: /* %o0=dest */
+ .globl clear_page
+ .type clear_page,@function
+clear_page: /* %o0=dest */
VISEntryHalf
+ ldx [%g6 + AOFF_task_mm], %o2
+ sub %o0, %g4, %g1
+ sethi %uhi(_PAGE_VALID), %g3
+ sllx %g3, 32, %g3
+ or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3
+ ldx [%o2 + AOFF_mm_segments], %o0
+ or %g1, %g3, %g1
+ mov TLB_TAG_ACCESS, %o2
+ sethi %hi(TLBTEMP_BASE), %o3
+ add %o0, %o3, %o0
+ sethi %hi(TLBTEMP_ENT2), %o3
+ rdpr %pstate, %g3
+ wrpr %g3, PSTATE_IE, %pstate
+ ldxa [%o3] ASI_DTLB_TAG_READ, %g5
+ ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7
+ stxa %o0, [%o2] ASI_DMMU
+ stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
fzero %f0 ! FPA Group
mov 32, %o1 ! IEU0
fzero %f2 ! FPA Group
@@ -79,6+146,11 @@ __bzero_1page: /* %o0=dest */ subcc %o1, 1, %o1 ! IEU1
bne,pt %icc, 1b ! CTI
add %o0, 0x100, %o0 ! IEU0 Group
- membar #StoreStore | #StoreLoad ! LSU Group
- jmpl %o7 + 0x8, %g0 ! CTI Group brk forced
- VISExitHalf
+ membar #Sync ! LSU Group
+ VISExitHalf
+
+ stxa %g5, [%o2] ASI_DMMU
+ stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ jmpl %o7 + 0x8, %g0
+ wrpr %g3, 0x0, %pstate
--- /dev/null
+/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $
+ * debuglocks.c: Debugging versions of SMP locking primitives.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+#ifdef __SMP__
+
+/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
+#ifdef SPIN_LOCK_DEBUG
+
+#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
+
+static inline void show (char *str, spinlock_t *lock, unsigned long caller)
+{
+ int cpu = smp_processor_id();
+
+ printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n",
+ str, lock, cpu, (unsigned int) caller,
+ lock->owner_pc, lock->owner_cpu);
+}
+
+static inline void show_read (char *str, rwlock_t *lock, unsigned long caller)
+{
+ int cpu = smp_processor_id();
+
+ printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n",
+ str, lock, cpu, (unsigned int) caller,
+ lock->writer_pc, lock->writer_cpu);
+}
+
+static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
+{
+ int cpu = smp_processor_id();
+
+ printk("%s(%p) CPU#%d stuck at %08x\n",
+ str, lock, cpu, (unsigned int) caller);
+ printk("Writer: PC(%08x):CPU(%x)\n",
+ lock->writer_pc, lock->writer_cpu);
+ printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n",
+ lock->reader_pc[0], lock->reader_pc[1],
+ lock->reader_pc[2], lock->reader_pc[3]);
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+void _do_spin_lock(spinlock_t *lock, char *str)
+{
+ unsigned long caller, val;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ GET_CALLER(caller);
+again:
+ __asm__ __volatile__("ldstub [%1], %0"
+ : "=r" (val)
+ : "r" (&(lock->lock))
+ : "memory");
+ membar("#StoreLoad | #StoreStore");
+ if (val) {
+ while (lock->lock) {
+ if (!--stuck) {
+ show(str, lock, caller);
+ stuck = INIT_STUCK;
+ }
+ membar("#LoadLoad");
+ }
+ goto again;
+ }
+ lock->owner_pc = ((unsigned int)caller);
+ lock->owner_cpu = cpu;
+}
+
+int _spin_trylock(spinlock_t *lock)
+{
+ unsigned long val, caller;
+ int cpu = smp_processor_id();
+
+ GET_CALLER(caller);
+ __asm__ __volatile__("ldstub [%1], %0"
+ : "=r" (val)
+ : "r" (&(lock->lock))
+ : "memory");
+ membar("#StoreLoad | #StoreStore");
+ if (!val) {
+ lock->owner_pc = ((unsigned int)caller);
+ lock->owner_cpu = cpu;
+ }
+ return val == 0;
+}
+
+void _do_spin_unlock(spinlock_t *lock)
+{
+ lock->owner_pc = 0;
+ lock->owner_cpu = NO_PROC_ID;
+ membar("#StoreStore | #LoadStore");
+ lock->lock = 0;
+}
+
+/* Keep INIT_STUCK the same... */
+
+void _do_read_lock (rwlock_t *rw, char *str)
+{
+ unsigned long caller, val;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ GET_CALLER(caller);
+wlock_again:
+ /* Wait for any writer to go away. */
+ while (((long)(rw->lock)) < 0) {
+ if (!--stuck) {
+ show_read(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ membar("#LoadLoad");
+ }
+ /* Try once to increment the counter. */
+ __asm__ __volatile__("
+ ldx [%0], %%g5
+ brlz,a,pn %%g5, 2f
+ mov 1, %0
+ add %%g5, 1, %%g7
+ casx [%0], %%g5, %%g7
+ sub %%g5, %%g7, %0
+2:" : "=r" (val)
+ : "0" (&(rw->lock))
+ : "g5", "g7", "memory");
+ membar("#StoreLoad | #StoreStore");
+ if (val)
+ goto wlock_again;
+ rw->reader_pc[cpu] = ((unsigned int)caller);
+}
+
+void _do_read_unlock (rwlock_t *rw, char *str)
+{
+ unsigned long caller, val;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ GET_CALLER(caller);
+
+ /* Drop our identity _first_. */
+ rw->reader_pc[cpu] = 0;
+runlock_again:
+ /* Spin trying to decrement the counter using casx. */
+ __asm__ __volatile__("
+ ldx [%0], %%g5
+ sub %%g5, 1, %%g7
+ casx [%0], %%g5, %%g7
+ membar #StoreLoad | #StoreStore
+ sub %%g5, %%g7, %0
+" : "=r" (val)
+ : "0" (&(rw->lock))
+ : "g5", "g7", "memory");
+ if (val) {
+ if (!--stuck) {
+ show_read(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ goto runlock_again;
+ }
+}
+
+void _do_write_lock (rwlock_t *rw, char *str)
+{
+ unsigned long caller, val;
+ int stuck = INIT_STUCK;
+ int cpu = smp_processor_id();
+
+ GET_CALLER(caller);
+wlock_again:
+ /* Spin while there is another writer. */
+ while (((long)rw->lock) < 0) {
+ if (!--stuck) {
+ show_write(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ membar("#LoadLoad");
+ }
+
+ /* Try to acuire the write bit. */
+ __asm__ __volatile__("
+ mov 1, %%g3
+ sllx %%g3, 63, %%g3
+ ldx [%0], %%g5
+ brlz,pn %%g5, 1f
+ or %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ membar #StoreLoad | #StoreStore
+ ba,pt %%xcc, 2f
+ sub %%g5, %%g7, %0
+1: mov 1, %0
+2:" : "=r" (val)
+ : "0" (&(rw->lock))
+ : "g3", "g5", "g7", "memory");
+ if (val) {
+ /* We couldn't get the write bit. */
+ if (!--stuck) {
+ show_write(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ goto wlock_again;
+ }
+ if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
+ /* Readers still around, drop the write
+ * lock, spin, and try again.
+ */
+ if (!--stuck) {
+ show_write(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ __asm__ __volatile__("
+ mov 1, %%g3
+ sllx %%g3, 63, %%g3
+1: ldx [%0], %%g5
+ andn %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%xcc, 1b
+ membar #StoreLoad | #StoreStore"
+ : /* no outputs */
+ : "r" (&(rw->lock))
+ : "g3", "g5", "g7", "cc", "memory");
+ while(rw->lock != 0) {
+ if (!--stuck) {
+ show_write(str, rw, caller);
+ stuck = INIT_STUCK;
+ }
+ membar("#LoadLoad");
+ }
+ goto wlock_again;
+ }
+
+ /* We have it, say who we are. */
+ rw->writer_pc = ((unsigned int)caller);
+ rw->writer_cpu = cpu;
+}
+
+void _do_write_unlock(rwlock_t *rw)
+{
+ unsigned long caller, val;
+ int stuck = INIT_STUCK;
+
+ GET_CALLER(caller);
+
+ /* Drop our identity _first_ */
+ rw->writer_pc = 0;
+ rw->writer_cpu = NO_PROC_ID;
+wlock_again:
+ __asm__ __volatile__("
+ mov 1, %%g3
+ sllx %%g3, 63, %%g3
+ ldx [%0], %%g5
+ andn %%g5, %%g3, %%g7
+ casx [%0], %%g5, %%g7
+ membar #StoreLoad | #StoreStore
+ sub %%g5, %%g7, %0
+" : "=r" (val)
+ : "0" (&(rw->lock))
+ : "g3", "g5", "g7", "memory");
+ if (val) {
+ if (!--stuck) {
+ show_write("write_unlock", rw, caller);
+ stuck = INIT_STUCK;
+ }
+ goto wlock_again;
+ }
+}
+
+#endif /* SPIN_LOCK_DEBUG */
+#endif /* __SMP__ */
+++ /dev/null
-/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
- * locks.S: SMP low-level lock primitives on Sparc64.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/asm_offsets.h>
-#include <asm/ptrace.h>
-#include <asm/smp.h>
-
- .text
- .align 32
-
-___lk_busy_spin:
- ldub [%g1 + 0], %g2
- brnz,pt %g2, ___lk_busy_spin
- membar #LoadLoad
- b,pt %xcc, 1f
- ldstub [%g1 + 0], %g2
-
- .globl ___lock_kernel
-___lock_kernel:
- addcc %g2, -1, %g2
- rdpr %pil, %g3
- bcs,a,pn %icc, 9f
- stw %g2, [%g6 + AOFF_task_lock_depth]
- wrpr %g0, 15, %pil
- ldstub [%g1 + 0], %g2
-1: brnz,pn %g2, ___lk_busy_spin
- membar #StoreLoad | #StoreStore
- lduw [%g6 + AOFF_task_processor], %g2
- stb %g2, [%g1 + 1]
-2: mov -1, %g2
- stw %g2, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, 0, %pil
-9: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
-
- .globl ___lock_reacquire_kernel
-___lock_reacquire_kernel:
- rdpr %pil, %g3
- wrpr %g0, 15, %pil
- stw %g2, [%g6 + AOFF_task_lock_depth]
- ldstub [%g1 + 0], %g2
-1: brz,pt %g2, 3f
- membar #StoreLoad | #StoreStore
-2: ldub [%g1 + 0], %g2
- brnz,pt %g2, 2b
- membar #LoadLoad
- b,pt %xcc, 1b
- ldstub [%g1 + 0], %g2
-3: lduw [%g6 + AOFF_task_processor], %g2
- stb %g2, [%g1 + 1]
- wrpr %g3, 0, %pil
- jmpl %o7 + 0x8, %g0
- mov %g5, %o7
-
-#undef NO_PROC_ID
-#define NO_PROC_ID 0xff
-
- .globl ___unlock_kernel
-___unlock_kernel:
- addcc %g2, 1, %g2
- rdpr %pil, %g3
- bne,a,pn %icc, 1f
- stw %g2, [%g6 + AOFF_task_lock_depth]
- wrpr 15, %pil
- mov NO_PROC_ID, %g2
- stb %g2, [%g1 + 1]
- membar #StoreStore | #LoadStore
- stb %g0, [%g1 + 0]
- stw %g0, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, 0, %pil
-1: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
-
#define HI_MAGIC 0x80808080
.align 32
- .global __strlen
+ .global strlen, __strlen
+strlen:
__strlen:
mov %o0, %o1
andcc %o0, 3, %g0
@@ -16,10+16,4 @@ O_OBJS := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o \ fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o \
fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
-.S.s:
- $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
-
-.S.o:
- $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
-
include $(TOPDIR)/Rules.make
-/* $Id: fault.c,v 1.24 1998/09/22 03:27:33 davem Exp $
+/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -154,6+154,7 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
+ current->mm->segments = (void *) (address & PAGE_SIZE);
handle_mm_fault(current, vma, address, write);
up(&mm->mmap_sem);
return;
-/* $Id: init.c,v 1.98 1998/09/28 06:18:39 davem Exp $
+/* $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7+45,6 @@ extern char __init_begin, __init_end, etext, __bss_start;
int do_check_pgt_cache(int low, int high)
{
- struct page *page, *page2;
int freed = 0;
if(pgtable_cache_size > high) {
@@ -60,6+59,7 @@ int do_check_pgt_cache(int low, int high) }
#ifndef __SMP__
if (pgd_cache_size > high / 4) {
+ struct page *page, *page2;
for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) {
if ((unsigned long)page->pprev_hash == 3) {
if (page2)
@@ -537,7+537,7 @@ static inline void inherit_prom_mappings(void) if (pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool,
PMD_TABLE_SIZE);
- clear_page(pmdp);
+ memset(pmdp, 0, PAGE_SIZE);
pgd_set(pgdp, pmdp);
}
pmdp = pmd_offset(pgdp, vaddr);
@@ -591,12+591,17 @@ static void __flush_nucleus_vptes(void) }
static int prom_ditlb_set = 0;
-int prom_itlb_ent, prom_dtlb_ent;
-unsigned long prom_itlb_tag, prom_itlb_data;
-unsigned long prom_dtlb_tag, prom_dtlb_data;
+struct prom_tlb_entry {
+ int tlb_ent;
+ unsigned long tlb_tag;
+ unsigned long tlb_data;
+};
+struct prom_tlb_entry prom_itlb[8], prom_dtlb[8];
void prom_world(int enter)
{
+ int i;
+
if (!prom_ditlb_set)
return;
if (enter) {
@@ -604,29+609,44 @@ void prom_world(int enter) __flush_nucleus_vptes();
/* Install PROM world. */
- __asm__ __volatile__("stxa %0, [%1] %2"
- : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
+ for (i = 0; i < 8; i++) {
+ if (prom_dtlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
"i" (ASI_DMMU));
- membar("#Sync");
- spitfire_put_dtlb_data(62, prom_dtlb_data);
- membar("#Sync");
- __asm__ __volatile__("stxa %0, [%1] %2"
- : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
+ membar("#Sync");
+ spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+ prom_dtlb[i].tlb_data);
+ membar("#Sync");
+ }
+
+ if (prom_itlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
"i" (ASI_IMMU));
- membar("#Sync");
- spitfire_put_itlb_data(62, prom_itlb_data);
- membar("#Sync");
+ membar("#Sync");
+ spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+ prom_itlb[i].tlb_data);
+ membar("#Sync");
+ }
+ }
} else {
- __asm__ __volatile__("stxa %%g0, [%0] %1"
+ for (i = 0; i < 8; i++) {
+ if (prom_dtlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
- membar("#Sync");
- spitfire_put_dtlb_data(62, 0x0UL);
- membar("#Sync");
- __asm__ __volatile__("stxa %%g0, [%0] %1"
+ membar("#Sync");
+ spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
+ membar("#Sync");
+ }
+ if (prom_itlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
- membar("#Sync");
- spitfire_put_itlb_data(62, 0x0UL);
- membar("#Sync");
+ membar("#Sync");
+ spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
+ membar("#Sync");
+ }
+ }
}
}
@@ -640,8+660,8 @@ void inherit_locked_prom_mappings(int save_p) * 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.
+ * irrecovable rule on the PROM, it is allowed 8 locked
+ * entries in the ITLB and 8 in the DTLB.
*
* Supposedly the upper 16GB of the address space is
* reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
@@ -650,17+670,23 @@ void inherit_locked_prom_mappings(int save_p) * systems to coordinate mmu mappings is also COMPLETELY
* UNDOCUMENTED!!!!!! Thanks S(t)un!
*/
+ if (save_p) {
+ for(i = 0; i < 8; i++) {
+ prom_dtlb[i].tlb_ent = -1;
+ prom_itlb[i].tlb_ent = -1;
+ }
+ }
for(i = 0; i < 63; i++) {
unsigned long data;
data = spitfire_get_dtlb_data(i);
- if(!dtlb_seen && (data & _PAGE_L)) {
+ if(data & _PAGE_L) {
unsigned long tag = spitfire_get_dtlb_tag(i);
if(save_p) {
- prom_dtlb_ent = i;
- prom_dtlb_tag = tag;
- prom_dtlb_data = data;
+ prom_dtlb[dtlb_seen].tlb_ent = i;
+ prom_dtlb[dtlb_seen].tlb_tag = tag;
+ prom_dtlb[dtlb_seen].tlb_data = data;
}
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
@@ -668,18+694,22 @@ void inherit_locked_prom_mappings(int save_p) spitfire_put_dtlb_data(i, 0x0UL);
membar("#Sync");
- dtlb_seen = 1;
- if(itlb_seen)
+ dtlb_seen++;
+ if(dtlb_seen > 7)
break;
}
+ }
+ for(i = 0; i < 63; i++) {
+ unsigned long data;
+
data = spitfire_get_itlb_data(i);
- if(!itlb_seen && (data & _PAGE_L)) {
+ if(data & _PAGE_L) {
unsigned long tag = spitfire_get_itlb_tag(i);
if(save_p) {
- prom_itlb_ent = i;
- prom_itlb_tag = tag;
- prom_itlb_data = data;
+ prom_itlb[itlb_seen].tlb_ent = i;
+ prom_itlb[itlb_seen].tlb_tag = tag;
+ prom_itlb[itlb_seen].tlb_data = data;
}
__asm__ __volatile__("stxa %%g0, [%0] %1"
: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
@@ -687,15+717,8 @@ void inherit_locked_prom_mappings(int save_p) 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)
+ itlb_seen++;
+ if(itlb_seen > 7)
break;
}
}
@@ -706,19+729,29 @@ void inherit_locked_prom_mappings(int save_p) /* Give PROM back his world, done during reboots... */
void prom_reload_locked(void)
{
- __asm__ __volatile__("stxa %0, [%1] %2"
- : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS),
- "i" (ASI_DMMU));
- membar("#Sync");
- spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data);
- membar("#Sync");
+ int i;
- __asm__ __volatile__("stxa %0, [%1] %2"
- : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS),
- "i" (ASI_IMMU));
- membar("#Sync");
- spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data);
- membar("#Sync");
+ for (i = 0; i < 8; i++) {
+ if (prom_dtlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+ "i" (ASI_DMMU));
+ membar("#Sync");
+ spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+ prom_dtlb[i].tlb_data);
+ membar("#Sync");
+ }
+
+ if (prom_itlb[i].tlb_ent != -1) {
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
+ "i" (ASI_IMMU));
+ membar("#Sync");
+ spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+ prom_itlb[i].tlb_data);
+ membar("#Sync");
+ }
+ }
}
void __flush_dcache_range(unsigned long start, unsigned long end)
@@ -844,7+877,7 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
if(pmd) {
- clear_page(pmd);
+ memset(pmd, 0, PAGE_SIZE);
pgd_set(pgd, pmd);
return pmd + offset;
}
@@ -857,7+890,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
if(pte) {
- clear_page(pte);
+ memset(pte, 0, PAGE_SIZE);
pmd_set(pmd, pte);
return pte + offset;
}
@@ -875,13+908,13 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end)) pgdp = pgd_offset(init_task.mm, start);
if (pgd_none(*pgdp)) {
pmdp = sparc_init_alloc(&mempool, PAGE_SIZE);
- clear_page(pmdp);
+ memset(pmdp, 0, PAGE_SIZE);
pgd_set(pgdp, pmdp);
}
pmdp = pmd_offset(pgdp, start);
if (pmd_none(*pmdp)) {
ptep = sparc_init_alloc(&mempool, PAGE_SIZE);
- clear_page(ptep);
+ memset(ptep, 0, PAGE_SIZE);
pmd_set(pmdp, ptep);
}
start = (start + PMD_SIZE) & PMD_MASK;
-/* $Id: ultra.S,v 1.27 1998/09/28 06:18:42 davem Exp $
+/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -125,34+125,39 @@ __flush_tlb_range_pbp_slow: retl
wrpr %g1, 0x0, %pstate
- /* Unfortunately, it is necessary. */
- .globl flush_page_to_ram
-flush_page_to_ram: /* %o0 = page */
- rdpr %pstate, %g5
- wrpr %g5, PSTATE_IE, %pstate
- sethi %hi(dcache_aliases_found), %g1
- ldx [%g1 + %lo(dcache_aliases_found)], %g2
- sub %o0, %g4, %o0 ! Get phys_page
- clr %o2 ! This dcache area begin
- sethi %hi(1<<14), %o1 ! This dcache area end
-1: ldxa [%o2] ASI_DCACHE_TAG, %o3
- andcc %o3, 0x3, %g0 ! Valid bits set?
- be,pn %xcc, 2f ! Nope, skip this one
- andn %o3, 0x3, %o3 ! Mask out valid bits
- sllx %o3, (13 - 2), %o3 ! Shift into physaddr
- cmp %o3, %o0 ! Match?
- bne,pt %xcc, 2f ! Nope, skip to next
+ .align 32
+ .globl flush_icache_page
+flush_icache_page: /* %o0 = phys_page */
+ sethi %hi(1 << 13), %o2 ! I-cache valid/set bit
+ srlx %o0, 5, %o0 ! phys-addr comparitor
+ clr %o1 ! I-cache address
+1: ldda [%o1] ASI_IC_TAG, %o4
+ andcc %o5, %o2, %g0
+ be,pn %xcc, 2f
+ andn %o5, %o2, %o5
+ cmp %o5, %o0
+
+ be,pn %xcc, iflush1
+2: ldda [%o1 + %o2] ASI_IC_TAG, %o4
+4: andcc %o5, %o2, %g0
+ be,pn %xcc, 3f
+ andn %o5, %o2, %o5
+ cmp %o5, %o0
+ be,pn %xcc, iflush2
nop
- stxa %g0, [%o2] ASI_DCACHE_TAG
- membar #Sync
- add %g2, 1, %g2 ! Increment alias counter
-2: add %o2, (1<<5), %o2 ! 32-bytes per full line
- cmp %o2, %o1
+
+3: add %o1, 0x20, %o1
+ cmp %o1, %o2
bne,pt %xcc, 1b
nop
- stx %g2, [%g1 + %lo(dcache_aliases_found)]
retl
- wrpr %g5, 0x0, %pstate
+ nop
+iflush1:stxa %g0, [%o1] ASI_IC_TAG
+ membar #Sync
+ ba,a,pt %xcc, 4b
+iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG
+ membar #Sync
+ ba,a,pt %xcc, 3b
#ifdef __SMP__
/* These are all called by the slaves of a cross call, at
-/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $
+/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -40,25+40,18 @@ extern int serial_console; /* 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)
{
- extern void kernel_enter_debugger(void);
- /* extern void install_obp_ticker(void); */
- /* extern void install_linux_ticker(void); */
unsigned long flags;
- /* kernel_enter_debugger(); */
#ifdef CONFIG_SUN_CONSOLE
if(!serial_console && prom_palette)
prom_palette (1);
#endif
- /* install_obp_ticker(); */
- save_flags(flags); cli();
+ __save_and_cli(flags);
p1275_cmd ("enter", P1275_INOUT(0,0));
- restore_flags(flags);
- /* install_linux_ticker(); */
+ __restore_flags(flags);
#ifdef CONFIG_SUN_CONSOLE
if(!serial_console && prom_palette)
prom_palette (0);
/* Set prom sync handler to call function 'funcp'. */
void
-prom_setsync(sync_func_t funcp)
+prom_setcallback(callback_func_t funcp)
{
if(!funcp) return;
p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)|
-/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $
+/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#include <asm/system.h>
#include <asm/spitfire.h>
#include <asm/pstate.h>
+#include <asm/spinlock.h>
struct {
- long prom_sync_routine; /* 0x00 */
+ long prom_callback; /* 0x00 */
void (*prom_cif_handler)(long *); /* 0x08 */
unsigned long prom_cif_stack; /* 0x10 */
unsigned long prom_args [23]; /* 0x18 */
@@ -31,29+32,262 @@ void prom_cif_interface (void) __asm__ __volatile__ ("
mov %0, %%o0
ldx [%%o0 + 0x010], %%o1 ! prom_cif_stack
- save %%o1, -0xc0, %%sp
+ save %%o1, -0x190, %%sp
ldx [%%i0 + 0x008], %%l2 ! prom_cif_handler
rdpr %%pstate, %%l4
- mov %%g4, %%l0
- mov %%g6, %%l1
- wrpr %%l4, %1, %%pstate ! turn on address masking
+ wrpr %%g0, 0x15, %%pstate ! save alternate globals
+ stx %%g1, [%%sp + 2047 + 0x0b0]
+ stx %%g2, [%%sp + 2047 + 0x0b8]
+ stx %%g3, [%%sp + 2047 + 0x0c0]
+ stx %%g4, [%%sp + 2047 + 0x0c8]
+ stx %%g5, [%%sp + 2047 + 0x0d0]
+ stx %%g6, [%%sp + 2047 + 0x0d8]
+ stx %%g7, [%%sp + 2047 + 0x0e0]
+ wrpr %%g0, 0x814, %%pstate ! save interrupt globals
+ stx %%g1, [%%sp + 2047 + 0x0e8]
+ stx %%g2, [%%sp + 2047 + 0x0f0]
+ stx %%g3, [%%sp + 2047 + 0x0f8]
+ stx %%g4, [%%sp + 2047 + 0x100]
+ stx %%g5, [%%sp + 2047 + 0x108]
+ stx %%g6, [%%sp + 2047 + 0x110]
+ stx %%g7, [%%sp + 2047 + 0x118]
+ wrpr %%g0, 0x14, %%pstate ! save normal globals
+ stx %%g1, [%%sp + 2047 + 0x120]
+ stx %%g2, [%%sp + 2047 + 0x128]
+ stx %%g3, [%%sp + 2047 + 0x130]
+ stx %%g4, [%%sp + 2047 + 0x138]
+ stx %%g5, [%%sp + 2047 + 0x140]
+ stx %%g6, [%%sp + 2047 + 0x148]
+ stx %%g7, [%%sp + 2047 + 0x150]
+ wrpr %%g0, 0x414, %%pstate ! save mmu globals
+ stx %%g1, [%%sp + 2047 + 0x158]
+ stx %%g2, [%%sp + 2047 + 0x160]
+ stx %%g3, [%%sp + 2047 + 0x168]
+ stx %%g4, [%%sp + 2047 + 0x170]
+ stx %%g5, [%%sp + 2047 + 0x178]
+ stx %%g6, [%%sp + 2047 + 0x180]
+ stx %%g7, [%%sp + 2047 + 0x188]
+ mov %%g1, %%l0 ! also save to locals, so we can handle
+ mov %%g2, %%l1 ! tlb faults later on, when accessing
+ mov %%g3, %%l3 ! the stack.
+ mov %%g7, %%l5
+ wrpr %%l4, %1, %%pstate ! turn off interrupts
call %%l2
add %%i0, 0x018, %%o0 ! prom_args
- wrpr %%l4, 0, %%pstate ! put pstate back
- mov %%l0, %%g4
+ wrpr %%g0, 0x414, %%pstate ! restore mmu globals
+ mov %%l0, %%g1
+ mov %%l1, %%g2
+ mov %%l3, %%g3
+ mov %%l5, %%g7
+ wrpr %%g0, 0x14, %%pstate ! restore normal globals
+ ldx [%%sp + 2047 + 0x120], %%g1
+ ldx [%%sp + 2047 + 0x128], %%g2
+ ldx [%%sp + 2047 + 0x130], %%g3
+ ldx [%%sp + 2047 + 0x138], %%g4
+ ldx [%%sp + 2047 + 0x140], %%g5
+ ldx [%%sp + 2047 + 0x148], %%g6
+ ldx [%%sp + 2047 + 0x150], %%g7
+ wrpr %%g0, 0x814, %%pstate ! restore interrupt globals
+ ldx [%%sp + 2047 + 0x0e8], %%g1
+ ldx [%%sp + 2047 + 0x0f0], %%g2
+ ldx [%%sp + 2047 + 0x0f8], %%g3
+ ldx [%%sp + 2047 + 0x100], %%g4
+ ldx [%%sp + 2047 + 0x108], %%g5
+ ldx [%%sp + 2047 + 0x110], %%g6
+ ldx [%%sp + 2047 + 0x118], %%g7
+ wrpr %%g0, 0x15, %%pstate ! restore alternate globals
+ ldx [%%sp + 2047 + 0x0b0], %%g1
+ ldx [%%sp + 2047 + 0x0b8], %%g2
+ ldx [%%sp + 2047 + 0x0c0], %%g3
+ ldx [%%sp + 2047 + 0x0c8], %%g4
+ ldx [%%sp + 2047 + 0x0d0], %%g5
+ ldx [%%sp + 2047 + 0x0d8], %%g6
+ ldx [%%sp + 2047 + 0x0e0], %%g7
+ wrpr %%l4, 0, %%pstate ! restore original pstate
ret
- restore %%l1, 0, %%g6
- save %%sp, -0xc0, %%sp ! If you change the offset of the save
- rdpr %%pstate, %%l4 ! here, please change the 0x8038
- andn %%l4, %1, %%l3 ! constant below as well
- wrpr %%l3, %%pstate
- ldx [%%o0 + 0x000], %%l2
+ restore
+ " : : "r" (&p1275buf), "i" (PSTATE_IE));
+}
+
+void prom_cif_callback(void)
+{
+ __asm__ __volatile__ ("
+ mov %0, %%o1
+ save %%sp, -0x270, %%sp
+ rdpr %%pstate, %%l4
+ wrpr %%g0, 0x15, %%pstate ! save PROM alternate globals
+ stx %%g1, [%%sp + 2047 + 0x0b0]
+ stx %%g2, [%%sp + 2047 + 0x0b8]
+ stx %%g3, [%%sp + 2047 + 0x0c0]
+ stx %%g4, [%%sp + 2047 + 0x0c8]
+ stx %%g5, [%%sp + 2047 + 0x0d0]
+ stx %%g6, [%%sp + 2047 + 0x0d8]
+ stx %%g7, [%%sp + 2047 + 0x0e0]
+ ! restore Linux alternate globals
+ ldx [%%sp + 2047 + 0x190], %%g1
+ ldx [%%sp + 2047 + 0x198], %%g2
+ ldx [%%sp + 2047 + 0x1a0], %%g3
+ ldx [%%sp + 2047 + 0x1a8], %%g4
+ ldx [%%sp + 2047 + 0x1b0], %%g5
+ ldx [%%sp + 2047 + 0x1b8], %%g6
+ ldx [%%sp + 2047 + 0x1c0], %%g7
+ wrpr %%g0, 0x814, %%pstate ! save PROM interrupt globals
+ stx %%g1, [%%sp + 2047 + 0x0e8]
+ stx %%g2, [%%sp + 2047 + 0x0f0]
+ stx %%g3, [%%sp + 2047 + 0x0f8]
+ stx %%g4, [%%sp + 2047 + 0x100]
+ stx %%g5, [%%sp + 2047 + 0x108]
+ stx %%g6, [%%sp + 2047 + 0x110]
+ stx %%g7, [%%sp + 2047 + 0x118]
+ ! restore Linux interrupt globals
+ ldx [%%sp + 2047 + 0x1c8], %%g1
+ ldx [%%sp + 2047 + 0x1d0], %%g2
+ ldx [%%sp + 2047 + 0x1d8], %%g3
+ ldx [%%sp + 2047 + 0x1e0], %%g4
+ ldx [%%sp + 2047 + 0x1e8], %%g5
+ ldx [%%sp + 2047 + 0x1f0], %%g6
+ ldx [%%sp + 2047 + 0x1f8], %%g7
+ wrpr %%g0, 0x14, %%pstate ! save PROM normal globals
+ stx %%g1, [%%sp + 2047 + 0x120]
+ stx %%g2, [%%sp + 2047 + 0x128]
+ stx %%g3, [%%sp + 2047 + 0x130]
+ stx %%g4, [%%sp + 2047 + 0x138]
+ stx %%g5, [%%sp + 2047 + 0x140]
+ stx %%g6, [%%sp + 2047 + 0x148]
+ stx %%g7, [%%sp + 2047 + 0x150]
+ ! restore Linux normal globals
+ ldx [%%sp + 2047 + 0x200], %%g1
+ ldx [%%sp + 2047 + 0x208], %%g2
+ ldx [%%sp + 2047 + 0x210], %%g3
+ ldx [%%sp + 2047 + 0x218], %%g4
+ ldx [%%sp + 2047 + 0x220], %%g5
+ ldx [%%sp + 2047 + 0x228], %%g6
+ ldx [%%sp + 2047 + 0x230], %%g7
+ wrpr %%g0, 0x414, %%pstate ! save PROM mmu globals
+ stx %%g1, [%%sp + 2047 + 0x158]
+ stx %%g2, [%%sp + 2047 + 0x160]
+ stx %%g3, [%%sp + 2047 + 0x168]
+ stx %%g4, [%%sp + 2047 + 0x170]
+ stx %%g5, [%%sp + 2047 + 0x178]
+ stx %%g6, [%%sp + 2047 + 0x180]
+ stx %%g7, [%%sp + 2047 + 0x188]
+ ! restore Linux mmu globals
+ ldx [%%sp + 2047 + 0x238], %%o0
+ ldx [%%sp + 2047 + 0x240], %%o1
+ ldx [%%sp + 2047 + 0x248], %%l2
+ ldx [%%sp + 2047 + 0x250], %%l3
+ ldx [%%sp + 2047 + 0x258], %%l5
+ ldx [%%sp + 2047 + 0x260], %%l6
+ ldx [%%sp + 2047 + 0x268], %%l7
+ ! switch to Linux tba
+ sethi %%hi(sparc64_ttable_tl0), %%l1
+ rdpr %%tba, %%l0 ! save PROM tba
+ mov %%o0, %%g1
+ mov %%o1, %%g2
+ mov %%l2, %%g3
+ mov %%l3, %%g4
+ mov %%l5, %%g5
+ mov %%l6, %%g6
+ mov %%l7, %%g7
+ wrpr %%l1, %%tba ! install Linux tba
+ wrpr %%l4, 0, %%pstate ! restore PSTATE
+ call prom_world
+ mov %%g0, %%o0
+ ldx [%%i1 + 0x000], %%l2
call %%l2
- nop
+ mov %%i0, %%o0
+ mov %%o0, %%l1
+ call prom_world
+ or %%g0, 1, %%o0
+ wrpr %%g0, 0x14, %%pstate ! interrupts off
+ ! restore PROM mmu globals
+ ldx [%%sp + 2047 + 0x158], %%o0
+ ldx [%%sp + 2047 + 0x160], %%o1
+ ldx [%%sp + 2047 + 0x168], %%l2
+ ldx [%%sp + 2047 + 0x170], %%l3
+ ldx [%%sp + 2047 + 0x178], %%l5
+ ldx [%%sp + 2047 + 0x180], %%l6
+ ldx [%%sp + 2047 + 0x188], %%l7
+ wrpr %%g0, 0x414, %%pstate ! restore PROM mmu globals
+ mov %%o0, %%g1
+ mov %%o1, %%g2
+ mov %%l2, %%g3
+ mov %%l3, %%g4
+ mov %%l5, %%g5
+ mov %%l6, %%g6
+ mov %%l7, %%g7
+ wrpr %%l0, %%tba ! restore PROM tba
+ wrpr %%g0, 0x14, %%pstate ! restore PROM normal globals
+ ldx [%%sp + 2047 + 0x120], %%g1
+ ldx [%%sp + 2047 + 0x128], %%g2
+ ldx [%%sp + 2047 + 0x130], %%g3
+ ldx [%%sp + 2047 + 0x138], %%g4
+ ldx [%%sp + 2047 + 0x140], %%g5
+ ldx [%%sp + 2047 + 0x148], %%g6
+ ldx [%%sp + 2047 + 0x150], %%g7
+ wrpr %%g0, 0x814, %%pstate ! restore PROM interrupt globals
+ ldx [%%sp + 2047 + 0x0e8], %%g1
+ ldx [%%sp + 2047 + 0x0f0], %%g2
+ ldx [%%sp + 2047 + 0x0f8], %%g3
+ ldx [%%sp + 2047 + 0x100], %%g4
+ ldx [%%sp + 2047 + 0x108], %%g5
+ ldx [%%sp + 2047 + 0x110], %%g6
+ ldx [%%sp + 2047 + 0x118], %%g7
+ wrpr %%g0, 0x15, %%pstate ! restore PROM alternate globals
+ ldx [%%sp + 2047 + 0x0b0], %%g1
+ ldx [%%sp + 2047 + 0x0b8], %%g2
+ ldx [%%sp + 2047 + 0x0c0], %%g3
+ ldx [%%sp + 2047 + 0x0c8], %%g4
+ ldx [%%sp + 2047 + 0x0d0], %%g5
+ ldx [%%sp + 2047 + 0x0d8], %%g6
+ ldx [%%sp + 2047 + 0x0e0], %%g7
wrpr %%l4, 0, %%pstate
ret
- restore
- " : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */));
+ restore %%l1, 0, %%o0
+ " : : "r" (&p1275buf), "i" (PSTATE_PRIV));
+}
+
+/* We need some SMP protection here. But be careful as
+ * prom callback code can call into here too, this is why
+ * the counter is needed. -DaveM
+ */
+static int prom_entry_depth = 0;
+#ifdef __SMP__
+static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
+extern void smp_capture(void);
+extern void smp_release(void);
+#endif
+
+static __inline__ unsigned long prom_get_lock(void)
+{
+ unsigned long flags;
+
+ __save_and_cli(flags);
+ if (prom_entry_depth == 0) {
+ spin_lock(&prom_entry_lock);
+
+#if 1 /* DEBUGGING */
+ if (prom_entry_depth != 0)
+ panic("prom_get_lock");
+#endif
+#ifdef __SMP__
+ smp_capture();
+#endif
+ }
+ prom_entry_depth++;
+
+ return flags;
+}
+
+static __inline__ void prom_release_lock(unsigned long flags)
+{
+ if (--prom_entry_depth == 0) {
+#ifdef __SMP__
+ smp_release();
+#endif
+ spin_unlock(&prom_entry_lock);
+ }
+ __restore_flags(flags);
}
long p1275_cmd (char *service, long fmt, ...)
@@ -66,13+300,15 @@ long p1275_cmd (char *service, long fmt, ...) long ctx = 0;
p = p1275buf.prom_buffer;
- __save_and_cli(flags);
ctx = spitfire_get_primary_context ();
if (ctx) {
flushw_user ();
spitfire_set_primary_context (0);
}
- p1275buf.prom_args[0] = (unsigned long)p; /* service */
+
+ flags = prom_get_lock();
+
+ p1275buf.prom_args[0] = (unsigned long)p; /* service */
strcpy (p, service);
p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */
@@ -82,7+318,9 @@ long p1275_cmd (char *service, long fmt, ...) for (i = 0; i < nargs; i++, attrs >>= 3) {
switch (attrs & 0x7) {
case P1275_ARG_NUMBER:
- p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break;
+ p1275buf.prom_args[i + 3] =
+ (unsigned)va_arg(list, long);
+ break;
case P1275_ARG_IN_STRING:
strcpy (p, va_arg(list, char *));
p1275buf.prom_args[i + 3] = (unsigned long)p;
@@ -111,16+349,16 @@ long p1275_cmd (char *service, long fmt, ...) p += 32;
break;
case P1275_ARG_IN_FUNCTION:
- p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38;
- p1275buf.prom_sync_routine = va_arg(list, long); break;
+ p1275buf.prom_args[i + 3] =
+ (unsigned long)prom_cif_callback;
+ p1275buf.prom_callback = va_arg(list, long);
+ break;
}
}
va_end(list);
prom_world(1);
-
prom_cif_interface();
-
prom_world(0);
attrs = fmt >> 8;
@@ -128,11+366,14 @@ long p1275_cmd (char *service, long fmt, ...) for (i = 0; i < nargs; i++, attrs >>= 3) {
switch (attrs & 0x7) {
case P1275_ARG_NUMBER:
- (void) va_arg(list, long); break;
+ (void) va_arg(list, long);
+ break;
case P1275_ARG_IN_STRING:
- (void) va_arg(list, char *); break;
+ (void) va_arg(list, char *);
+ break;
case P1275_ARG_IN_FUNCTION:
- (void) va_arg(list, long); break;
+ (void) va_arg(list, long);
+ break;
case P1275_ARG_IN_BUF:
(void) va_arg(list, char *);
(void) va_arg(list, long);
@@ -152,10+393,12 @@ long p1275_cmd (char *service, long fmt, ...) }
va_end(list);
x = p1275buf.prom_args [nargs + 3];
-
+
+ prom_release_lock(flags);
+
if (ctx)
spitfire_set_primary_context (ctx);
- __restore_flags(flags);
+
return x;
}
@@ -15,10+15,10 @@ CPPFLAGS = $(MODFLAGS) endif
.S.s:
- $(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o
ifneq ($(CONFIG_SOLARIS_EMUL),y)
do_it_all:
endif
endif
-ifeq ($(CONFIG_SUN_OPENPROMIO),y)
-else
- ifeq ($(CONFIG_SUN_OPENPROMIO),m)
- endif
-endif
-
ifeq ($(CONFIG_WDT),y)
L_OBJS += wdt.o
else
* Parport sharing hacking by Andrea Arcangeli
* Fixed kernel_(to/from)_user memory copy to check for errors
* by Riccardo Facchetti <fizban@tin.it>
- * Interrupt handling workaround for printers with buggy handshake
- * by Andrea Arcangeli, 11 May 98
+ * Redesigned interrupt handling for handle printers with buggy handshake
+ * by Andrea Arcangeli, 11 May 1998
+ * Full efficient handling of printer with buggy irq handshake (now I have
+ * understood the meaning of the strange handshake). This is done sending new
+ * characters if the interrupt is just happened, even if the printer say to
+ * be still BUSY. This is needed at least with Epson Stylus Color.
+ * I also fixed the irq on the rising edge of the strobe problem.
+ * Andrea Arcangeli, 15 Oct 1998
*/
/* This driver should, in theory, work with any parallel port that has an
*
* ftp://e-mind.com/pub/linux/pscan/
*
- * 11 May 98, Andrea Arcangeli
+ * My printer scanner run on an Epson Stylus Color show that such printer
+ * generates the irq on the _rising_ edge of the STROBE. Now lp handle
+ * this case fine too.
+ *
+ * I also understood that on such printer we are just allowed to send
+ * new characters after the interrupt even if the BUSY line is still active.
+ *
+ * 15 Oct 1998, Andrea Arcangeli
*/
#include <linux/module.h>
#include <linux/parport.h>
#undef LP_STATS
-#undef LP_NEED_CAREFUL
#include <linux/lp.h>
#include <asm/irq.h>
@@ -115,16+127,21 @@ struct lp_struct lp_table[LP_NO] = NULL, 0, 0, 0}
};
-/* Test if printer is ready (and optionally has no error conditions) */
-#ifdef LP_NEED_CAREFUL
-#define LP_READY(minor, status) \
- ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : ((status) & LP_PBUSY))
-#define _LP_CAREFUL_READY(status) \
+/*
+ * Test if printer is ready.
+ */
+#define LP_READY(status) \
((status) & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
(LP_PBUSY|LP_PSELECD|LP_PERRORP)
-#else
-#define LP_READY(minor, status) ((status) & LP_PBUSY)
-#endif
+
+/*
+ * Test if the printer has error conditions.
+ */
+#define LP_NO_ERROR(status) \
+ ((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
+ (LP_PSELECD|LP_PERRORP)
+
+#define LP_NO_ACKING(status) ((status) & LP_PACK)
#undef LP_DEBUG
#undef LP_READ_DEBUG
@@ -187,52+204,88 @@ static int lp_reset(int minor) return retval;
}
-static inline int lp_char(char lpchar, int minor)
+static inline void lp_wait(int minor)
{
unsigned int wait = 0;
+#ifndef __sparc__
+ /* FIXME: should be function(time) */
+ while (wait++ != LP_WAIT(minor));
+#else
+ udelay(1);
+#endif
+
+}
+
+static inline int lp_char(char lpchar, int minor)
+{
unsigned long count = 0;
#ifdef LP_STATS
struct lp_stats *stats;
#endif
+ if (signal_pending(current))
+ return 0;
+
for (;;)
{
+ unsigned char status;
lp_yield(minor);
- if (LP_READY(minor, r_str(minor)))
+
+ status = r_str(minor);
+ /*
+ * On Epson Stylus Color we must continue even if LP_READY()
+ * is false to be efficient. This way is backwards
+ * compatible with old not-buggy printers. -arca
+ */
+ if (LP_NO_ERROR(status) &&
+ ((lp_table[minor].irq_detected && LP_NO_ACKING(status)) ||
+ LP_READY(status)))
break;
- if (++count == LP_CHAR(minor) || signal_pending(current))
- return 0;
+ /*
+ * To have a chance to sleep on the interrupt we should break
+ * the polling loop ASAP. Unfortunately there seems to be
+ * some hardware that underperform so we leave this
+ * configurable at runtime. So when printing with irqs
+ * `tunelp /dev/lp0 -c 1' is a must to take the full
+ * advantage of the irq. -arca
+ */
+ if (++count == LP_CHAR(minor))
+ return 0;
}
w_dtr(minor, lpchar);
+
#ifdef LP_STATS
stats = &LP_STAT(minor);
stats->chars++;
#endif
+
+ /*
+ * Epson Stylus Color generate the IRQ on the rising edge of
+ * strobe so clean the irq's information before playing with
+ * the strobe. -arca
+ */
+ lp_table[minor].irq_detected = 0;
+ lp_table[minor].irq_missed = 0;
+ /*
+ * Be sure that the CPU doesn' t reorder instruction. I am not sure
+ * if it' s needed also before an outb(). If not tell me ;-). -arca
+ */
+ mb();
+
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
-#ifndef __sparc__
- while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
- wait++;
-#else
- udelay(1);
-#endif
+ lp_wait(minor);
+
/* control port takes strobe high */
- w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-#ifndef __sparc__
- while (wait) /* FIXME: should be a udelay() */
- wait--;
-#else
- udelay(1);
-#endif
- /* take strobe low */
if (LP_POLLED(minor))
- /* take strobe low */
- w_ctr(minor, LP_PSELECP | LP_PINITP);
- else
{
- lp_table[minor].irq_detected = 0;
- lp_table[minor].irq_missed = 0;
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
+ lp_wait(minor);
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ } else {
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN);
+ lp_wait(minor);
w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
}
@@ -240,7+293,8 @@ static inline int lp_char(char lpchar, int minor) /* update waittime statistics */
if (count > stats->maxwait) {
#ifdef LP_DEBUG
- printk(KERN_DEBUG "lp%d success after %d counts.\n", minor, count);
+ printk(KERN_DEBUG "lp%d success after %d counts.\n",
+ minor, count);
#endif
stats->maxwait = count;
}
@@ -325,8+379,12 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count) lp_table[minor].last_error = 0;
lp_table[minor].irq_detected = 0;
lp_table[minor].irq_missed = 1;
+ LP_POLLED(minor) = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
- w_ctr(minor, LP_PSELECP | LP_PINITP);
+ if (LP_POLLED(minor))
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ else
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
do {
bytes_written = 0;
@@ -649,14+707,6 @@ static int lp_ioctl(struct inode *inode, struct file *file, else
LP_F(minor) &= ~LP_ABORTOPEN;
break;
-#ifdef LP_NEED_CAREFUL
- case LPCAREFUL:
- if (arg)
- LP_F(minor) |= LP_CAREFUL;
- else
- LP_F(minor) &= ~LP_CAREFUL;
- break;
-#endif
case LPWAIT:
LP_WAIT(minor) = arg;
break;
@@ -35,6+35,9 @@ void soundcard_init(void); void dmasound_init(void);
#endif
#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
#ifdef CONFIG_ISDN
int isdn_init(void);
#endif
@@ -571,6+574,9 @@ __initfunc(int chr_dev_init(void)) dmasound_init();
#endif
#endif
+#ifdef CONFIG_SPARCAUDIO
+ sparcaudio_init();
+#endif
#ifdef CONFIG_JOYSTICK
/*
* Some joysticks only appear when the sound card they are
@@ -43,7+43,7 @@ static int users = 0; * 92.7400017 -> 92.75
*/
#define RSF16_ENCODE(x) ((x)/800+214)
-#define RSF16_MINFREQ 88*16000
+#define RSF16_MINFREQ 87*16000
#define RSF16_MAXFREQ 108*16000
static void outbits(int bits, unsigned int data, int port)
@@ -64,27+64,32 @@ static void outbits(int bits, unsigned int data, int port) }
}
-static void fmi_mute(int port)
+static inline void fmi_mute(int port)
{
outb(0x00, port);
}
-static void fmi_unmute(int port)
+static inline void fmi_unmute(int port)
{
outb(0x08, port);
}
-static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
{
int myport = dev->port;
outbits(16, RSF16_ENCODE(freq), myport);
outbits(8, 0xC0, myport);
- /* we should wait here... */
+ /* it is better than udelay(140000), isn't it? */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/7;
+ schedule();
+ /* ignore signals, we really should restore volume */
+ if (dev->curvol) fmi_unmute(myport);
return 0;
}
-static int fmi_getsigstr(struct fmi_device *dev)
+static inline int fmi_getsigstr(struct fmi_device *dev)
{
int val;
int res;
@@ -93,10+98,17 @@ static int fmi_getsigstr(struct fmi_device *dev) val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
outb(val | 0x10, myport);
- udelay(140000);
+ /* it is better than udelay(140000), isn't it? */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/7;
+ schedule();
+ /* do not do it..., 140ms is very looong time to get signal in real program
+ if (signal_pending(current))
+ return -EINTR;
+ */
res = (int)inb(myport+1);
outb(val, myport);
- return (res & 2) ? 0 : 1;
+ return (res & 2) ? 0 : 0xFFFF;
}
static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -136,7+148,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.rangehigh = RSF16_MAXFREQ/mult;
v.flags=fmi->flags;
v.mode=VIDEO_MODE_AUTO;
- v.signal=0xFFFF*fmi_getsigstr(fmi);
+ v.signal = fmi_getsigstr(fmi);
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
return 0;
#include <asm/io.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/feature.h>
#include "bmac.h"
#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
/* switch to use multicast code lifted from sunhme driver */
#define SUNHME_MULTICAST
-/* a bunch of constants for the "Heathrow" interrupt controller.
- These really should be in an include file somewhere */
-#define IoBaseHeathrow ((unsigned *)0xf3000000)
-#define HeathrowFCR 0x0038 /* FCR offset from Heathrow Base Address */
-#define fcrEnetEnabledBits 0x60000000 /* mask to enable Enet Xcvr/Controller */
-#define fcrResetEnetCell 0x80000000 /* mask used to reset Enet cell */
-#define fcrClearResetEnetCell 0x7fffffff /* mask used to clear reset Enet cell */
-#define fcrDisableEnet 0x1fffffff /* mask to disable Enet Xcvr/Controller */
-
#define N_RX_RING 64
#define N_TX_RING 32
#define MAX_TX_ACTIVE 1
@@ -122,6+114,7 @@ bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = { };
struct device *bmac_devs = NULL;
+static int is_bmac_plus;
#if 0
/*
@@ -157,8+150,6 @@ static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
static void bmac_set_timeout(struct device *dev);
static void bmac_tx_timeout(unsigned long data);
-static void bmac_reset_chip(struct device *dev);
-static void bmac_init_registers(struct device *dev);
static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy);
static int bmac_output(struct sk_buff *skb, struct device *dev);
static void bmac_start(struct device *dev);
@@ -240,34+231,86 @@ bmac_reset_chip(struct device *dev) struct bmac_data *bp = (struct bmac_data *) dev->priv;
volatile struct dbdma_regs *rd = bp->rx_dma;
volatile struct dbdma_regs *td = bp->tx_dma;
- volatile unsigned *heathrowFCR;
- unsigned int fcrValue;
dbdma_reset(rd);
dbdma_reset(td);
- heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR);
+ feature_set(FEATURE_BMac_IO_enable);
+ udelay(10000);
+ feature_set(FEATURE_BMac_reset);
+ udelay(10000);
+ feature_clear(FEATURE_BMac_reset);
+ udelay(10000);
+}
- fcrValue = in_le32(heathrowFCR);
+#define MIFDELAY udelay(500)
- fcrValue &= fcrDisableEnet; /* clear out Xvr and Controller Bit */
- out_le32(heathrowFCR, fcrValue);
- udelay(50000);
+static unsigned int
+bmac_mif_readbits(struct device *dev, int nb)
+{
+ unsigned int val = 0;
+
+ while (--nb >= 0) {
+ bmwrite(dev, MIFCSR, 0);
+ MIFDELAY;
+ if (bmread(dev, MIFCSR) & 8)
+ val |= 1 << nb;
+ bmwrite(dev, MIFCSR, 1);
+ MIFDELAY;
+ }
+ bmwrite(dev, MIFCSR, 0);
+ MIFDELAY;
+ bmwrite(dev, MIFCSR, 1);
+ MIFDELAY;
+ return val;
+}
- fcrValue |= fcrResetEnetCell; /* set bit to reset them */
- out_le32(heathrowFCR, fcrValue);
- udelay(50000);
-
- fcrValue &= fcrDisableEnet;
- out_le32(heathrowFCR, fcrValue);
- udelay(50000);
+static void
+bmac_mif_writebits(struct device *dev, unsigned int val, int nb)
+{
+ int b;
+
+ while (--nb >= 0) {
+ b = (val & (1 << nb))? 6: 4;
+ bmwrite(dev, MIFCSR, b);
+ MIFDELAY;
+ bmwrite(dev, MIFCSR, b|1);
+ MIFDELAY;
+ }
+}
- fcrValue |= fcrEnetEnabledBits;
- out_le32(heathrowFCR, fcrValue);
- udelay(50000);
-
- out_le32(heathrowFCR, fcrValue);
- udelay(50000);
+static unsigned int
+bmac_mif_read(struct device *dev, unsigned int addr)
+{
+ unsigned int val;
+
+ bmwrite(dev, MIFCSR, 4);
+ MIFDELAY;
+ bmac_mif_writebits(dev, ~0U, 32);
+ bmac_mif_writebits(dev, 6, 4);
+ bmac_mif_writebits(dev, addr, 10);
+ bmwrite(dev, MIFCSR, 2);
+ MIFDELAY;
+ bmwrite(dev, MIFCSR, 1);
+ MIFDELAY;
+ val = bmac_mif_readbits(dev, 17);
+ bmwrite(dev, MIFCSR, 4);
+ MIFDELAY;
+ printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val);
+ return val;
+}
+
+static void
+bmac_mif_write(struct device *dev, unsigned int addr, unsigned int val)
+{
+ bmwrite(dev, MIFCSR, 4);
+ MIFDELAY;
+ bmac_mif_writebits(dev, ~0U, 32);
+ bmac_mif_writebits(dev, 5, 4);
+ bmac_mif_writebits(dev, addr, 10);
+ bmac_mif_writebits(dev, 2, 2);
+ bmac_mif_writebits(dev, val, 16);
+ bmac_mif_writebits(dev, 3, 2);
}
static void
@@ -280,14+323,23 @@ bmac_init_registers(struct device *dev)
/* XXDEBUG(("bmac: enter init_registers\n")); */
+ bmwrite(dev, RXRST, RxResetValue);
bmwrite(dev, TXRST, TxResetBit);
+ i = 100;
do {
+ --i;
+ udelay(10000);
regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */
- } while (regValue & TxResetBit);
+ } while ((regValue & TxResetBit) && i > 0);
+
+ if (!is_bmac_plus) {
+ regValue = bmread(dev, XCVRIF);
+ regValue |= ClkBit | SerialMode | COLActiveLow;
+ bmwrite(dev, XCVRIF, regValue);
+ udelay(10000);
+ }
- bmwrite(dev, RXRST, RxResetValue);
- bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow);
bmwrite(dev, RSEED, (unsigned short)0x1968);
regValue = bmread(dev, XIFC);
@@ -366,18+418,30 @@ bmac_start_chip(struct device *dev)
/* enable rx dma channel */
dbdma_continue(rd);
+
+ oldConfig = bmread(dev, TXCFG);
+ bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
/* turn on rx plus any other bits already on (promiscuous possibly) */
oldConfig = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
-
- oldConfig = bmread(dev, TXCFG);
- bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
+ udelay(20000);
}
static int
bmac_init_chip(struct device *dev)
{
+ if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) {
+ if (bmac_mif_read(dev, 4) == 0xa1) {
+ bmac_mif_write(dev, 0, 0x1000);
+ } else {
+ bmac_mif_write(dev, 4, 0xa1);
+ bmac_mif_write(dev, 0, 0x1200);
+ }
+ /* XXX debugging */
+ bmac_mif_read(dev, 0);
+ bmac_mif_read(dev, 4);
+ }
bmac_init_registers(dev);
return 1;
}
@@ -1144,8+1208,16 @@ bmac_probe(struct device *dev) unsigned char *addr;
static struct device_node *all_bmacs = NULL, *next_bmac;
- if (all_bmacs == NULL)
- all_bmacs = next_bmac = find_devices("bmac");
+ if (all_bmacs == NULL) {
+ all_bmacs = find_devices("bmac");
+ is_bmac_plus = 0;
+ if (all_bmacs == NULL) {
+ all_bmacs = find_compatible_devices("network", "bmac+");
+ if (all_bmacs)
+ is_bmac_plus = 1;
+ }
+ next_bmac = all_bmacs;
+ }
bmacs = next_bmac;
if (bmacs == NULL) return -ENODEV;
next_bmac = bmacs->next;
@@ -1157,7+1229,7 @@ bmac_probe(struct device *dev) bmacs->full_name);
return -EINVAL;
}
-
+
if (dev == NULL) {
dev = init_etherdev(NULL, PRIV_BYTES);
bmac_devs = dev; /*KLUDGE!!*/
-/* $Id: pcikbd.c,v 1.22 1998/09/21 05:06:45 jj Exp $
+/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
#else
#define PCI_KB_NAME "keyboard"
#define PCI_MS_NAME "mouse"
-/*
- * XXX.
- * Gleb defines check_region and request_region here.
- * This looks suspicios because he neglects to call
- * sparc_alloc_io, but the conflict with sparc_alloc_io is what
- * causes problems.
- */
#endif
#include "pcikbd.h"
@@ -517,7+510,7 @@ __initfunc(void pcikbd_init_hw(void)) for_each_ebusdev(edev, ebus) {
if(!strcmp(edev->prom_name, "8042")) {
for_each_edevchild(edev, child) {
- if (!strcmp(child->prom_name, "kb_ps2"))
+ if (!strcmp(child->prom_name, PCI_KB_NAME))
goto found;
}
}
-/* $Id: sab82532.c,v 1.23 1998/09/16 03:20:25 ecd Exp $
+/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -88,6+88,7 @@ static char *sab82532_version[16] = { "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)",
"V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)"
};
+static char serial_version[16];
/*
* tmp_buf is used as a temporary buffer by sab82532_write. We need to
@@ -505,7+506,7 @@ check_modem: #endif
}
if ((info->regs->r.pvr & info->pvr_dsr_bit) ^ info->dsr) {
- info->dsr = info->regs->r.pvr & info->pvr_dsr_bit;
+ info->dsr = (info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : 1;
info->icount.dsr++;
modem_change++;
#if 0
@@ -786,6+787,12 @@ static int startup(struct sab82532 *info) */
sab82532_init_line(info);
+ if (info->tty->termios->c_cflag & CBAUD) {
+ info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
+ info->regs->rw.mode |= SAB82532_MODE_RTS;
+ info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
+ }
+
/*
* Finally, enable interrupts
*/
@@ -951,8+958,9 @@ static void change_speed(struct sab82532 *info) ebrg = ebrg_table[i].n;
ebrg |= (ebrg_table[i].m << 6);
- if (ebrg_table[i].baud)
- info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+ info->baud = ebrg_table[i].baud;
+ if (info->baud)
+ info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
else
info->timeout = 0;
info->timeout += HZ / 50; /* Add .02 seconds of slop */
@@ -1278,7+1286,9 @@ static int get_modem_info(struct sab82532 * info, unsigned int *value) {
unsigned int result;
- result = ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+ result = ((info->regs->r.mode & SAB82532_MODE_RTS) ?
+ ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS)
+ : TIOCM_RTS)
| ((info->regs->r.pvr & info->pvr_dtr_bit) ? 0 : TIOCM_DTR)
| ((info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR)
| ((info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : TIOCM_DSR)
@@ -1952,9+1962,11 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) * /proc fs routines....
*/
-static int inline line_info(char *buf, struct tty_struct *tty)
+static __inline__ int
+line_info(char *buf, struct sab82532 *info)
{
- struct sab82532 *info = (struct sab82532 *)tty->driver_data;
+ unsigned long flags;
+ char stat_buf[30];
int ret;
ret = sprintf(buf, "%d: uart:SAB82532 ", info->line);
@@ -1972,8+1984,8 @@ static int inline line_info(char *buf, struct tty_struct *tty) ret += sprintf(buf+ret, "V?.? ");
break;
}
- ret += sprintf(buf+ret, "port:%lX irq:%d",
- (unsigned long)info->regs, info->irq);
+ ret += sprintf(buf+ret, "port:%lX irq:%s",
+ (unsigned long)info->regs, __irq_itoa(info->irq));
if (!info->regs) {
ret += sprintf(buf+ret, "\n");
@@ -1983,20+1995,57 @@ static int inline line_info(char *buf, struct tty_struct *tty) /*
* Figure out the current RS-232 lines
*/
+ stat_buf[0] = 0;
+ stat_buf[1] = 0;
+ save_flags(flags); cli();
+ if (info->regs->r.mode & SAB82532_MODE_RTS) {
+ if (!(info->regs->r.mode & SAB82532_MODE_FRTS))
+ strcat(stat_buf, "|RTS");
+ } else {
+ strcat(stat_buf, "|RTS");
+ }
+ if (info->regs->r.star & SAB82532_STAR_CTS)
+ strcat(stat_buf, "|CTS");
+ if (!(info->regs->r.pvr & info->pvr_dtr_bit))
+ strcat(stat_buf, "|DTR");
+ if (!(info->regs->r.pvr & info->pvr_dsr_bit))
+ strcat(stat_buf, "|DSR");
+ if (!(info->regs->r.vstr & SAB82532_VSTR_CD))
+ strcat(stat_buf, "|CD");
+ restore_flags(flags);
+
+ if (info->baud)
+ ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+ if (info->icount.frame)
+ ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+
+ if (info->icount.parity)
+ ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
- ret += sprintf(buf+ret, "\n");
+ if (info->icount.brk)
+ ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+
+ if (info->icount.overrun)
+ ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+ /*
+ * Last thing is the RS-232 status lines.
+ */
+ ret += sprintf(buf+ret, " %s\n", stat_buf + 1);
return ret;
}
int sab82532_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
- int i, len = 0;
- off_t begin = 0;
+ struct sab82532 *info = sab82532_chain;
+ off_t begin = 0;
+ int len = 0;
- len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.23 $");
- for (i = 0; i < NR_PORTS && len < 4000; i++) {
- len += line_info(page + len, sab82532_table[i]);
+ len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+ for (info = sab82532_chain; info && len < 4000; info = info->next) {
+ len += line_info(page + len, info);
if (len+begin > off+count)
goto done;
if (len+begin < off) {
@@ -2089,13+2138,14 @@ sab82532_kgdb_hook(int line))
__initfunc(static inline void show_serial_version(void))
{
- char *revision = "$Revision: 1.23 $";
+ char *revision = "$Revision: 1.26 $";
char *version, *p;
version = strchr(revision, ' ');
- p = strchr(++version, ' ');
+ strcpy(serial_version, ++version);
+ p = strchr(serial_version, ' ');
*p = '\0';
- printk("SAB82532 serial driver version %s\n", version);
+ printk("SAB82532 serial driver version %s\n", serial_version);
}
/*
@@ -2456,8+2506,9 @@ sab82532_console_setup(struct console *con, char *options) ebrg = ebrg_table[i].n;
ebrg |= (ebrg_table[i].m << 6);
- if (ebrg_table[i].baud)
- info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud;
+ info->baud = ebrg_table[i].baud;
+ if (info->baud)
+ info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
else
info->timeout = 0;
info->timeout += HZ / 50; /* Add .02 seconds of slop */
@@ -2490,6+2541,7 @@ sab82532_console_setup(struct console *con, char *options) info->regs->rw.mode &= ~(SAB82532_MODE_FRTS);
info->regs->rw.mode |= SAB82532_MODE_FCTS;
}
+ info->regs->rw.pvr &= ~(info->pvr_dtr_bit);
info->regs->rw.mode |= SAB82532_MODE_RAC;
restore_flags(flags);
-/* $Id: su32.c,v 1.1 1998/09/18 10:45:32 jj Exp $
+/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
#define CONFIG_SERIAL_NOPAUSE_IO /* Unused on sparc */
#define SERIAL_DO_RESTART
-#if 1
-/* Normally these defines are controlled by the autoconf.h */
-
-#undef CONFIG_SERIAL_MANY_PORTS
-#define CONFIG_SERIAL_SHARE_IRQ /* Must be enabled for MrCoffee. */
-#undef CONFIG_SERIAL_DETECT_IRQ /* code is removed from su.c */
-#undef CONFIG_SERIAL_MULTIPORT
-#endif
-
-/* Sanity checks */
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-#ifndef CONFIG_SERIAL_SHARE_IRQ
-#define CONFIG_SERIAL_SHARE_IRQ
-#endif
-#endif
-
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
#undef SERIAL_DEBUG_THROTTLE
-/* */
-
-#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
-#ifdef __sparc_v9__
-#define IRQ_4M(n) (n)
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-#else
-/* 0x20 is sun4m thing, Dave Redman heritage. See arch/sparc/kernel/irq.c. */
+/*
+ * 0x20 is sun4m thing, Dave Redman heritage.
+ * See arch/sparc/kernel/irq.c.
+ */
#define IRQ_4M(n) ((n)|0x20)
-/* Interrupts must be shared on MrCoffee. */
-#define IRQ_T(info) SA_SHIRQ
-#endif
-#define SERIAL_INLINE
-
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#define DBG_CNT(s) \
+do { \
+ printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount, \
+ info->count,tty->count,s); \
+} while (0);
#else
#define DBG_CNT(s)
#endif
/*
* End of serial driver configuration section.
*/
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#if 0 /* P3: Needed if we to support /sbin/setserial. */
-#include <asm/serial.h>
-#endif
#include "sunserial.h"
#include "sunkbd.h"
@@ -128,24+101,22 @@ struct su_struct { int magic;
unsigned long port;
int baud_base;
- int type; /* Hardware type: e.g. 16550 */
+ int type; /* Hardware type: e.g. 16550 */
int irq;
int flags;
int line;
int cflag;
- /* XXX Unify. */
int kbd_node;
int ms_node;
int port_node;
char name[16];
- int xmit_fifo_size;
- int custom_divisor;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
+ int xmit_fifo_size;
+ int custom_divisor;
+ unsigned short close_delay;
+ unsigned short closing_wait; /* time to wait before closing */
struct tty_struct *tty;
int read_status_mask;
@@ -168,30+139,14 @@ struct su_struct { struct wait_queue *close_wait;
struct wait_queue *delta_msr_wait;
- struct su_struct *next_port;
- struct su_struct *prev_port;
-
int count;
struct async_icount icount;
struct termios normal_termios, callout_termios;
unsigned long last_active; /* For async_struct, to be */
};
-#if 0 /* P3: became unused after surgery. */
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-#endif
-
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#endif
-
-static char *serial_name = "Serial driver";
-static char *serial_version = "4.25.s1";
+static char *serial_name = "PCIO serial driver";
+static char *serial_version = "1.1";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -201,16+156,6 @@ static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
-/*
- * IRQ_timeout - How long the timeout should be for each IRQ
- * should be after the IRQ has been active.
- */
-static struct su_struct *IRQ_ports[NR_IRQS];
-#ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[NR_IRQS];
-#endif
-static int IRQ_timeout[NR_IRQS];
-
static void autoconfig(struct su_struct *info);
static void change_speed(struct su_struct *info);
static void su_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -317,8+262,8 @@ su_outb(struct su_struct *info, unsigned long offset, int value)
#endif
-#define serial_in(info, off) su_inb(info, off)
-#define serial_inp(info, off) su_inb(info, off)
+#define serial_in(info, off) su_inb(info, off)
+#define serial_inp(info, off) su_inb(info, off)
#define serial_out(info, off, val) su_outb(info, off, val)
#define serial_outp(info, off, val) su_outb(info, off, val)
@@ -387,22+332,20 @@ static void su_start(struct tty_struct *tty) * This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
-static _INLINE_ void su_sched_event(struct su_struct *info, int event)
+static __inline__ void
+su_sched_event(struct su_struct *info, int event)
{
info->event |= 1 << event;
queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
-static _INLINE_ void receive_chars(struct su_struct *info, int *status,
- struct pt_regs *regs)
+static __inline__ void
+receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs)
{
- struct tty_struct *tty = info->tty;
+ unsigned char status = 0;
unsigned char ch;
- int ignored = 0;
- struct async_icount *icount;
- icount = &info->icount;
do {
ch = serial_inp(info, UART_RX);
if (info->kbd_node) {
@@ -427,6+370,23 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status, } else {
sun_mouse_inbyte(ch);
}
+
+ status = su_inb(info, UART_LSR);
+ } while (status & UART_LSR_DR);
+}
+
+static __inline__ void
+receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch;
+ int ignored = 0;
+ struct async_icount *icount;
+
+ icount = &info->icount;
+ do {
+ ch = serial_inp(info, UART_RX);
+
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
break;
*tty->flip.char_buf_ptr = ch;
@@ -455,7+415,7 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status, * Now check to see if character should be
* ignored, and mask off conditions which
* should be ignored.
- */
+ */
if (*status & info->ignore_status_mask) {
if (++ignored > 100)
break;
@@ -497,7+457,8 @@ static _INLINE_ void receive_chars(struct su_struct *info, int *status, tty_flip_buffer_push(tty);
}
-static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done)
+static __inline__ void
+transmit_chars(struct su_struct *info, int *intr_done)
{
int count;
@@ -540,7+501,8 @@ static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done) }
}
-static _INLINE_ void check_modem_status(struct su_struct *info)
+static __inline__ void
+check_modem_status(struct su_struct *info)
{
int status;
struct async_icount *icount;
@@ -607,222+569,79 @@ static _INLINE_ void check_modem_status(struct su_struct *info) }
}
}
-
-#ifdef CONFIG_SERIAL_SHARE_IRQ
+
/*
- * This is the serial driver's generic interrupt routine
- */
-static void su_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+ * This is the kbd/mouse serial driver's interrupt routine
+ */
+static void
+su_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
- int status;
- struct su_struct *info;
- int pass_counter = 0;
- struct su_struct *end_mark = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
- int first_multi = 0;
- struct su_multiport_struct *multi;
-#endif
+ struct su_struct *info = (struct su_struct *)dev_id;
+ unsigned char status;
#ifdef SERIAL_DEBUG_INTR
printk("su_interrupt(%s)...", __irq_itoa(irq));
#endif
-
- info = IRQ_ports[irq];
if (!info)
return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT
- multi = &rs_multiport[irq];
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-#endif
- do {
- if (!info->tty ||
- (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
- if (!end_mark)
- end_mark = info;
- goto next;
- }
- end_mark = 0;
+ if (serial_in(info, UART_IIR) & UART_IIR_NO_INT)
+ return;
- info->last_active = jiffies;
-
- status = serial_inp(info, UART_LSR);
+ status = serial_inp(info, UART_LSR);
#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
+ printk("status = %x...", status);
#endif
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
- if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
+ if (status & UART_LSR_DR)
+ receive_kbd_ms_chars(info, regs);
- next:
- info = info->next_port;
- if (!info) {
- info = IRQ_ports[irq];
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 0
- printk("rs loop break\n");
-#endif
- break; /* Prevent infinite loops */
- }
- continue;
- }
- } while (end_mark != info);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (multi->port_monitor)
- printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
- info->irq, first_multi,
- inb(multi->port_monitor));
-#endif
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
-#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
-
/*
- * This is the serial driver's interrupt routine for a single port
+ * This is the serial driver's generic interrupt routine
*/
-static void su_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+static void
+su_serial_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
int status;
+ struct su_struct *info;
int pass_counter = 0;
- struct su_struct * info;
-#ifdef CONFIG_SERIAL_MULTIPORT
- int first_multi = 0;
- struct rs_multiport_struct *multi;
-#endif
#ifdef SERIAL_DEBUG_INTR
- printk("su_interrupt_single(%d) int=%x ...", irq,
- serial_inp(&su_table[0], UART_IIR));
+ printk("su_interrupt(%s)...", __irq_itoa(irq));
#endif
-
- info = IRQ_ports[irq];
+ info = (struct su_struct *)dev_id;
if (!info || !info->tty)
return;
-
-#ifdef CONFIG_SERIAL_MULTIPORT
- multi = &rs_multiport[irq];
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-#endif
-
+
do {
status = serial_inp(info, UART_LSR);
#ifdef SERIAL_DEBUG_INTR
printk("status = %x...", status);
#endif
if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
+ receive_serial_chars(info, &status, regs);
check_modem_status(info);
if (status & UART_LSR_THRE)
transmit_chars(info, 0);
+
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
#if 0
- printk("su_single loop break.\n");
+ printk("rs loop break\n");
#endif
- break;
+ break; /* Prevent infinite loops */
}
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
- info->last_active = jiffies;
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (multi->port_monitor)
- printk("rs port monitor (single) irq %s: 0x%x, 0x%x\n",
- __irq_itoa(info->irq), first_multi,
- inb(multi->port_monitor));
-#endif
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-
-#ifdef CONFIG_SERIAL_MULTIPORT
-/*
- * This is the serial driver's for multiport boards
- */
-static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
-{
- int status;
- struct su_struct * info;
- int pass_counter = 0;
- int first_multi= 0;
- struct rs_multiport_struct *multi;
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_multi(%d)...", irq);
-#endif
-
- info = IRQ_ports[irq];
- if (!info)
- return;
- multi = &rs_multiport[irq];
- if (!multi->port1) {
- /* Should never happen */
- printk("rs_interrupt_multi: NULL port1!\n");
- return;
- }
- if (multi->port_monitor)
- first_multi = inb(multi->port_monitor);
-
- while (1) {
- if (!info->tty ||
- (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
- goto next;
- info->last_active = jiffies;
-
- status = serial_inp(info, UART_LSR);
-#ifdef SERIAL_DEBUG_INTR
- printk("status = %x...", status);
-#endif
- if (status & UART_LSR_DR)
- receive_chars(info, &status, regs);
- check_modem_status(info);
- if (status & UART_LSR_THRE)
- transmit_chars(info, 0);
-
- next:
- info = info->next_port;
- if (info)
- continue;
+ info->last_active = jiffies;
- info = IRQ_ports[irq];
- if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 1
- printk("rs_multi loop break\n");
-#endif
- break; /* Prevent infinite loops */
- }
- if (multi->port_monitor)
- printk("rs port monitor irq %d: 0x%x, 0x%x\n",
- info->irq, first_multi,
- inb(multi->port_monitor));
- if ((inb(multi->port1) & multi->mask1) != multi->match1)
- continue;
- if (!multi->port2)
- break;
- if ((inb(multi->port2) & multi->mask2) != multi->match2)
- continue;
- if (!multi->port3)
- break;
- if ((inb(multi->port3) & multi->mask3) != multi->match3)
- continue;
- if (!multi->port4)
- break;
- if ((inb(multi->port4) & multi->mask4) == multi->match4)
- continue;
- break;
- }
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
-#endif
/*
* -------------------------------------------------------------------
@@ -839,12+658,14 @@ static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) * interrupt driver proper are done; the interrupt driver schedules
* them using su_sched_event(), and they get done here.
*/
-static void do_serial_bh(void)
+static void
+do_serial_bh(void)
{
run_task_queue(&tq_serial);
}
-static void do_softint(void *private_)
+static void
+do_softint(void *private_)
{
struct su_struct *info = (struct su_struct *) private_;
struct tty_struct *tty;
@@ -862,62+683,6 @@ static void do_softint(void *private_) }
/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * by the serial driver to handle ports that do not have an interrupt
- * (irq=0). This doesn't work very well for 16450's, but gives barely
- * passable results for a 16550A. (Although at the expense of much
- * CPU overhead).
- */
-static void su_timer(void)
-{
- static unsigned long last_strobe = 0;
- struct su_struct *info;
- unsigned int i;
-
- if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
- for (i=1; i < NR_IRQS; i++) {
- info = IRQ_ports[i];
- if (!info)
- continue;
- cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- if (info->next_port) {
- do {
- serial_out(info, UART_IER, 0);
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- info = info->next_port;
- } while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (rs_multiport[i].port1)
- rs_interrupt_multi(i, NULL, NULL);
- else
-#endif
- su_interrupt(i, NULL, NULL);
- } else
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
- su_interrupt_single(i, NULL, NULL);
- sti();
- }
- }
- last_strobe = jiffies;
- timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
- timer_active |= 1 << RS_TIMER;
-
- if (IRQ_ports[0]) {
- cli();
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- su_interrupt(0, NULL, NULL);
-#else
- su_interrupt_single(0, NULL, NULL);
-#endif
- sti();
-
- timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
- }
-}
-
-/*
* ---------------------------------------------------------------
* Low level utility subroutines for the serial driver: routines to
* figure out the appropriate timeout for an interrupt chain, routines
@@ -926,62+691,41 @@ static void su_timer(void) * ---------------------------------------------------------------
*/
-/*
- * This routine figures out the correct timeout for a particular IRQ.
- * It uses the smallest timeout of all of the serial ports in a
- * particular interrupt chain. Now only used for IRQ 0....
- */
-static void figure_IRQ_timeout(int irq)
-{
- struct su_struct *info;
- int timeout = 60*HZ; /* 60 seconds === a long time :-) */
-
- info = IRQ_ports[irq];
- if (!info) {
- IRQ_timeout[irq] = 60*HZ;
- return;
- }
- while (info) {
- if (info->timeout < timeout)
- timeout = info->timeout;
- info = info->next_port;
- }
- if (!irq)
- timeout = timeout / 2;
- IRQ_timeout[irq] = timeout ? timeout : 1;
-}
-
-static int startup(struct su_struct *info)
+static int
+startup(struct su_struct *info)
{
unsigned long flags;
int retval=0;
- void (*handler)(int, void *, struct pt_regs *);
unsigned long page;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- unsigned short ICP;
-#endif
- page = get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ save_flags(flags);
+ if (info->tty) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
- save_flags(flags); cli();
+ cli();
- if (info->flags & ASYNC_INITIALIZED) {
- free_page(page);
- goto errout;
- }
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
- if (info->port == 0 || info->type == PORT_UNKNOWN) {
- if (info->tty)
+ if (info->port == 0 || info->type == PORT_UNKNOWN) {
set_bit(TTY_IO_ERROR, &info->tty->flags);
- free_page(page);
- goto errout;
+ free_page(page);
+ goto errout;
+ }
+ if (info->xmit_buf)
+ free_page(page);
+ else
+ info->xmit_buf = (unsigned char *) page;
}
- if (info->xmit_buf)
- free_page(page);
- else
- info->xmit_buf = (unsigned char *) page;
+ cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
if (uart_config[info->type].flags & UART_STARTECH) {
/* Wake up UART */
@@ -1022,51+766,25 @@ static int startup(struct su_struct *info) /*
* Allocate the IRQ if necessary
*/
- if (info->irq && (!IRQ_ports[info->irq] ||
- !IRQ_ports[info->irq]->next_port)) {
- if (IRQ_ports[info->irq]) {
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- free_irq(IRQ_4M(info->irq), info);
-#ifdef CONFIG_SERIAL_MULTIPORT
- if (rs_multiport[info->irq].port1)
- handler = rs_interrupt_multi;
- else
-#endif
- handler = su_interrupt;
-#else
- retval = -EBUSY;
- goto errout;
-#endif /* CONFIG_SERIAL_SHARE_IRQ */
- } else
- handler = su_interrupt_single;
-
- retval = request_irq(IRQ_4M(info->irq), handler, IRQ_T(info),
- "serial", info);
- if (retval) {
- if (capable(CAP_SYS_ADMIN)) {
- if (info->tty)
- set_bit(TTY_IO_ERROR,
- &info->tty->flags);
- retval = 0;
- }
- goto errout;
+ if (info->kbd_node || info->ms_node) {
+ retval = request_irq(info->irq, su_kbd_ms_interrupt,
+ SA_SHIRQ, info->name, info);
+ } else {
+ retval = request_irq(info->irq, su_serial_interrupt,
+ SA_SHIRQ, info->name, info);
+ }
+ if (retval) {
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ retval = 0;
}
+ goto errout;
}
/*
- * Insert serial port into IRQ chain.
- */
- info->prev_port = 0;
- info->next_port = IRQ_ports[info->irq];
- if (info->next_port)
- info->next_port->prev_port = info;
- IRQ_ports[info->irq] = info;
- figure_IRQ_timeout(info->irq);
-
- /*
* Clear the interrupt registers.
*/
- /* (void) serial_inp(info, UART_LSR); */ /* (see above) */
(void) serial_inp(info, UART_RX);
(void) serial_inp(info, UART_IIR);
(void) serial_inp(info, UART_MSR);
@@ -1077,24+795,10 @@ static int startup(struct su_struct *info) serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
info->MCR = 0;
- if (info->tty->termios->c_cflag & CBAUD)
+ if (info->tty && info->tty->termios->c_cflag & CBAUD)
info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- if (info->irq == 0)
- info->MCR |= UART_MCR_OUT1;
- } else
-#endif
- {
- if (info->irq != 0)
- info->MCR |= UART_MCR_OUT2;
- }
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ if (info->irq != 0)
+ info->MCR |= UART_MCR_OUT2;
serial_outp(info, UART_MCR, info->MCR);
/*
@@ -1103,15+807,6 @@ static int startup(struct su_struct *info) info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
serial_outp(info, UART_IER, info->IER); /* enable interrupts */
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- /* Enable interrupts on the AST Fourport board */
- ICP = (info->port & 0xFE0) | 0x01F;
- outb_p(0x80, ICP);
- (void) inb_p(ICP);
- }
-#endif
-
/*
* And clear the interrupt registers again for luck.
*/
@@ -1125,12+820,6 @@ static int startup(struct su_struct *info) info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
- * Set up serial timers...
- */
- timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
- timer_active |= 1 << RS_TIMER;
-
- /*
* Set up the tty->alt_speed kludge
*/
if (info->tty) {
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct su_struct *info)
+static void
+shutdown(struct su_struct *info)
{
unsigned long flags;
- int retval;
if (!(info->flags & ASYNC_INITIALIZED))
return;
@@ -1179,32+868,9 @@ static void shutdown(struct su_struct *info) wake_up_interruptible(&info->delta_msr_wait);
/*
- * First unlink the serial port from the IRQ chain...
- */
- if (info->next_port)
- info->next_port->prev_port = info->prev_port;
- if (info->prev_port)
- info->prev_port->next_port = info->next_port;
- else
- IRQ_ports[info->irq] = info->next_port;
- figure_IRQ_timeout(info->irq);
-
- /*
* Free the IRQ, if necessary
*/
- if (info->irq && (!IRQ_ports[info->irq] ||
- !IRQ_ports[info->irq]->next_port)) {
- if (IRQ_ports[info->irq]) {
- free_irq(IRQ_4M(info->irq), info);
- retval = request_irq(IRQ_4M(info->irq),
- su_interrupt_single, IRQ_T(info), "serial", info);
-
- if (retval)
- printk("serial shutdown: request_irq: error %d"
- " Couldn't reacquire IRQ.\n", retval);
- } else
- free_irq(IRQ_4M(info->irq), info);
- }
+ free_irq(info->irq, info);
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
@@ -1213,20+879,7 @@ static void shutdown(struct su_struct *info)
info->IER = 0;
serial_outp(info, UART_IER, 0x00); /* disable all intrs */
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- /* reset interrupts on the AST Fourport board */
- (void) inb((info->port & 0xFE0) | 0x01F);
- info->MCR |= UART_MCR_OUT1;
- } else
-#endif
- info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
- /*
- * DEC did something gratutiously wrong....
- */
- info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+ info->MCR &= ~UART_MCR_OUT2;
/* disable break condition */
serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
@@ -1258,26+911,51 @@ static void shutdown(struct su_struct *info) restore_flags(flags);
}
+static __inline__ int
+su_get_baud_rate(struct su_struct *info)
+{
+ static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
+ };
+ int i;
+
+ if (info->tty)
+ return tty_get_baud_rate(info->tty);
+
+ i = info->cflag & CBAUD;
+ if (i & CBAUDEX) {
+ i &= ~(CBAUDEX);
+ if (i < 1 || i > 4)
+ info->cflag &= ~(CBAUDEX);
+ else
+ i += 15;
+ }
+ return baud_table[i];
+}
+
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void change_speed(struct su_struct *info)
+static void
+change_speed(struct su_struct *info)
{
- unsigned short port;
- int quot = 0, baud_base, baud;
- unsigned cflag, cval, fcr = 0;
- int bits;
- unsigned long flags;
+ int quot = 0, baud;
+ unsigned int cval, fcr = 0;
+ int bits;
+ unsigned long flags;
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
- if (!(port = info->port))
- return;
+ if (!info->kbd_node && !info->ms_node) {
+ if (!info->tty || !info->tty->termios)
+ return;
+ if (!info->port)
+ return;
+ info->cflag = info->tty->termios->c_cflag;
+ }
/* byte size and parity */
- switch (cflag & CSIZE) {
+ switch (info->cflag & CSIZE) {
case CS5: cval = 0x00; bits = 7; break;
case CS6: cval = 0x01; bits = 8; break;
case CS7: cval = 0x02; bits = 9; break;
@@ -1285,45+963,43 @@ static void change_speed(struct su_struct *info) /* Never happens, but GCC is too dumb to figure it out */
default: cval = 0x00; bits = 7; break;
}
- if (cflag & CSTOPB) {
+ if (info->cflag & CSTOPB) {
cval |= 0x04;
bits++;
}
- if (cflag & PARENB) {
+ if (info->cflag & PARENB) {
cval |= UART_LCR_PARITY;
bits++;
}
- if (!(cflag & PARODD))
+ if (!(info->cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
- if (cflag & CMSPAR)
+ if (info->cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/* Determine divisor based on baud rate */
- baud = tty_get_baud_rate(info->tty);
- baud_base = info->baud_base;
+ baud = su_get_baud_rate(info);
if (baud == 38400 &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->custom_divisor;
else {
if (baud == 134)
/* Special case since 134 is really 134.5 */
- quot = (2*baud_base / 269);
+ quot = (2 * info->baud_base / 269);
else if (baud)
- quot = baud_base / baud;
+ quot = info->baud_base / baud;
}
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
- quot = baud_base / 9600;
- info->quot = quot;
- info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+ quot = info->baud_base / 9600;
+ info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base);
info->timeout += HZ/50; /* Add .02 seconds of slop */
/* Set up FIFO's */
if (uart_config[info->type].flags & UART_USE_FIFO) {
- if ((info->baud_base / quot) < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+ if ((info->baud_base / quot) < 9600)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
}
@@ -1334,12+1010,12 @@ static void change_speed(struct su_struct *info) info->IER &= ~UART_IER_MSI;
if (info->flags & ASYNC_HARDPPS_CD)
info->IER |= UART_IER_MSI;
- if (cflag & CRTSCTS) {
+ if (info->cflag & CRTSCTS) {
info->flags |= ASYNC_CTS_FLOW;
info->IER |= UART_IER_MSI;
} else
info->flags &= ~ASYNC_CTS_FLOW;
- if (cflag & CLOCAL)
+ if (info->cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
else {
info->flags |= ASYNC_CHECK_CD;
@@ -1350,39+1026,43 @@ static void change_speed(struct su_struct *info) /*
* Set up parity check flag
*/
+ if (info->tty) {
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= UART_LSR_BI;
+ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE |
+ UART_LSR_DR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= UART_LSR_BI;
- /*
- * Characters to ignore
- */
- info->ignore_status_mask = 0;
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= UART_LSR_BI;
/*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
+ * Characters to ignore
*/
+ info->ignore_status_mask = 0;
if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= UART_LSR_OE;
+ info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignore parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= UART_LSR_OE;
+ }
+ /*
+ * !!! ignore all characters if CREAD is not set
+ */
+ if ((info->cflag & CREAD) == 0)
+ info->ignore_status_mask |= UART_LSR_DR;
}
- /*
- * !!! ignore all characters if CREAD is not set
- */
- if ((cflag & CREAD) == 0)
- info->ignore_status_mask |= UART_LSR_DR;
+
save_flags(flags); cli();
if (uart_config[info->type].flags & UART_STARTECH) {
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR,
- (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+ (info->cflag & CRTSCTS) ? UART_EFR_CTS : 0);
}
serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */
@@ -1396,7+1076,8 @@ static void change_speed(struct su_struct *info) info->quot = quot;
}
-static void su_put_char(struct tty_struct *tty, unsigned char ch)
+static void
+su_put_char(struct tty_struct *tty, unsigned char ch)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
unsigned long flags;
@@ -1421,18+1102,13 @@ static void su_put_char(struct tty_struct *tty, unsigned char ch)
static void su_put_char_kbd(unsigned char c)
{
- struct su_struct *info;
- int i;
+ struct su_struct *info = su_table;
int lsr;
- for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
- if (info->kbd_node != 0)
- break;
- }
- if (i >= NR_PORTS) {
- /* XXX P3: I would put a printk here but it may flood. */
+ if (!info->kbd_node)
+ ++info;
+ if (!info)
return;
- }
do {
lsr = serial_in(info, UART_LSR);
@@ -1442,14+1118,15 @@ static void su_put_char_kbd(unsigned char c) su_outb(info, UART_TX, c);
}
-static void su_change_mouse_baud(int baud)
+static void
+su_change_mouse_baud(int baud)
{
struct su_struct *info = su_table;
- int i;
- for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
- if (info->kbd_node != 0) break;
- if (i >= NR_PORTS) return;
+ if (!info->ms_node)
+ ++info;
+ if (!info)
+ return;
info->cflag &= ~(CBAUDEX | CBAUD);
switch(baud) {
@@ -1474,7+1151,8 @@ static void su_change_mouse_baud(int baud) change_speed(info);
}
-static void su_flush_chars(struct tty_struct *tty)
+static void
+su_flush_chars(struct tty_struct *tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
unsigned long flags;
@@ -1492,7+1170,8 @@ static void su_flush_chars(struct tty_struct *tty) restore_flags(flags);
}
-static int su_write(struct tty_struct * tty, int from_user,
+static int
+su_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
int c, ret = 0;
@@ -1562,7+1241,8 @@ static int su_write(struct tty_struct * tty, int from_user, return ret;
}
-static int su_write_room(struct tty_struct *tty)
+static int
+su_write_room(struct tty_struct *tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
int ret;
@@ -1575,7+1255,8 @@ static int su_write_room(struct tty_struct *tty) return ret;
}
-static int su_chars_in_buffer(struct tty_struct *tty)
+static int
+su_chars_in_buffer(struct tty_struct *tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
@@ -1584,7+1265,8 @@ static int su_chars_in_buffer(struct tty_struct *tty) return info->xmit_cnt;
}
-static void su_flush_buffer(struct tty_struct *tty)
+static void
+su_flush_buffer(struct tty_struct *tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
@@ -1603,7+1285,8 @@ static void su_flush_buffer(struct tty_struct *tty) * This function is used to send a high-priority XON/XOFF character to
* the device
*/
-static void su_send_xchar(struct tty_struct *tty, char ch)
+static void
+su_send_xchar(struct tty_struct *tty, char ch)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
@@ -1626,7+1309,8 @@ static void su_send_xchar(struct tty_struct *tty, char ch) * incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void su_throttle(struct tty_struct * tty)
+static void
+su_throttle(struct tty_struct * tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
@@ -1650,7+1334,8 @@ static void su_throttle(struct tty_struct * tty) sti();
}
-static void su_unthrottle(struct tty_struct * tty)
+static void
+su_unthrottle(struct tty_struct * tty)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
#ifdef SERIAL_DEBUG_THROTTLE
@@ -1682,139+1367,6 @@ static void su_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------
*/
-#if 0
-static int get_serial_info(struct su_struct * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.xmit_fifo_size = info->xmit_fifo_size;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_serial_info(struct su_struct * info,
- struct serial_struct * new_info)
-{
- struct serial_struct new_serial;
- struct serial_state old_state, *state;
- unsigned int i,change_irq,change_port;
- int retval = 0;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_state = *state;
-
- change_irq = new_serial.irq != state->irq;
- change_port = (new_serial.port != state->port);
-
- if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq || change_port ||
- (new_serial.baud_base != state->baud_base) ||
- (new_serial.type != state->type) ||
- (new_serial.close_delay != state->close_delay) ||
- (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
- ((new_serial.flags & ~ASYNC_USR_MASK) !=
- (state->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- state->flags = ((state->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- state->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- new_serial.irq = irq_cannonicalize(new_serial.irq);
-
- if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
- (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
- return -EINVAL;
- }
-
- /* Make sure address is not already in use */
- if (new_serial.type) {
- for (i = 0 ; i < NR_PORTS; i++)
- if ((state != &su_table[i]) &&
- (su_table[i].port == new_serial.port) &&
- su_table[i].type)
- return -EADDRINUSE;
- }
-
- if ((change_port || change_irq) && (state->count > 1))
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- state->baud_base = new_serial.baud_base;
- state->flags = ((state->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
- (info->flags & ASYNC_INTERNAL_FLAGS));
- state->custom_divisor = new_serial.custom_divisor;
- state->type = new_serial.type;
- state->close_delay = new_serial.close_delay * HZ/100;
- state->closing_wait = new_serial.closing_wait * HZ/100;
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->xmit_fifo_size = state->xmit_fifo_size =
- new_serial.xmit_fifo_size;
-
- release_region(state->port,8);
- if (change_port || change_irq) {
- /*
- * We need to shutdown the serial port at the old
- * port/irq combination.
- */
- shutdown(info);
- state->irq = new_serial.irq;
- info->port = state->port = new_serial.port;
- info->hub6 = state->hub6 = new_serial.hub6;
- }
- if (state->type != PORT_UNKNOWN)
- request_region(state->port,8,"serial(set)");
-
-check_and_exit:
- if (!state->port || !state->type)
- return 0;
- if (state->type != old_state.type)
- info->xmit_fifo_size = state->xmit_fifo_size =
- uart_config[state->type].dfl_xmit_fifo_size;
- if (state->flags & ASYNC_INITIALIZED) {
- if (((old_state.flags & ASYNC_SPD_MASK) !=
- (state->flags & ASYNC_SPD_MASK)) ||
- (old_state.custom_divisor != state->custom_divisor)) {
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- info->tty->alt_speed = 57600;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- info->tty->alt_speed = 115200;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
- info->tty->alt_speed = 230400;
- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
- info->tty->alt_speed = 460800;
- change_speed(info);
- }
- } else
- retval = startup(info);
- return retval;
-}
-#endif
-
-
/*
* get_lsr_info - get line status register info
*
@@ -1825,7+1377,8 @@ check_and_exit: * transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct su_struct * info, unsigned int *value)
+static int
+get_lsr_info(struct su_struct * info, unsigned int *value)
{
unsigned char status;
unsigned int result;
@@ -1838,7+1391,8 @@ static int get_lsr_info(struct su_struct * info, unsigned int *value) }
-static int get_modem_info(struct su_struct * info, unsigned int *value)
+static int
+get_modem_info(struct su_struct * info, unsigned int *value)
{
unsigned char control, status;
unsigned int result;
@@ -1860,8+1414,8 @@ static int get_modem_info(struct su_struct * info, unsigned int *value) return put_user(result,value);
}
-static int set_modem_info(struct su_struct * info, unsigned int cmd,
- unsigned int *value)
+static int
+set_modem_info(struct su_struct * info, unsigned int cmd, unsigned int *value)
{
int error;
unsigned int arg;
@@ -1917,34+1471,11 @@ static int set_modem_info(struct su_struct * info, unsigned int cmd, return 0;
}
-#if 0
-static int do_autoconfig(struct su_struct * info)
-{
- int retval;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (info->state->count > 1)
- return -EBUSY;
-
- shutdown(info);
-
- autoconfig(info->state);
- if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
- info->state->irq = detect_uart_irq(info->state);
-
- retval = startup(info);
- if (retval)
- return retval;
- return 0;
-}
-#endif
-
/*
* su_break() --- routine which turns the break handling on or off
*/
-static void su_break(struct tty_struct *tty, int break_state)
+static void
+su_break(struct tty_struct *tty, int break_state)
{
struct su_struct * info = (struct su_struct *)tty->driver_data;
unsigned long flags;
@@ -1964,122+1495,8 @@ static void su_break(struct tty_struct *tty, int break_state) restore_flags(flags);
}
-#ifdef CONFIG_SERIAL_MULTIPORT
-static int get_multiport_struct(struct su_struct * info,
- struct serial_multiport_struct *retinfo)
-{
- struct serial_multiport_struct ret;
- struct rs_multiport_struct *multi;
-
- multi = &rs_multiport[info->state->irq];
-
- ret.port_monitor = multi->port_monitor;
-
- ret.port1 = multi->port1;
- ret.mask1 = multi->mask1;
- ret.match1 = multi->match1;
-
- ret.port2 = multi->port2;
- ret.mask2 = multi->mask2;
- ret.match2 = multi->match2;
-
- ret.port3 = multi->port3;
- ret.mask3 = multi->mask3;
- ret.match3 = multi->match3;
-
- ret.port4 = multi->port4;
- ret.mask4 = multi->mask4;
- ret.match4 = multi->match4;
-
- ret.irq = info->state->irq;
-
- if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_multiport_struct(struct su_struct * info,
- struct serial_multiport_struct *in_multi)
-{
- struct serial_multiport_struct new_multi;
- struct rs_multiport_struct *multi;
- struct serial_state *state;
- int was_multi, now_multi;
- int retval;
- void (*handler)(int, void *, struct pt_regs *);
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- state = info->state;
-
- if (copy_from_user(&new_multi, in_multi,
- sizeof(struct serial_multiport_struct)))
- return -EFAULT;
-
- if (new_multi.irq != state->irq || state->irq == 0 ||
- !IRQ_ports[state->irq])
- return -EINVAL;
-
- multi = &rs_multiport[state->irq];
- was_multi = (multi->port1 != 0);
-
- multi->port_monitor = new_multi.port_monitor;
-
- if (multi->port1)
- release_region(multi->port1,1);
- multi->port1 = new_multi.port1;
- multi->mask1 = new_multi.mask1;
- multi->match1 = new_multi.match1;
- if (multi->port1)
- request_region(multi->port1,1,"serial(multiport1)");
-
- if (multi->port2)
- release_region(multi->port2,1);
- multi->port2 = new_multi.port2;
- multi->mask2 = new_multi.mask2;
- multi->match2 = new_multi.match2;
- if (multi->port2)
- request_region(multi->port2,1,"serial(multiport2)");
-
- if (multi->port3)
- release_region(multi->port3,1);
- multi->port3 = new_multi.port3;
- multi->mask3 = new_multi.mask3;
- multi->match3 = new_multi.match3;
- if (multi->port3)
- request_region(multi->port3,1,"serial(multiport3)");
-
- if (multi->port4)
- release_region(multi->port4,1);
- multi->port4 = new_multi.port4;
- multi->mask4 = new_multi.mask4;
- multi->match4 = new_multi.match4;
- if (multi->port4)
- request_region(multi->port4,1,"serial(multiport4)");
-
- now_multi = (multi->port1 != 0);
-
- if (IRQ_ports[state->irq]->next_port &&
- (was_multi != now_multi)) {
- free_irq(IRQ_4M(state->irq), info);
- if (now_multi)
- handler = rs_interrupt_multi;
- else
- handler = su_interrupt;
-
- retval = request_irq(IRQ_4M(state->irq), handler, IRQ_T(info),
- "serial", info);
- if (retval) {
- printk("Couldn't reallocate serial interrupt "
- "driver!!\n");
- }
- }
-
- return 0;
-}
-#endif
-
-static int su_ioctl(struct tty_struct *tty, struct file * file,
+static int
+su_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
int error;
@@ -2104,16+1521,6 @@ static int su_ioctl(struct tty_struct *tty, struct file * file, case TIOCMBIC:
case TIOCMSET:
return set_modem_info(info, cmd, (unsigned int *) arg);
-#if 0
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSERCONFIG:
- return do_autoconfig(info);
-#endif
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -2126,15+1533,6 @@ static int su_ioctl(struct tty_struct *tty, struct file * file, return 0;
#endif
-#ifdef CONFIG_SERIAL_MULTIPORT
- case TIOCSERGETMULTI:
- return get_multiport_struct(info,
- (struct serial_multiport_struct *) arg);
- case TIOCSERSETMULTI:
- return set_multiport_struct(info,
- (struct serial_multiport_struct *) arg);
-#endif
-
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -2194,7+1592,8 @@ static int su_ioctl(struct tty_struct *tty, struct file * file, /* return 0; */ /* Trigger warnings is fall through by a chance. */
}
-static void su_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void
+su_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
@@ -2257,7+1656,8 @@ static void su_set_termios(struct tty_struct *tty, struct termios *old_termios) * that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
-static void su_close(struct tty_struct *tty, struct file * filp)
+static void
+su_close(struct tty_struct *tty, struct file * filp)
{
struct su_struct *info = (struct su_struct *)tty->driver_data;
unsigned long flags;
@@ -2359,7+1759,8 @@ static void su_close(struct tty_struct *tty, struct file * filp) /*
* su_wait_until_sent() --- wait until the transmitter is empty
*/
-static void su_wait_until_sent(struct tty_struct *tty, int timeout)
+static void
+su_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct su_struct * info = (struct su_struct *)tty->driver_data;
unsigned long orig_jiffies, char_time;
@@ -2412,7+1813,8 @@ static void su_wait_until_sent(struct tty_struct *tty, int timeout) /*
* su_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-static void su_hangup(struct tty_struct *tty)
+static void
+su_hangup(struct tty_struct *tty)
{
struct su_struct * info = (struct su_struct *)tty->driver_data;
@@ -2433,8+1835,9 @@ static void su_hangup(struct tty_struct *tty) * su_open() and friends
* ------------------------------------------------------------
*/
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct su_struct *info)
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct su_struct *info)
{
struct wait_queue wait = { current, NULL };
int retval;
@@ -2569,8+1972,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * enables interrupts for a serial port, linking in its async structure into
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
- */
-static int su_open(struct tty_struct *tty, struct file * filp)
+ */
+static int
+su_open(struct tty_struct *tty, struct file * filp)
{
struct su_struct *info;
int retval, line;
@@ -2646,7+2050,7 @@ static int su_open(struct tty_struct *tty, struct file * filp) if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
- change_speed(info);
+ change_speed(info);
}
#endif
info->session = current->session;
@@ -2661,15+2065,15 @@ static int su_open(struct tty_struct *tty, struct file * filp) /*
* /proc fs routines....
*/
-
-static inline int line_info(char *buf, struct su_struct *info)
+static __inline__ int
+line_info(char *buf, struct su_struct *info)
{
char stat_buf[30], control, status;
int ret;
- ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+ ret = sprintf(buf, "%d: uart:%s port:%X irq:%s",
info->line, uart_config[info->type].name,
- (int)info->port, info->irq);
+ (int)info->port, __irq_itoa(info->irq));
if (info->port == 0 || info->type == PORT_UNKNOWN) {
ret += sprintf(buf+ret, "\n");
* number, and identifies which options were configured into this
* driver.
*/
-static _INLINE_ void show_su_version(void)
+static __inline__
+void show_su_version(void)
{
- printk(KERN_INFO "%s version %s with", serial_name, serial_version);
-#ifdef CONFIG_SERIAL_MANY_PORTS
- printk(" MANY_PORTS");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_MULTIPORT
- printk(" MULTIPORT");
-#define SERIAL_OPT
-#endif
-#ifdef CONFIG_SERIAL_SHARE_IRQ
- printk(" SHARE_IRQ");
-#endif
-#define SERIAL_OPT
-#ifdef CONFIG_SERIAL_DETECT_IRQ
- printk(" DETECT_IRQ");
-#endif
-#ifdef SERIAL_OPT
- printk(" enabled\n");
-#else
- printk(" no serial options enabled\n");
-#endif
-#undef SERIAL_OPT
+ printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
}
/*
@@ -2828,16+2212,10 @@ ebus_done: return;
info->irq = dev->irqs[0];
-
-#ifdef DEBUG_SERIAL_OPEN
- printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
- __irq_itoa(dev->irqs[0]));
-#endif
-
#else
- if (info->port_node == 0) {
+ if (!info->port_node)
return;
- }
+
if (prom_getproperty(info->port_node, "reg",
(char *)®0, sizeof(reg0)) == -1) {
prom_printf("su: no \"reg\" property\n");
@@ -2852,7+2230,12 @@ ebus_done: /*
* There is no intr property on MrCoffee, so hardwire it. Krups?
*/
- info->irq = 13;
+ info->irq = IRQ_4M(13);
+#endif
+
+#ifdef DEBUG_SERIAL_OPEN
+ printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
+ __irq_itoa(dev->irqs[0]));
#endif
info->magic = SERIAL_MAGIC;
@@ -2956,19+2339,20 @@ ebus_done: return;
}
+ if (info->kbd_node || info->ms_node)
+ sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+ else
+ strcpy(info->name, "su(serial)");
+
#ifdef __sparc_v9__
- sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
request_region(info->port, 8, info->name);
-#else
- strcpy(info->name, "su(serial)");
#endif
/*
* Reset the UART.
*/
su_outb(info, UART_MCR, 0x00);
- su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
+ su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
su_inb(info, UART_RX);
restore_flags(flags);
@@ -2977,46+2361,12 @@ ebus_done: /*
* The serial driver boot-time initialization code!
*/
-__initfunc(int su_init(void))
+__initfunc(int su_serial_init(void))
{
int i;
struct su_struct *info;
- extern void atomwide_serial_init (void);
- extern void dualsp_serial_init (void);
-
-#ifdef CONFIG_ATOMWIDE_SERIAL
- atomwide_serial_init ();
-#endif
-#ifdef CONFIG_DUALSP_SERIAL
- dualsp_serial_init ();
-#endif
-
+
init_bh(SERIAL_BH, do_serial_bh);
- timer_table[RS_TIMER].fn = su_timer;
- timer_table[RS_TIMER].expires = 0;
-
- for (i = 0; i < NR_IRQS; i++) {
- IRQ_ports[i] = 0;
- IRQ_timeout[i] = 0;
-#ifdef CONFIG_SERIAL_MULTIPORT
- memset(&rs_multiport[i], 0,
- sizeof(struct rs_multiport_struct));
-#endif
- }
-#if 0 /* Must be shared with keyboard on MrCoffee. */
-#ifdef CONFIG_SERIAL_CONSOLE
- /*
- * The interrupt of the serial console port
- * can't be shared.
- */
- if (sercons.flags & CON_CONSDEV) {
- for(i = 0; i < NR_PORTS; i++)
- if (i != sercons.index &&
- su_table[i].irq == su_table[sercons.index].irq)
- su_table[i].irq = 0;
- }
-#endif
-#endif
show_su_version();
/* Initialize the tty_driver structure */
@@ -3076,7+2426,6 @@ __initfunc(int su_init(void)) panic("Couldn't register callout su\n");
for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
- info->magic = SSTATE_MAGIC;
info->line = i;
info->type = PORT_UNKNOWN;
info->baud_base = BAUD_BASE;
@@ -3093,13+2442,36 @@ __initfunc(int su_init(void)) info->icount.overrun = info->icount.brk = 0;
info->tqueue.routine = do_softint;
info->tqueue.data = info;
+ info->cflag = serial_driver.init_termios.c_cflag;
+
+ autoconfig(info);
+ if (info->type == PORT_UNKNOWN)
+ continue;
+
+ printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+ info->name, info->port, __irq_itoa(info->irq),
+ uart_config[info->type].name);
+ }
+
+ return 0;
+}
+
+__initfunc(int su_kbd_ms_init(void))
+{
+ int i;
+ struct su_struct *info;
+
+ show_su_version();
+
+ for (i = 0, info = su_table; i < 2; i++, info++) {
+ info->line = i;
+ info->type = PORT_UNKNOWN;
+ info->baud_base = BAUD_BASE;
if (info->kbd_node)
- info->cflag = B1200 | CS8 | CREAD;
- else if (info->ms_node)
- info->cflag = B4800 | CS8 | CREAD;
+ info->cflag = B1200 | CS8 | CLOCAL | CREAD;
else
- info->cflag = B9600 | CS8 | CREAD;
+ info->cflag = B4800 | CS8 | CLOCAL | CREAD;
autoconfig(info);
if (info->type == PORT_UNKNOWN)
@@ -3109,20+2481,12 @@ __initfunc(int su_init(void)) info->name, info->port, __irq_itoa(info->irq),
uart_config[info->type].name);
- /*
- * We want startup here because we want mouse and keyboard
- * working without opening. On SPARC console will work
- * without startup.
- */
- if (info->kbd_node) {
- startup(info);
- keyboard_zsinit(su_put_char_kbd);
- } else if (info->ms_node) {
startup(info);
+ if (info->kbd_node)
+ keyboard_zsinit(su_put_char_kbd);
+ else
sun_mouse_zsinit();
}
- }
-
return 0;
}
@@ -3147,12+2511,16 @@ __initfunc(int su_probe (unsigned long *memory_start)) info->port_node = sunode;
#ifdef CONFIG_SERIAL_CONSOLE
/*
- * Console must be initiated after the generic initialization.
- * sunserial_setinitfunc inverts order, so call this before next one.
+ * Console must be initiated after the generic
+ * initialization.
+ * sunserial_setinitfunc inverts order, so
+ * call this before next one.
*/
- sunserial_setinitfunc(memory_start, su_serial_console_init);
+ sunserial_setinitfunc(memory_start,
+ su_serial_console_init);
#endif
- sunserial_setinitfunc(memory_start, su_init);
+ sunserial_setinitfunc(memory_start,
+ su_serial_init);
return 0;
}
}
@@ -3237,7+2605,7 @@ __initfunc(int su_probe (unsigned long *memory_start)) /*
* Found everything we need?
*/
- if (devices == NR_PORTS)
+ if (devices == 2)
goto found;
sunode = prom_getsibling(sunode);
@@ -3256,7+2624,7 @@ __initfunc(int su_probe (unsigned long *memory_start)) return -ENODEV;
found:
- sunserial_setinitfunc(memory_start, su_init);
+ sunserial_setinitfunc(memory_start, su_kbd_ms_init);
rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
sunkbd_setinitfunc(memory_start, sun_kbd_init);
kbd_ops.compute_shiftstate = sun_compute_shiftstate;
return 0;
}
-#if 0
-#ifdef MODULE
-int init_module(void)
-{
- return su_init(); /* rs_init? su_probe? XXX */
-}
-
-void cleanup_module(void)
-{
- unsigned long flags;
- int e1, e2;
- int i;
-
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- save_flags(flags);
- cli();
- timer_active &= ~(1 << RS_TIMER);
- timer_table[RS_TIMER].fn = NULL;
- timer_table[RS_TIMER].expires = 0;
- remove_bh(SERIAL_BH);
- if ((e1 = tty_unregister_driver(&serial_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
- e1);
- if ((e2 = tty_unregister_driver(&callout_driver)))
- printk("SERIAL: failed to unregister callout driver (%d)\n",
- e2);
- restore_flags(flags);
-
- for (i = 0; i < NR_PORTS; i++) {
- if (su_table[i].type != PORT_UNKNOWN)
- release_region(su_table[i].port, 8);
- }
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = NULL;
- }
-}
-#endif /* MODULE */
-#endif /* deadwood */
-
/*
* ------------------------------------------------------------
* Serial console driver
@@ -3325,7+2653,8 @@ void cleanup_module(void) /*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct su_struct *info)
+static __inline__ void
+wait_for_xmitr(struct su_struct *info)
{
int lsr;
unsigned int tmout = 1000000;
@@ -3341,7+2670,8 @@ static inline void wait_for_xmitr(struct su_struct *info) * Print a string to the serial port trying not to disturb
* any possible real use of the port...
*/
-static void serial_console_write(struct console *co, const char *s,
+static void
+serial_console_write(struct console *co, const char *s,
unsigned count)
{
struct su_struct *info;
@@ -3383,7+2713,8 @@ static void serial_console_write(struct console *co, const char *s, /*
* Receive character from the serial port
*/
-static int serial_console_wait_key(struct console *co)
+static int
+serial_console_wait_key(struct console *co)
{
struct su_struct *info;
int ier;
@@ -3413,7+2744,8 @@ static int serial_console_wait_key(struct console *co) return c;
}
-static kdev_t serial_console_device(struct console *c)
+static kdev_t
+serial_console_device(struct console *c)
{
return MKDEV(TTY_MAJOR, 64 + c->index);
}
-/* $Id: sunserial.c,v 1.66 1998/09/21 05:48:48 jj Exp $
+/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $
* serial.c: Serial port driver infrastructure for the Sparc.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -399,6+399,14 @@ sun_serial_setup(unsigned long memory_start))
if (!ret)
return memory_start;
+
+#ifdef __sparc_v9__
+ ret = prom_finddevice("/ssp-serial");
+ if (ret && ret != -1) {
+ /* Hello, Starfire. Pleased to meet you :) */
+ return memory_start;
+ }
+#endif
prom_printf("No serial devices found, bailing out.\n");
prom_halt();
@@ -218,7+218,7 @@ static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) return -ENOMEM;
if(copy_from_user(buffer, inout.buffer,
- inout.len*sizeof(char));) {
+ inout.len*sizeof(char))) {
kfree_s(buffer,inout.len*sizeof(char));
return -EFAULT;
}
-/* $Id: zs.c,v 1.29 1998/09/21 05:06:53 jj Exp $
+/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $
* zs.c: Zilog serial port driver for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1808,7+1808,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.29 $";
+ char *revision = "$Revision: 1.31 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -1830,6+1830,7 @@ __initfunc(static struct sun_zslayout * get_zs(int chip))
{
unsigned int vaddr[2] = { 0, 0 };
+ unsigned long mapped_addr = 0;
int busnode, seen, zsnode, sun4u_ino;
static int irq = 0;
@@ -1854,7+1855,30 @@ get_zs(int chip)) int len = prom_getproperty(zsnode, "address",
(void *) vaddr, sizeof(vaddr));
- if(len % sizeof(unsigned int)) {
+ if(len == -1) {
+ struct linux_sbus *sbus;
+ struct linux_sbus_device *sdev = NULL;
+
+ /* "address" property is not guarenteed,
+ * everything in I/O is implicitly mapped
+ * anyways by our clever TLB miss handling
+ * scheme, so don't fail here. -DaveM
+ */
+ for_each_sbus(sbus) {
+ for_each_sbusdev(sdev, sbus) {
+ if (sdev->prom_node == zsnode)
+ goto found;
+ }
+ }
+ found:
+ if (sdev == NULL)
+ prom_halt();
+ prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
+ mapped_addr = (unsigned long)
+ sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+ PAGE_SIZE, "Zilog Registers",
+ sdev->reg_addrs[0].which_io, 0x0);
+ } else if(len % sizeof(unsigned int)) {
prom_printf("WHOOPS: proplen for %s "
"was %d, need multiple of "
"%d\n", "address", len,
@@ -1883,9+1907,12 @@ get_zs(int chip)) }
if(!zsnode)
panic("get_zs: whee chip not found");
- if(!vaddr[0])
+ if(!vaddr[0] && !mapped_addr)
panic("get_zs: whee no serial chip mappable");
- return (struct sun_zslayout *)(unsigned long) vaddr[0];
+ if (mapped_addr != 0)
+ return (struct sun_zslayout *) mapped_addr;
+ else
+ return (struct sun_zslayout *) (unsigned long) vaddr[0];
}
#else /* !(__sparc_v9__) */
__initfunc(static struct sun_zslayout *
@@ -2119,7+2146,7 @@ no_probe: kbd_ops.getledstate = sun_getledstate;
kbd_ops.setkeycode = sun_setkeycode;
kbd_ops.getkeycode = sun_getkeycode;
-#ifdef CONFIG_PCI
+#if defined(__sparc_v9__) && defined(CONFIG_PCI)
sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
sun_func_buf, sun_func_table,
sun_funcbufsize, sun_funcbufleft,
-/* $Id: sbus.c,v 1.72 1998/09/05 17:25:51 jj Exp $
+/* $Id: sbus.c,v 1.73 1998/10/07 11:35:50 jj Exp $
* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -278,8+278,16 @@ __initfunc(void sbus_init(void)) if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
(nd = prom_getchild(iommund)) == 0 ||
(nd = prom_searchsiblings(nd, "sbus")) == 0) {
+#ifdef CONFIG_PCI
+ if (!pcibios_present()) {
+ prom_printf("Neither SBUS nor PCI found.\n");
+ prom_halt();
+ }
+ return;
+#else
/* No reason to run further - the data access trap will occur. */
panic("sbus not found");
+#endif
}
}
@@ -104,8+104,11 @@ if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
-if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
- dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+ dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
+ bool ' _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP
+ fi
fi
dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
--- /dev/null
+The tmscsim driver
+==================
+
+1. Purpose and history
+2. Installation
+3. Features
+4. Configuration via /proc/scsi/tmscsim/?
+5. Configuration via boot/module params
+6. Potential improvements
+7. Bug reports, debugging and updates
+8. Acknowledgements
+
+
+1. Purpose and history
+----------------------
+The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974
+chip. AM53C974 based SCSI adapters include:
+ Tekram DC390, DC390T
+ Dawicontrol 2974
+ some on-board adapters
+(This is most probably not a complete list)
+
+It has originally written by C.L. Huang from the Tekram corp. to support the
+Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
+scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
+(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
+tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more,
+as the ncr53c8xx is perfectly supporting these adpaters since some time.
+
+The driver first appeared in April 1996, exclusively supported the DC390
+and has been enhanced since then in various steps. In May 1998 support for
+general AM53C974 based adapters and some possibilities to configure it were
+added. The non-DC390 support works by assuming some values for the data
+normally taken from the DC390 EEPROM. See below (chapter 5) for details.
+
+When using the DC390, the configuration is still be done using the DC390
+BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or
+module parameters (chapter 5) are ignored! However, you can change settings
+dynamically, as described in chapter 4.
+
+For a more detailed description of the driver's history, see the first lines
+of tmscsim.c.
+The numbering scheme isn't consistent. The first versions went from 1.00 to
+1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
+the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
+2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
+fixes to people for testing, those will have a digit appended, e.g. 2.0a1.
+
+
+2. Installation
+---------------
+If you got any recent kernel with this driver and document included in
+linux/drivers/scsi, you basically have to do nothing special to use this
+driver. Of course you have to choose to compile SCSI support and DC390(T)
+support into your kernel or as module when configuring your kernel for
+compiling.
+
+If you got an older kernel with an old version of this driver included, you
+should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and
+README.tmscsim) from this directory to linux/drivers/scsi. You have to
+recompile your kernel/module of course.
+
+You should apply the three patches included in dc390-20-kernel.diff
+(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff)
+The patches are against 2.1.103, so you might have to manually resolve
+rejections when applying to another kernel version.
+
+The patches will update the kernel startup code to allow boot parameters to
+be passed to the driver, update the Documentation and finally offer you the
+possibility to omit the non-DC390 parts of the driver.
+(By selecting "Omit support for non DC390" you basically disable the
+emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
+of memory.)
+
+If you got a very old kernel without the tmscsim driver (pre 2.0.31)
+I recommend upgrading your kernel. However, if you don't want to, please
+contact me to get the appropriate patches.
+
+Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has
+proven stable on many systems, but it's still a good idea to take some
+precautions. In an ideal world you would have a full backup of your disks.
+The world isn't ideal and most people don't have full backups (me neither).
+So take at least the following two measures:
+* make your kernel remount the FS read-only on detecting an error:
+ tune2fs -e remount-ro /dev/sd??
+* have copies of your SCSI disk's partition tables on some safe location:
+ dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1
+* make sure you are able to boot Linux (e.g. from floppy disk using InitRD)
+ if your SCSI disk gets corrupted. You can use
+ ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz
+
+One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram
+DC390F (Sym53c875) accepted this as well as my Millenium. But the Am53C974
+produced errors and started to corrupt my disks. So don't do that! A 37.50
+MHz PCI bus works for me, though, but I don't recommend using higher clocks
+than the 33.33 MHz being in the PCI spec.
+
+If you want to share the IRQ with another device and the driver refuses to
+do, you might succeed with changing the DC390_IRQ type in tmscsim.c to
+SA_SHIRQ | SA_INTERRUPT.
+
+
+3.Features
+----------
+- SCSI
+ * Tagged queueing
+ * Sync speed up to 10 MHz
+ * Disconnection
+ * Multiple LUNs
+
+- General / Linux interface
+ * Support for up to 4 adapters.
+ * DC390 EEPROM usage or boot/module params
+ * Information via cat /proc/scsi/tmscsim/?
+ * Dynamically configurable by writing to /proc/scsi/tmscsim/?
+ * Dynamic allocation of resources
+ * SMP support: Adapter specific locks (Linux 2.1.x)
+ * Uniform source code for Linux-2.x.y
+ * Support for dyn. addition/removal of devices via add/remove-single-device
+ (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi
+ H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care!
+ * Try to use the partition table for the determination of the mapping
+
+
+4. Configuration via /proc/scsi/tmscsim/?
+-----------------------------------------
+First of all look at the output of /proc/scsi/tmscsim/? by typing
+ cat /proc/scsi/tmscsim/?
+The "?" should be replaced by the SCSI host number. (The shell might do this
+for you.)
+You will see some info regarding the adapter and, at the end, a listing of
+the attached devices and their settings.
+
+Here's an example:
+garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0
+Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20
+SCSI Host Nr 0, AM53C974 Adapter Nr 0
+IOPortBase 0x6200, IRQLevel 0x09
+MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms
+TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns
+Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0
+ Nr of lost arbitrations 17
+Nr of attached devices: 4, Nr of DCBs: 4
+Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs
+00 00 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15
+01 01 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15
+02 03 00 Yes Yes Yes Yes No No 100 ns 10.0 M 15
+03 05 00 Yes No Yes Yes No No (200 ns)
+
+Note that the settings MaxID and MaxLUN are not zero- but one-based, which
+means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This
+is somehow inconvenient, but the way the mid-level SCSI code expects it to be.
+
+ACB and DCB are acronyms for Adapter Control Block and Device Control Block.
+These are data structures of the driver containing information about the
+adapter and the connected SCSI devices respectively.
+
+Idx is the device index (just a consecutive number for the driver), ID and
+LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous
+negotiation, DsCn Disconnection, SndS Send Start command on startup (not
+used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and
+SyncSpeed are somehow redundant, because they are reciprocal values
+(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the
+NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know
+if certain devices will have problems with this discrepancy. Max. speed is
+10 MHz corresp. to a min. NegoPeriod of 100 ns.
+(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept
+it, but that's out of adapter spec, on your own risk and unlikely to improve
+performance. You're likely to crash your disks.)
+SyncOffs is the offset used for synchronous negotiations; max. is 15.
+The last values are only shown, if Sync is enabled. (NegoPeriod is still
+displayed in brackets to show the values which will be used after enabling
+Sync.)
+The STOP parameter is for testing/debugging purposes only and should bet set
+to No. Please don't fiddle with it, unless you want to get rid of the
+contents of your disk.
+
+If you want to change a setting, you can do that by writing to
+/proc/scsi/tmscsim/?. Basically you have to imitate the output of driver.
+(Don't use the brackets for NegoPeriod on Sync disabled devices.)
+You don't have to care about capitalisation. The driver will accept space,
+tab, comma, = and : as separators.
+
+There are three kinds of changes:
+
+(1) Change driver settings:
+ You type the names of the parameters and the params following it.
+ Example:
+ echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0
+
+ Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut,
+ TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you
+ want to see what happens, if the driver hangs.
+
+(2) Change device settings: You write a config line to the driver. The Nr
+ must match the ID and LUN given. If you give "-" as parameter, it is
+ ignored and the corresponding setting won't be changed.
+ You can use "y" or "n" instead of "Yes" and "No" if you want to.
+ You don't need to specify a full line. The driver automatically performs
+ an INQUIRY on the device if necessary to check if it is capable to operate
+ with the given settings (Sync, TagQ).
+ Examples:
+ echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0
+ echo "3 5 0 y n y" >/proc/scsi/tmscsim/0
+
+ To give a short explanation of the first example:
+ The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0),
+ select the device to which the following parameters apply. Note that it
+ would be sufficient to use the index or both SCSI ID and LUN, but I chose
+ to require all three to have a syntax similar to the output.
+ The following "y y y - y" enables Parity checking, enables Synchronous
+ transfers, Disconnection, leaves Send Start (not used) untouched and
+ enables Tagged Command Queueing for the selected device. The "-" skips
+ the Negotiation Period setting but the "10" sets the max sync. speed to
+ 10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as
+ discussed above. The values used in this example will result in maximum
+ performance.
+
+(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and
+ the removal of a device's DCB.
+ This is only used for debugging when you meet problems. The parameter of
+ the INQUIRY and remove command is the device index as shown by the
+ output of /proc/scsi/tmscsim/? in the device listing in the first column
+ (Idx).
+ Examples:
+ echo "reset" >/proc/scsi/tmscsim/0
+ echo "inquiry 1" >/proc/scsi/tmscsim/0
+ echo "remove 2" >/proc/scsi/tmscsim/1
+
+ Note that you will meet problems when you remove a device's DCB with the
+ remove command if it contains partitions which are mounted. Only use it
+ after unmounting its partitions, telling the SCSI mid-level code to
+ remove it (scsi remove-single-device) and you really need a few bytes of
+ memory.
+
+
+I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing
+settings to see if everything changed as requested.
+
+
+5. Configuration via boot/module parameters
+-------------------------------------------
+With the DC390, the driver reads its EEPROM settings and IGNORES boot /
+module parameters. If you want to override the EEPROM settings of a DC390,
+you have to use the /proc/scsi/tmscsim/? interface described in the above
+chapter.
+
+However, if you do have another AM53C974 based adapter you might want to
+adjust some settings before you are able to write to the /proc/scsi/tmscsim/?
+pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that
+the log message "DC390: No EEPROM found!" is normal without a DC390.)
+For this purpose, you can pass options to the driver before it is initialised
+by using kernel or module parameters. See lilo(8) or modprobe(1) manual
+pages on how to pass params to the kernel or a module.
+
+The syntax of the params is much shorter than the syntax of the /proc/...
+interface. This makes it a little bit more difficult to use. However, long
+parameter lines have the risk to be misinterpreted and the length of kernel
+parameters is limited.
+
+As the support for non-DC390 adapters works by simulating the values of the
+DC390 EEPROM, the settings are given in a DC390 BIOS' way.
+
+Here's the syntax:
+tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds
+
+Each of the parameters is a number, containing the described information:
+
+* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7
+ Default is 7.
+
+* SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values
+ 0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is
+ 1 (8.0 MHz).
+
+* DevMode is a bit mapped value describing the per-device features. It
+ applies to all devices. (Sync, Disc and TagQ will only apply, if the
+ device supports it.) The meaning of the bits (* = default):
+
+ Bit Val(hex) Val(dec) Meaning
+ *0 0x01 1 Parity check
+ *1 0x02 2 Synchronous Negotiation
+ *2 0x04 4 Disconnection
+ *3 0x08 8 Send Start command on startup. (Not used)
+ *4 0x10 16 Tagged Queueing
+
+ As usual, the desired value is obtained by adding the wanted values. If
+ you want to enable all values, e.g., you would use 31(0x1f). Default is 31.
+
+* AdaptMode is a bit mapped value describing the enabled adapter features.
+
+ Bit Val(hex) Val(dec) Meaning
+ *0 0x01 1 Support more than two drives. (Not used)
+ *1 0x02 2 Use DOS compatible mapping for HDs greater than 1GB.
+ *2 0x04 4 Reset SCSI Bus on startup.
+ *3 0x08 8 Active Negation: Improves SCSI Bus noise immunity.
+ 4 0x10 16 Immediate return on BIOS seek command. (Not used)
+ (*)5 0x20 32 Check for LUNs >= 1.
+
+ The default for LUN Check depends on CONFIG_SCSI_MULTI_LUN.
+
+* TaggedCmnds is a number indicating the maximum number of Tagged Commands.
+ It is the binary logarithm - 1 of the actual number. Max is 4 (32).
+ Value Number of Tagged Commands
+ 0 2
+ 1 4
+ 2 8
+ *3 16
+ 4 32
+
+Example:
+ modprobe tmscsim tmscsim=6,2,31
+would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device
+features and leave the adapter features and the number of Tagged Commands
+to the defaults.
+
+As you can see, you don't need to specify all of the five params.
+
+The defaults (7,1,31,15,3) are aggressive to allow good performance. You can
+use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is
+perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut
+for tmscsim=7,4,9,15,2.
+
+
+6. Potential improvements
+-------------------------
+Most of the intended work on the driver has been done. Here are a few ideas
+to further improve its usability:
+
+* More intelligent abort() routine
+* Implement new_eh code (Linux-2.1+)
+* Have the mid-level code (and not the driver) handle more of the various
+ conditions.
+* Rework command queueing in the driver
+* More user friendly boot/module param syntax
+
+Further investigation on these problems:
+
+* TagQ and Disconnection (Resel: SRB Tag Seleection)
+* Problems with IRQ sharing (IO-APIC on SMP Systems) (??)
+* Driver crashes with readcdda (xcdroast)
+
+Known problems:
+
+* There was a report that with a certain Scanner, the last SCSI command
+ won't be finished correctly. This might be a command queueing bug or a bug
+ in SCSI implementation of the scanner. Issueing another command to the
+ scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where
+ x is the index (not the SCSI ID!) of the scanner. See 4.(3).)
+* If there is a valid partition table, the driver will use it for determing
+ the mapping. Other operating systems may not like this mapping, though
+ it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
+ partition table and used a H/S = 64/32 or 255/63 translation. So if you
+ want to be compatible to those, use this old mapping when creating
+ partition tables.
+* In some situations, the driver will get stuck in an abort loop. Please
+ disable DsCn, if you meet this problem. Please contact me for further
+ debugging.
+* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c
+ There used to be a patch included here, which partially solved the
+ problem. I suggest you contact Chiaki Ishikawa <ishikawa@yk.rim.or.jp>,
+ Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
+ <dledford@dialnet.net>, if you want to help further debugging it.
+* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
+ the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply
+ the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa.
+ I was told that this fix will be in 2.0.36, so you don't need it for
+ 2.0.36.
+[The patch file is contained in the dc390-XXX.tar.gz files which can be found
+on the ftp server. See below.]
+
+
+7. Bug reports, debugging and updates
+-------------------------------------
+Whenever you have problems with the driver, you are invited to ask the
+author for help. However, I'd suggest reading the docs and trying to solve
+the problem yourself, first.
+If you find something, which you believe to be a bug, please report it to me.
+Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
+maybe the DC390 log messages to the report.
+
+Bug reports should be send to me (Kurt Garloff <K.Garloff@ping.de>) as well
+as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs
+are caused by the SCSI mid-level code.
+
+I will ask you for some more details and probably I will also ask you to
+enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX
+defines). The driver will produce some data for the syslog facility then.
+Beware: If your syslog gets written to a SCSI disk connected to your
+AM53C974, the logging might produce log output again, and you might end
+having your box spending most of its time doing the logging.
+
+The latest version of the driver can be found at:
+ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+
+
+8. Acknowledgements
+-------------------
+Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF
+people, the XFree86 team and all the others for the wonderful OS and
+software.
+Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
+release and support.
+Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding.
+Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert
+Tonneau) for intensively testing the driver (and even risking data loss
+doing this during early revisions).
+
+
+-------------------------------------------------------------------------
+Written by Kurt Garloff <K.Garloff@ping.de> 1998/06/11
+Last updated 1998/10/15, driver revision 2.0b
+$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $
* Description: Device Driver for Tekram DC-390(T) PCI SCSI *
* Bus Master Host Adapter *
***********************************************************************/
+/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */
#include <linux/version.h>
/*
- * AMD 53C974 driver, header file
+ * DC390/AMD 53C974 driver, header file
*/
#ifndef DC390_H
#define DC390_H
+#define DC390_BANNER "Tekram DC390/AM53C974"
+#define DC390_VERSION "2.0b 1998/10/24"
+
#if defined(HOSTS_C) || defined(MODULE)
#include <scsi/scsicam.h>
@@ -30,24+34,24 @@ static int DC390_release(struct Scsi_Host *); # define DC390_release NULL
#endif
-extern struct proc_dir_entry proc_scsi_tmscsim;
-extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
-
-#define DC390_T { \
- proc_dir: &proc_scsi_tmscsim, \
- proc_info: tmscsim_proc_info, \
- name: "Tekram DC390(T) V1.12 Feb-25-1998",\
- detect: DC390_detect, \
- release: DC390_release, \
- queuecommand: DC390_queue_command, \
- abort: DC390_abort, \
- reset: DC390_reset, \
- bios_param: DC390_bios_param, \
- can_queue: 10, \
- this_id: 7, \
- sg_tablesize: SG_ALL, \
- cmd_per_lun: 2, \
- use_clustering: DISABLE_CLUSTERING \
+extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
+extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+
+#define DC390_T { \
+ proc_dir: &DC390_proc_scsi_tmscsim, \
+ proc_info: DC390_proc_info, \
+ name: DC390_BANNER " V" DC390_VERSION, \
+ detect: DC390_detect, \
+ release: DC390_release, \
+ queuecommand: DC390_queue_command, \
+ abort: DC390_abort, \
+ reset: DC390_reset, \
+ bios_param: DC390_bios_param, \
+ can_queue: 17, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 8, \
+ use_clustering: DISABLE_CLUSTERING \
}
#endif /* defined(HOSTS_C) || defined(MODULE) */
* Description: Device Driver for Tekram DC-390 (T) PCI SCSI *
* Bus Master Host Adapter *
***********************************************************************/
+/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */
-
-static USHORT
-DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+UCHAR
+dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
{
- USHORT ioport, rc;
- UCHAR bval, bval1, i, cnt;
- PUCHAR ptr;
- ULONG wlval;
+ USHORT wlval;
+ UCHAR bval, bval1;
pSRB->TagNumber = 31;
- ioport = pACB->IOPortBase;
- bval = pDCB->UnitSCSIID;
- outb(bval,ioport+Scsi_Dest_ID);
- bval = pDCB->SyncPeriod;
- outb(bval,ioport+Sync_Period);
- bval = pDCB->SyncOffset;
- outb(bval,ioport+Sync_Offset);
- bval = pDCB->CtrlR1;
- outb(bval,ioport+CtrlReg1);
- bval = pDCB->CtrlR3;
- outb(bval,ioport+CtrlReg3);
- bval = pDCB->CtrlR4;
- outb(bval,ioport+CtrlReg4);
- bval = CLEAR_FIFO_CMD; /* Flush FIFO */
- outb(bval,ioport+ScsiCmd);
-
+ DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+ DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+ DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+ DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+ DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+ DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */
+ DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
+ pSRB->CmdBlock[0], pDCB->SyncMode);)
pSRB->ScsiPhase = SCSI_NOP0;
+ //pSRB->MsgOutBuf[0] = MSG_NOP;
+ //pSRB->MsgCnt = 0;
bval = pDCB->IdentifyMsg;
- if( !(pDCB->SyncMode & EN_ATN_STOP) )
+ if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */
{
if( (pSRB->CmdBlock[0] == INQUIRY) ||
(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
(pSRB->SRBFlag & AUTO_REQSENSE) )
{
- bval &= 0xBF; /* NO disconnection */
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval &= 0xBF; /* No DisConn */
+ DC390_write8 (ScsiFifo, bval);
+ bval1 = SEL_W_ATN;
pSRB->SRBState = SRB_START_;
+ DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
if( pDCB->SyncMode & SYNC_ENABLE )
- {
- if( !(pDCB->IdentifyMsg & 7) ||
+ {
+ if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */
(pSRB->CmdBlock[0] != INQUIRY) )
{
- bval1 = SEL_W_ATN_STOP;
+ bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */
pSRB->SRBState = SRB_MSGOUT;
}
}
}
- else
+ else /* TagQ ? */
{
- if(pDCB->SyncMode & EN_TAG_QUEUING)
+ DC390_write8 (ScsiFifo, bval);
+ if(pDCB->SyncMode & EN_TAG_QUEUEING)
{
- outb(bval,ioport+ScsiFifo);
- bval = MSG_SIMPLE_QTAG;
- outb(bval,ioport+ScsiFifo);
- wlval = 1;
- bval = 0;
- while( wlval & pDCB->TagMask )
- {
- wlval = wlval << 1;
- bval++;
- }
- outb(bval,ioport+ScsiFifo);
+ DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
+ DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+ bval = 0; wlval = 1;
+ while (wlval & pDCB->TagMask)
+ { bval++; wlval <<= 1; };
pDCB->TagMask |= wlval;
+ DC390_write8 (ScsiFifo, bval);
pSRB->TagNumber = bval;
- bval1 = SEL_W_ATN2;
+ DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+ bval1 = SEL_W_ATN3;
pSRB->SRBState = SRB_START_;
}
- else
+ else /* No TagQ */
{
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval1 = SEL_W_ATN;
+ DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
pSRB->SRBState = SRB_START_;
}
}
- if( pSRB->SRBFlag & AUTO_REQSENSE )
- {
- bval = REQUEST_SENSE;
- outb(bval,ioport+ScsiFifo);
- bval = pDCB->IdentifyMsg << 5;
- outb(bval,ioport+ScsiFifo);
- bval = 0;
- outb(bval,ioport+ScsiFifo);
- outb(bval,ioport+ScsiFifo);
- bval = sizeof(pSRB->pcmd->sense_buffer);
- outb(bval,ioport+ScsiFifo);
- bval = 0;
- outb(bval,ioport+ScsiFifo);
- }
- else
- {
- cnt = pSRB->ScsiCmdLen;
- ptr = (PUCHAR) pSRB->CmdBlock;
- for(i=0; i<cnt; i++)
- {
- bval = *ptr++;
- outb(bval,ioport+ScsiFifo);
- }
- }
}
- else /* ATN_STOP */
+ else /* ATN_STOP: Always try to establish Sync nego */
{
if( (pSRB->CmdBlock[0] == INQUIRY) ||
(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
(pSRB->SRBFlag & AUTO_REQSENSE) )
{
- bval &= 0xBF;
- outb(bval,ioport+ScsiFifo);
- bval1 = SELECT_W_ATN;
+ bval &= 0xBF; /* No DisConn */
+ DC390_write8 (ScsiFifo, bval);
+ bval1 = SEL_W_ATN;
+ DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
pSRB->SRBState = SRB_START_;
+ /* ??? */
if( pDCB->SyncMode & SYNC_ENABLE )
{
- if( !(pDCB->IdentifyMsg & 7) ||
+ if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */
(pSRB->CmdBlock[0] != INQUIRY) )
{
- bval1 = SEL_W_ATN_STOP;
+ bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */
pSRB->SRBState = SRB_MSGOUT;
}
}
}
- else
+ else /* TagQ ? */
{
- if(pDCB->SyncMode & EN_TAG_QUEUING)
+ DC390_write8 (ScsiFifo, bval);
+ if(pDCB->SyncMode & EN_TAG_QUEUEING)
{
- outb(bval,ioport+ScsiFifo);
pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
- wlval = 1;
- bval = 0;
- while( wlval & pDCB->TagMask )
- {
- wlval = wlval << 1;
- bval++;
- }
+ DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+ bval = 0; wlval = 1;
+ while (wlval & pDCB->TagMask)
+ { bval++; wlval <<= 1; };
pDCB->TagMask |= wlval;
pSRB->TagNumber = bval;
+ DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
pSRB->MsgOutBuf[1] = bval;
pSRB->MsgCnt = 2;
bval1 = SEL_W_ATN_STOP;
- pSRB->SRBState = SRB_START_;
+ pSRB->SRBState = SRB_START_; /* ?? */
}
- else
+ else /* No TagQ */
{
- outb(bval,ioport+ScsiFifo);
pSRB->MsgOutBuf[0] = MSG_NOP;
pSRB->MsgCnt = 1;
pSRB->SRBState = SRB_START_;
bval1 = SEL_W_ATN_STOP;
- }
+ DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+ };
}
}
- bval = inb( ioport+Scsi_Status );
- if( bval & INTERRUPT )
+ if (bval1 != SEL_W_ATN_STOP)
+ { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+ if( pSRB->SRBFlag & AUTO_REQSENSE )
+ {
+ bval = 0;
+ DC390_write8 (ScsiFifo, REQUEST_SENSE);
+ DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+ DC390_write8 (ScsiFifo, bval);
+ DEBUG1(printk ("DC390: AutoReqSense !\n");)
+ }
+ else /* write cmnd to bus */
+ {
+ PUCHAR ptr; UCHAR i;
+ ptr = (PUCHAR) pSRB->CmdBlock;
+ for (i=0; i<pSRB->ScsiCmdLen; i++)
+ DC390_write8 (ScsiFifo, *(ptr++));
+ };
+ }
+
+ /* Check if we can't win arbitration */
+ if (DC390_read8 (Scsi_Status) & INTERRUPT)
{
pSRB->SRBState = SRB_READY;
pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
- rc = 1;
+ DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");)
+ return 1;
}
else
{
pSRB->ScsiPhase = SCSI_NOP1;
+ DEBUG0(if (pACB->pActiveDCB) \
+ printk ("DC390: ActiveDCB != 0\n");)
+ DEBUG0(if (pDCB->pActiveSRB) \
+ printk ("DC390: ActiveSRB != 0\n");)
pACB->pActiveDCB = pDCB;
pDCB->pActiveSRB = pSRB;
- rc = 0;
- outb(bval1,ioport+ScsiCmd);
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, bval1);
+ return 0;
}
- return( rc );
}
+//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
+#define DMA_INT 0
-static void
+#if DMA_INT
+/* This is similar to AM53C974.c ... */
+static UCHAR
+dc390_dma_intr (PACB pACB)
+{
+ PSRB pSRB;
+ UCHAR dstate;
+ DEBUG0(USHORT pstate;PDEVDECL1;)
+
+ DEBUG0(PDEVSET1;)
+ DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
+ DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
+ { printk("DC390: PCI state = %04x!\n", pstate); \
+ PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
+
+ dstate = DC390_read8 (DMA_Status);
+ DC390_write8 (DMA_Status, dstate); /* clear */
+ //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+
+ if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
+ else pSRB = pACB->pActiveDCB->pActiveSRB;
+
+ if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
+ {
+ printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
+ return dstate;
+ };
+ if (dstate & DMA_XFER_DONE)
+ {
+ ULONG residual, xferCnt; int ctr = 5000000;
+ if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
+ {
+ do
+ {
+ DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
+ dstate = DC390_read8 (DMA_Status);
+ DC390_write8 (DMA_Status, dstate); /* clear */
+ residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
+ DC390_read8 (CtcReg_High) << 16;
+ residual += DC390_read8 (Current_Fifo) & 0x1f;
+ } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
+ if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+ /* residual = ... */
+ }
+ else
+ residual = 0;
+
+ /* ??? */
+
+ xferCnt = pSRB->SGToBeXferLen - residual;
+ pSRB->SGBusAddr += xferCnt;
+ pSRB->TotalXferredLen += xferCnt;
+ pSRB->SGToBeXferLen = residual;
+# ifdef DC390_DEBUG0
+ printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n",
+ (unsigned int)residual, (unsigned int)xferCnt);
+# endif
+
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ }
+ return dstate;
+};
+#endif
+
+void __inline__
DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
PACB pACB;
PDCB pDCB;
PSRB pSRB;
- USHORT ioport = 0;
- USHORT phase, i;
+ UCHAR sstatus=0;
+ UCHAR phase, i;
void (*stateV)( PACB, PSRB, PUCHAR );
- UCHAR istate = 0;
- UCHAR sstatus=0, istatus;
+ UCHAR istate, istatus;
+ UCHAR dstatus;
+ DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
+
+ pACB = dc390_pACB_start;
- pACB = pACB_start;
- if( pACB == NULL )
+ if (pACB == 0)
+ {
+ printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n");
return;
- for( i=0; i < adapterCnt; i++ )
+ }
+ DC390_LOCK_DRV;
+
+ for( i=0; i < dc390_adapterCnt; i++ )
{
if( pACB->IRQLevel == (UCHAR) irq )
{
- ioport = pACB->IOPortBase;
- sstatus = inb( ioport+Scsi_Status );
+ sstatus = DC390_read8 (Scsi_Status);
if( sstatus & INTERRUPT )
break;
else
@@ -207,99+273,128 @@ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) }
}
-#ifdef DC390_DEBUG1
- printk("sstatus=%2x,",sstatus);
+ DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
+
+ if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; };
+
+#if DMA_INT
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
+ dstatus = dc390_dma_intr (pACB);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+
+ DEBUG1(printk ("dstatus=%02x,", dstatus);)
+ if (! (dstatus & SCSI_INTERRUPT))
+ {
+ DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");)
+ DC390_UNLOCK_DRV;
+ return;
+ };
+#else
+ dstatus = DC390_read8 (DMA_Status);
#endif
- if( pACB == (PACB )-1 )
- {
- printk("DC390: Spurious interrupt detected!\n");
- return;
- }
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
+ DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
- istate = inb( ioport+Intern_State );
- istatus = inb( ioport+INT_Status );
+ istate = DC390_read8 (Intern_State);
+ istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
-#ifdef DC390_DEBUG1
- printk("Istatus=%2x,",istatus);
-#endif
+ DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
+ dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus;
+ if (sstatus & ILLEGAL_OP_ERR)
+ {
+ printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+ dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+ };
+
if(istatus & DISCONNECTED)
{
- DC390_Disconnect( pACB );
- return;
+ dc390_Disconnect( pACB );
+ goto unlock;
}
if(istatus & RESELECTED)
{
- DC390_Reselect( pACB );
- return;
+ dc390_Reselect( pACB );
+ goto unlock;
}
if(istatus & INVALID_CMD)
{
- DC390_InvalidCmd( pACB );
- return;
+ dc390_InvalidCmd( pACB );
+ goto unlock;
}
if(istatus & SCSI_RESET)
{
- DC390_ScsiRstDetect( pACB );
- return;
+ dc390_ScsiRstDetect( pACB );
+ goto unlock;
}
- if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+ if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
{
pDCB = pACB->pActiveDCB;
- pSRB = pDCB->pActiveSRB;
- if( pDCB )
+ if (!pDCB)
{
- if( pDCB->DCBFlag & ABORT_DEV_ )
- EnableMsgOut( pACB, pSRB );
- }
+ printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
+ goto unlock;
+ };
+ pSRB = pDCB->pActiveSRB;
+ if( pDCB->DCBFlag & ABORT_DEV_ )
+ dc390_EnableMsgOut( pACB, pSRB );
- phase = (USHORT) pSRB->ScsiPhase;
- stateV = (void *) DC390_phase0[phase];
- stateV( pACB, pSRB, &sstatus );
+ phase = pSRB->ScsiPhase;
+ DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
+ stateV = (void *) dc390_phase0[phase];
+ ( *stateV )( pACB, pSRB, &sstatus );
pSRB->ScsiPhase = sstatus & 7;
- phase = (USHORT) sstatus & 7;
- stateV = (void *) DC390_phase1[phase];
- stateV( pACB, pSRB, &sstatus );
+ phase = (UCHAR) sstatus & 7;
+ DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
+ stateV = (void *) dc390_phase1[phase];
+ ( *stateV )( pACB, pSRB, &sstatus );
}
+ unlock:
+ DC390_LOCK_DRV_NI;
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ DC390_UNLOCK_DRV; /* Restore initial flags */
}
-static void
+void
do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long flags;
-
- spin_lock_irqsave(&io_request_lock, flags);
+ DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);)
+ /* Locking is done in DC390_Interrupt */
DC390_Interrupt(irq, dev_id, regs);
- spin_unlock_irqrestore(&io_request_lock, flags);
+ DEBUG1(printk (".. IRQ returned\n");)
}
-static void
-DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR sstatus, bval;
- USHORT ioport;
+ UCHAR sstatus;
PSGL psgl;
ULONG ResidCnt, xferCnt;
- ioport = pACB->IOPortBase;
sstatus = *psstatus;
if( !(pSRB->SRBState & SRB_XFERPAD) )
{
- if( sstatus & PARITY_ERR )
+ if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
pSRB->SRBStatus |= PARITY_ERROR;
if( sstatus & COUNT_2_ZERO )
{
- bval = inb(ioport+DMA_Status);
- while( !(bval & DMA_XFER_DONE) )
- bval = inb(ioport+DMA_Status);
+ int ctr = 5000000; /* only try for about a tenth of a second */
+ while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+ DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+ if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+ DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
pSRB->SGIndex++;
if( pSRB->SGIndex < pSRB->SGcount )
@@ -307,7+402,7 @@ DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) pSRB->pSegmentList++;
psgl = pSRB->pSegmentList;
- pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+ pSRB->SGBusAddr = virt_to_bus( psgl->address );
pSRB->SGToBeXferLen = (ULONG) psgl->length;
}
else
@@ -315,51+410,50 @@ DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) }
else
{
- bval = inb( ioport+Current_Fifo );
- bval &= 0x1f;
- ResidCnt = (ULONG) inb(ioport+CtcReg_High);
- ResidCnt = ResidCnt << 8;
- ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
- ResidCnt = ResidCnt << 8;
- ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
- ResidCnt += (ULONG) bval;
+ ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f;
+ ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16;
+ ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8;
+ ResidCnt += (ULONG) DC390_read8 (CtcReg_Low);
xferCnt = pSRB->SGToBeXferLen - ResidCnt;
- pSRB->SGPhysAddr += xferCnt;
+ pSRB->SGBusAddr += xferCnt;
pSRB->TotalXferredLen += xferCnt;
pSRB->SGToBeXferLen = ResidCnt;
}
}
- bval = WRITE_DIRECTION+DMA_IDLE_CMD;
- outb( bval, ioport+DMA_Cmd);
+ DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
}
-static void
-DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR sstatus, bval;
- USHORT i, ioport, residual;
+ UCHAR sstatus, residual, bval;
PSGL psgl;
- ULONG ResidCnt, xferCnt;
+ ULONG ResidCnt, xferCnt, i;
PUCHAR ptr;
-
- ioport = pACB->IOPortBase;
sstatus = *psstatus;
if( !(pSRB->SRBState & SRB_XFERPAD) )
{
- if( sstatus & PARITY_ERR )
+ if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
pSRB->SRBStatus |= PARITY_ERROR;
if( sstatus & COUNT_2_ZERO )
{
- bval = inb(ioport+DMA_Status);
- while( !(bval & DMA_XFER_DONE) )
- bval = inb(ioport+DMA_Status);
-
- bval = READ_DIRECTION+DMA_IDLE_CMD;
- outb( bval, ioport+DMA_Cmd);
+ int ctr = 5000000; /* only try for about a tenth of a second */
+ int dstate = 0;
+ while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
+ DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+ if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+ if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+ DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \
+ + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \
+ + ((ULONG) DC390_read8 (CtcReg_Low));)
+ DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
+ DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+
+ DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
pSRB->SGIndex++;
@@ -368,7+462,7 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) pSRB->pSegmentList++;
psgl = pSRB->pSegmentList;
- pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+ pSRB->SGBusAddr = virt_to_bus( psgl->address );
pSRB->SGToBeXferLen = (ULONG) psgl->length;
}
else
@@ -377,14+471,15 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) else /* phase changed */
{
residual = 0;
- bval = inb(ioport+Current_Fifo);
+ bval = DC390_read8 (Current_Fifo);
while( bval & 0x1f )
{
+ DEBUG1(printk ("Check for residuals,");)
if( (bval & 0x1f) == 1 )
{
- for(i=0; i< 0x100; i++)
+ for(i=0; i < 0x100; i++)
{
- bval = inb(ioport+Current_Fifo);
+ bval = DC390_read8 (Current_Fifo);
if( !(bval & 0x1f) )
goto din_1;
else if( i == 0x0ff )
@@ -395,87+490,85 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) }
}
else
- bval = inb(ioport+Current_Fifo);
+ bval = DC390_read8 (Current_Fifo);
}
din_1:
- bval = READ_DIRECTION+DMA_BLAST_CMD;
- outb(bval, ioport+DMA_Cmd);
- for(i=0; i<0x8000; i++)
+ DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
+ for (i=0; i<0x8000; i++)
{
- bval = inb(ioport+DMA_Status);
- if(bval & BLAST_COMPLETE)
+ bval = DC390_read8 (DMA_Status);
+ DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */
+ if (bval & BLAST_COMPLETE)
break;
}
- bval = READ_DIRECTION+DMA_IDLE_CMD;
- outb(bval, ioport+DMA_Cmd);
+ if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n");
+ //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
- ResidCnt = (ULONG) inb(ioport+CtcReg_High);
- ResidCnt = ResidCnt << 8;
- ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
- ResidCnt = ResidCnt << 8;
- ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+ DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);)
+ ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
+ ResidCnt <<= 8;
+ ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
+ ResidCnt <<= 8;
+ ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low);
xferCnt = pSRB->SGToBeXferLen - ResidCnt;
- pSRB->SGPhysAddr += xferCnt;
+ pSRB->SGBusAddr += xferCnt;
pSRB->TotalXferredLen += xferCnt;
pSRB->SGToBeXferLen = ResidCnt;
if( residual )
{
- bval = inb(ioport+ScsiFifo); /* get residual byte */
- ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+ bval = DC390_read8 (ScsiFifo); /* get one residual byte */
+ ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr );
*ptr = bval;
- pSRB->SGPhysAddr++;
+ pSRB->SGBusAddr++; xferCnt++;
pSRB->TotalXferredLen++;
pSRB->SGToBeXferLen--;
}
+ DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+ pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
+
}
}
}
static void
-DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}
static void
-DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR bval;
- USHORT ioport;
- ioport = pACB->IOPortBase;
- bval = inb(ioport+ScsiFifo);
- pSRB->TargetStatus = bval;
- bval++;
- bval = inb(ioport+ScsiFifo); /* get message */
- pSRB->EndMessage = bval;
+ pSRB->TargetStatus = DC390_read8 (ScsiFifo);
+ //udelay (1);
+ pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */
*psstatus = SCSI_NOP0;
pSRB->SRBState = SRB_COMPLETED;
- bval = MSG_ACCEPTED_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
}
static void
-DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
*psstatus = SCSI_NOP0;
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
}
-static void
-DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
UCHAR bval;
- USHORT ioport, wval, wval1;
+ USHORT wval, wval1;
PDCB pDCB;
PSRB psrb;
- ioport = pACB->IOPortBase;
pDCB = pACB->pActiveDCB;
- bval = inb( ioport+ScsiFifo );
+ bval = DC390_read8 (ScsiFifo);
if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
{
if(bval == MSG_DISCONNECT)
@@ -490,12+583,12 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) pSRB->SRBState |= SRB_MSGIN_MULTI;
pSRB->MsgInBuf[0] = bval;
pSRB->MsgCnt = 1;
- pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+ pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]);
}
else if(bval == MSG_REJECT_)
{
- bval = RESET_ATN_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+ pDCB->NegoPeriod = 50;
if( pSRB->SRBState & DO_SYNC_NEGO)
goto set_async;
}
@@ -521,7+614,7 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) psrb = pDCB->pGoingLast;
if( pSRB )
{
- for( ;; )
+ for( ;pSRB ; )
{
if(pSRB->TagNumber != bval)
{
@@ -535,7+628,7 @@ DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) if( pDCB->DCBFlag & ABORT_DEV_ )
{
pSRB->SRBState = SRB_ABORT_SENT;
- EnableMsgOut( pACB, pSRB );
+ dc390_EnableMsgOut( pACB, pSRB );
}
if( !(pSRB->SRBState & SRB_DISCONNECT) )
goto mingx0;
pSRB->SRBState = SRB_UNEXPECT_RESEL;
pDCB->pActiveSRB = pSRB;
pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
- EnableMsgOut2( pACB, pSRB );
+ dc390_EnableMsgOut2( pACB, pSRB );
}
}
}
else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
- {
- pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
- if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+ { /* Note: This will fail for target initiated SDTR ? */
+ pSRB->SRBState &= ~(SRB_MSGIN_MULTI);
+ if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) )
{ /* reject_msg: */
pSRB->MsgCnt = 1;
pSRB->MsgInBuf[0] = MSG_REJECT_;
- bval = SET_ATN_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, SET_ATN_CMD);
}
else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
{
set_async:
pDCB = pSRB->pSRBDCB;
+ if (!(pSRB->SRBState & DO_SYNC_NEGO))
+ printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ pSRB->SRBState &= ~DO_SYNC_NEGO;
pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
- pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */
+ pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */
pDCB->CtrlR4 &= 0x3f;
- pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */
- goto re_prog;
+ pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */
+ goto re_prog;
}
else
{ /* set_sync: */
pDCB = pSRB->pSRBDCB;
+ if (!(pSRB->SRBState & DO_SYNC_NEGO))
+ printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n",
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+ pSRB->SRBState &= ~DO_SYNC_NEGO;
pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
pDCB->SyncOffset &= 0x0f0;
pDCB->SyncOffset |= pSRB->MsgInBuf[4];
pDCB->NegoPeriod = pSRB->MsgInBuf[3];
wval = (USHORT) pSRB->MsgInBuf[3];
- wval = wval << 2;
- wval--;
- wval1 = wval / 25;
+ wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */
if( (wval1 * 25) != wval)
wval1++;
- bval = FAST_CLK+FAST_SCSI;
- pDCB->CtrlR4 &= 0x3f;
- if(wval1 >= 8)
+ bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */
+ pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */
+ if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+ pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+ else
+ pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+ if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+ if (wval1 >= 8)
{
- wval1--;
- bval = FAST_CLK; /* ;fast clock/normal scsi */
- pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */
+ wval1--; /* Timing computation differs by 1 from FAST_SCSI */
+ bval = FAST_CLK; /* fast clock / normal scsi */
+ pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */
}
pDCB->CtrlR3 = bval;
pDCB->SyncPeriod = (UCHAR)wval1;
re_prog:
- bval = pDCB->SyncPeriod;
- outb(bval, ioport+Sync_Period);
- bval = pDCB->SyncOffset;
- outb(bval, ioport+Sync_Offset);
- bval = pDCB->CtrlR3;
- outb(bval, ioport+CtrlReg3);
- bval = pDCB->CtrlR4;
- outb(bval, ioport+CtrlReg4);
- SetXferRate( pACB, pDCB);
+ DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+ DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+ DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+ DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+ dc390_SetXferRate (pACB, pDCB);
}
}
}
min6:
*psstatus = SCSI_NOP0;
- bval = MSG_ACCEPTED_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
}
-static void
-DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+void
+dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
{
PSGL psgl;
- UCHAR bval;
- USHORT ioport;
ULONG lval;
-
- ioport = pACB->IOPortBase;
if( pSRB->SGIndex < pSRB->SGcount )
{
- bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
- outb( bval, ioport+DMA_Cmd);
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
if( !pSRB->SGToBeXferLen )
{
psgl = pSRB->pSegmentList;
- pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+ pSRB->SGBusAddr = virt_to_bus( psgl->address );
pSRB->SGToBeXferLen = (ULONG) psgl->length;
+ DEBUG1(printk (" DC390: Next SG segment.");)
}
lval = pSRB->SGToBeXferLen;
- bval = (UCHAR) lval;
- outb(bval,ioport+CtcReg_Low);
- lval = lval >> 8;
- bval = (UCHAR) lval;
- outb(bval,ioport+CtcReg_Mid);
- lval = lval >> 8;
- bval = (UCHAR) lval;
- outb(bval,ioport+CtcReg_High);
-
- lval = pSRB->SGToBeXferLen;
- outl(lval, ioport+DMA_XferCnt);
+ DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+ DC390_write8 (CtcReg_Low, (UCHAR) lval);
+ lval >>= 8;
+ DC390_write8 (CtcReg_Mid, (UCHAR) lval);
+ lval >>= 8;
+ DC390_write8 (CtcReg_High, (UCHAR) lval);
- lval = pSRB->SGPhysAddr;
- outl( lval, ioport+DMA_XferAddr);
-
- bval = DMA_COMMAND+INFO_XFER_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
+ DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
pSRB->SRBState = SRB_DATA_XFER;
- bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */
- outb(bval, ioport+DMA_Cmd);
+ DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
- bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */
- outb(bval, ioport+DMA_Cmd);
+ DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+ //DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
}
else /* xfer pad */
{
+ UCHAR bval = 0;
if( pSRB->SGcount )
{
pSRB->AdaptStatus = H_OVER_UNDER_RUN;
pSRB->SRBStatus |= OVER_RUN;
+ DEBUG0(printk (" DC390: Overrun -");)
}
- bval = 0;
- outb(bval,ioport+CtcReg_Low);
- outb(bval,ioport+CtcReg_Mid);
- outb(bval,ioport+CtcReg_High);
+ DEBUG0(printk (" Clear transfer pad \n");)
+ DC390_write8 (CtcReg_Low, bval);
+ DC390_write8 (CtcReg_Mid, bval);
+ DC390_write8 (CtcReg_High, bval);
pSRB->SRBState |= SRB_XFERPAD;
- bval = DMA_COMMAND+XFER_PAD_BYTE;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
/*
- bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT
- outb(bval, ioport+DMA_Cmd);
- bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT
- outb(bval, ioport+DMA_Cmd);
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+ DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
*/
}
}
static void
-DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR ioDir;
-
- ioDir = WRITE_DIRECTION;
- DataIO_Comm( pACB, pSRB, ioDir);
+ dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
}
static void
-DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR ioDir;
-
- ioDir = READ_DIRECTION;
- DataIO_Comm( pACB, pSRB, ioDir);
+ dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
}
-static void
-DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
PDCB pDCB;
- UCHAR bval;
+ UCHAR i, cnt;
PUCHAR ptr;
- USHORT ioport, i, cnt;
-
- ioport = pACB->IOPortBase;
- bval = RESET_ATN_CMD;
- outb(bval, ioport+ScsiCmd);
- bval = CLEAR_FIFO_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
{
- cnt = (USHORT) pSRB->ScsiCmdLen;
+ cnt = (UCHAR) pSRB->ScsiCmdLen;
ptr = (PUCHAR) pSRB->CmdBlock;
for(i=0; i < cnt; i++)
- {
- outb(*ptr, ioport+ScsiFifo);
- ptr++;
- }
+ DC390_write8 (ScsiFifo, *(ptr++));
}
else
{
- bval = REQUEST_SENSE;
- outb(bval, ioport+ScsiFifo);
+ UCHAR bval = 0;
+ DC390_write8 (ScsiFifo, REQUEST_SENSE);
pDCB = pACB->pActiveDCB;
- bval = pDCB->IdentifyMsg << 5;
- outb(bval, ioport+ScsiFifo);
- bval = 0;
- outb(bval, ioport+ScsiFifo);
- outb(bval, ioport+ScsiFifo);
- bval = sizeof(pSRB->pcmd->sense_buffer);
- outb(bval, ioport+ScsiFifo);
- bval = 0;
- outb(bval, ioport+ScsiFifo);
+ DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, bval);
+ DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+ DC390_write8 (ScsiFifo, bval);
}
pSRB->SRBState = SRB_COMMAND;
- bval = INFO_XFER_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, INFO_XFER_CMD);
}
static void
-DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR bval;
- USHORT ioport;
-
- ioport = pACB->IOPortBase;
- bval = CLEAR_FIFO_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
pSRB->SRBState = SRB_STATUS;
- bval = INITIATOR_CMD_CMPLTE;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
}
-static void
-DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void
+dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR bval;
- USHORT ioport, i, cnt;
+ UCHAR bval, i, cnt;
PUCHAR ptr;
PDCB pDCB;
- ioport = pACB->IOPortBase;
- bval = CLEAR_FIFO_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
pDCB = pACB->pActiveDCB;
if( !(pSRB->SRBState & SRB_MSGOUT) )
{
@@ -785,10+843,7 @@ DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) {
ptr = (PUCHAR) pSRB->MsgOutBuf;
for(i=0; i < cnt; i++)
- {
- outb(*ptr, ioport+ScsiFifo);
- ptr++;
- }
+ DC390_write8 (ScsiFifo, *(ptr++));
pSRB->MsgCnt = 0;
if( (pDCB->DCBFlag & ABORT_DEV_) &&
(pSRB->MsgOutBuf[0] == MSG_ABORT) )
@@ -804,76+859,67 @@ DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) if( pDCB->SyncMode & SYNC_ENABLE )
goto mop1;
}
- outb(bval, ioport+ScsiFifo);
+ DC390_write8 (ScsiFifo, bval);
}
- bval = INFO_XFER_CMD;
- outb( bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, INFO_XFER_CMD);
}
else
{
mop1:
- bval = MSG_EXTENDED;
- outb(bval, ioport+ScsiFifo);
- bval = 3; /* ;length of extended msg */
- outb(bval, ioport+ScsiFifo);
- bval = 1; /* ; sync nego */
- outb(bval, ioport+ScsiFifo);
- bval = pDCB->NegoPeriod;
- outb(bval, ioport+ScsiFifo);
- bval = SYNC_NEGO_OFFSET;
- outb(bval, ioport+ScsiFifo);
+ //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ DC390_write8 (ScsiFifo, MSG_EXTENDED);
+ DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */
+ DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */
+ DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
+ if (pDCB->SyncOffset & 0x0f)
+ DC390_write8 (ScsiFifo, pDCB->SyncOffset);
+ else
+ DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);
pSRB->SRBState |= DO_SYNC_NEGO;
- bval = INFO_XFER_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, INFO_XFER_CMD);
}
}
static void
-DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
- UCHAR bval;
- USHORT ioport;
-
- ioport = pACB->IOPortBase;
- bval = CLEAR_FIFO_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
if( !(pSRB->SRBState & SRB_MSGIN) )
{
- pSRB->SRBState &= SRB_DISCONNECT;
+ pSRB->SRBState &= ~SRB_DISCONNECT;
pSRB->SRBState |= SRB_MSGIN;
}
- bval = INFO_XFER_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
}
static void
-DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}
static void
-DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
{
}
static void
-SetXferRate( PACB pACB, PDCB pDCB )
+dc390_SetXferRate( PACB pACB, PDCB pDCB )
{
- UCHAR bval;
- USHORT cnt, i;
+ UCHAR bval, i, cnt;
PDCB ptr;
if( !(pDCB->IdentifyMsg & 0x07) )
{
if( pACB->scan_devices )
{
- CurrSyncOffset = pDCB->SyncOffset;
+ dc390_CurrSyncOffset = pDCB->SyncOffset;
}
else
{
ptr = pACB->pLinkDCB;
- cnt = pACB->DeviceCnt;
+ cnt = pACB->DCBCnt;
bval = pDCB->UnitSCSIID;
for(i=0; i<cnt; i++)
{
@@ -893,39+939,34 @@ SetXferRate( PACB pACB, PDCB pDCB ) }
-static void
-DC390_Disconnect( PACB pACB )
+void
+dc390_Disconnect( PACB pACB )
{
PDCB pDCB;
PSRB pSRB, psrb;
- ULONG flags;
- USHORT ioport, i, cnt;
- UCHAR bval;
+ UCHAR i, cnt;
-#ifdef DC390_DEBUG0
- printk("DISC,");
-#endif
+ DEBUG0(printk(KERN_INFO "DISC,");)
- save_flags(flags);
- cli();
- ioport = pACB->IOPortBase;
pDCB = pACB->pActiveDCB;
if (!pDCB)
{
-#ifdef DC390_DEBUG0
- printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
-#endif
- restore_flags(flags); return;
+ int j = 400;
+ DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\
+ (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);)
+ while (--j) udelay (1000);
+ DC390_read8 (INT_Status); /* Reset Pending INT */
+ DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+ return;
}
pSRB = pDCB->pActiveSRB;
pACB->pActiveDCB = 0;
pSRB->ScsiPhase = SCSI_NOP0;
- bval = EN_SEL_RESEL;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, EN_SEL_RESEL);
if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
{
pSRB->SRBState = 0;
- DoWaitingSRB( pACB );
+ dc390_DoWaitingSRB( pACB );
}
else if( pSRB->SRBState & SRB_ABORT_SENT )
{
@@ -942,7+983,7 @@ DC390_Disconnect( PACB pACB ) pSRB = psrb;
}
pDCB->pGoingSRB = 0;
- DoWaitingSRB( pACB );
+ dc390_DoWaitingSRB( pACB );
}
else
{
@@ -952,7+993,7 @@ DC390_Disconnect( PACB pACB ) if( !(pACB->scan_devices) )
{
pSRB->SRBState = SRB_READY;
- RewaitSRB( pDCB, pSRB);
+ dc390_RewaitSRB( pDCB, pSRB);
}
else
{
@@ -962,76+1003,66 @@ DC390_Disconnect( PACB pACB ) }
else if( pSRB->SRBState & SRB_DISCONNECT )
{
- DoWaitingSRB( pACB );
+ dc390_DoWaitingSRB( pACB );
}
else if( pSRB->SRBState & SRB_COMPLETED )
{
disc1:
if(pDCB->MaxCommand > 1)
{
- bval = pSRB->TagNumber;
- pDCB->TagMask &= (~(1 << bval)); /* free tag mask */
+ pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */
}
pDCB->pActiveSRB = 0;
pSRB->SRBState = SRB_FREE;
- SRBdone( pACB, pDCB, pSRB);
+ dc390_SRBdone( pACB, pDCB, pSRB);
}
}
- restore_flags(flags);
return;
}
-static void
-DC390_Reselect( PACB pACB )
+void
+dc390_Reselect( PACB pACB )
{
- PDCB pDCB, pdcb;
+ PDCB pDCB;
PSRB pSRB;
- USHORT ioport, wval;
- UCHAR bval, bval1;
-
+ USHORT wval;
+ UCHAR bval;
-#ifdef DC390_DEBUG0
- printk("RSEL,");
-#endif
- ioport = pACB->IOPortBase;
+ DEBUG0(printk(KERN_INFO "RSEL,");)
pDCB = pACB->pActiveDCB;
if( pDCB )
{ /* Arbitration lost but Reselection win */
+ DEBUG0(printk ("(ActiveDCB != 0)");)
pSRB = pDCB->pActiveSRB;
if( !( pACB->scan_devices ) )
{
pSRB->SRBState = SRB_READY;
- RewaitSRB( pDCB, pSRB);
+ dc390_RewaitSRB( pDCB, pSRB);
}
}
- bval = inb(ioport+ScsiFifo); /* get ID */
- bval = bval ^ pACB->HostID_Bit;
+ bval = DC390_read8 (ScsiFifo); /* get ID */
+ DEBUG0(printk ("Dev %02x,", bval);)
+ bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
wval = 0;
- bval1 = 1;
- for(;;)
- {
- if( !(bval & bval1) )
- {
- bval1 = bval1 << 1;
- wval++;
- }
- else
- break;
- }
- wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */
+ while (bval >>= 1) wval++;
+ wval |= ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8; /* get LUN */
+ DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);)
pDCB = pACB->pLinkDCB;
- pdcb = pDCB;
while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
{
pDCB = pDCB->pNextDCB;
- if( pDCB == pdcb )
+ if( pDCB == pACB->pLinkDCB )
+ {
+ printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
+ wval & 0xff, (wval & 0xff00) >> 8);
return;
+ }
}
pACB->pActiveDCB = pDCB;
- if( pDCB->SyncMode & EN_TAG_QUEUING )
+ if( pDCB->SyncMode & EN_TAG_QUEUEING )
{
- pSRB = pACB->pTmpSRB;
+ pSRB = pACB->pTmpSRB; /* ?? */
pDCB->pActiveSRB = pSRB;
}
else
@@ -1041,57+1072,163 @@ DC390_Reselect( PACB pACB ) {
pSRB= pACB->pTmpSRB;
pSRB->SRBState = SRB_UNEXPECT_RESEL;
+ printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
+ wval & 0xff, (wval & 0xff00) >> 8);
pDCB->pActiveSRB = pSRB;
- EnableMsgOut( pACB, pSRB );
+ dc390_EnableMsgOut( pACB, pSRB );
}
else
{
if( pDCB->DCBFlag & ABORT_DEV_ )
{
pSRB->SRBState = SRB_ABORT_SENT;
- EnableMsgOut( pACB, pSRB );
+ printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+ wval & 0xff, (wval & 0xff00) >> 8);
+ dc390_EnableMsgOut( pACB, pSRB );
}
else
pSRB->SRBState = SRB_DATA_XFER;
}
}
+
+ DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
pSRB->ScsiPhase = SCSI_NOP0;
- bval = pDCB->UnitSCSIID;
- outb( bval, ioport+Scsi_Dest_ID);
- bval = pDCB->SyncPeriod;
- outb(bval, ioport+Sync_Period);
- bval = pDCB->SyncOffset;
- outb( bval, ioport+Sync_Offset);
- bval = pDCB->CtrlR1;
- outb(bval, ioport+CtrlReg1);
- bval = pDCB->CtrlR3;
- outb(bval, ioport+CtrlReg3);
- bval = pDCB->CtrlR4; /* ; Glitch eater */
- outb(bval, ioport+CtrlReg4);
- bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+ DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+ DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+ DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+ DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+ DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */
+ DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */
}
-static void
-SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void
+dc390_remove_dev (PACB pACB, PDCB pDCB)
+{
+ PDCB pPrevDCB = pACB->pLinkDCB;
+
+ pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
+ if (pDCB->GoingSRBCnt > 1)
+ {
+ DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);)
+ return;
+ };
+
+ if (pDCB == pACB->pLinkDCB)
+ {
+ if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0;
+ pACB->pLinkDCB = pDCB->pNextDCB;
+ pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
+ }
+ else
+ {
+ while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
+ pPrevDCB->pNextDCB = pDCB->pNextDCB;
+ if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
+ }
+
+ DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+ kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
+ pACB->DCBCnt--;
+ /* pACB->DeviceCnt--; */
+};
+
+
+static UCHAR __inline__
+dc390_tagq_blacklist (char* name)
+{
+ UCHAR i;
+ for(i=0; i<BADDEVCNT; i++)
+ if (memcmp (name, dc390_baddevname1[i], 28) == 0)
+ return 1;
+ return 0;
+};
+
+
+static void
+dc390_disc_tagq_set (PDCB pDCB, PSCSI_INQDATA ptr)
+{
+ /* Check for SCSI format (ANSI and Response data format) */
+ if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
+ {
+ if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+ (pDCB->DevMode & TAG_QUEUEING_) &&
+ /* ((pDCB->DevType == TYPE_DISK)
+ || (pDCB->DevType == TYPE_MOD)) &&*/
+ !dc390_tagq_blacklist (((char*)ptr)+8) )
+ {
+ pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
+ pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */;
+ pDCB->TagMask = 0;
+ }
+ else
+ {
+ /* Do we really need to check for DevType here ? */
+ if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/
+ /* && ((pDCB->DevType == TYPE_DISK)
+ || (pDCB->DevType == TYPE_MOD))*/ )
+ pDCB->SyncMode |= EN_ATN_STOP;
+ else
+ //pDCB->SyncMode &= ~EN_ATN_STOP;
+ pDCB->SyncMode &= ~0;
+ }
+ }
+};
+
+
+static void
+dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
+{
+ UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE;
+ pDCB->DevType = bval1;
+ /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
+ dc390_disc_tagq_set (pDCB, ptr);
+};
+
+
+void
+dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
{
PSRB psrb;
- UCHAR bval, bval1, i, j, status;
+ UCHAR bval, status, i;
PSCSICMD pcmd;
PSCSI_INQDATA ptr;
- USHORT disable_tag;
- ULONG flags;
PSGL ptr2;
ULONG swlval;
pcmd = pSRB->pcmd;
status = pSRB->TargetStatus;
+ DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
+ pSRB, pcmd->pid);)
if(pSRB->SRBFlag & AUTO_REQSENSE)
- {
+ { /* Last command was a Request Sense */
pSRB->SRBFlag &= ~AUTO_REQSENSE;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+#ifdef DC390_REMOVABLEDEBUG
+ switch (pcmd->sense_buffer[2] & 0x0f)
+ {
+ case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+ status, pACB->scan_devices); break;
+ case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+ status, pACB->scan_devices); break;
+ case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+ status, pACB->scan_devices); break;
+ case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+ status, pACB->scan_devices); break;
+ case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+ status, pACB->scan_devices); break;
+ }
+#endif
+ //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
if(status == SCSI_STAT_CHECKCOND)
{
pcmd->result = DID_BAD_TARGET << 16;
@@ -1099,7+1236,7 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) }
if(pSRB->RetryCnt == 0)
{
- *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+ (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0];
pSRB->TotalXferredLen = pSRB->Segment1[1];
if( (pSRB->TotalXferredLen) &&
(pSRB->TotalXferredLen >= pcmd->underflow) )
@@ -1107,28+1244,29 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) else
pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
SCSI_STAT_CHECKCOND;
-#ifdef DC390_DEBUG0
- printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
- (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
-#endif
+ REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
+ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
goto ckc_e;
}
- else
+ else /* Retry */
{
pSRB->RetryCnt--;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
*((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
*((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
- if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+ /* Don't retry on TEST_UNIT_READY */
+ if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */)
{
- pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
- SCSI_STAT_CHECKCOND;
+ pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16)
+ | SCSI_STAT_CHECKCOND;
+ REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
goto ckc_e;
}
pcmd->result |= (DRIVER_SENSE << 24);
- pSRB->SGcount = (UCHAR) pSRB->Segment1[0];
- pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8);
+ pSRB->SGcount = (UCHAR) pSRB->Segment1[0];
+ pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8);
pSRB->SGIndex = 0;
pSRB->TotalXferredLen = 0;
pSRB->SGToBeXferLen = 0;
@@ -1140,8+1278,8 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
pSRB->Segmentx.length = pcmd->request_bufflen;
}
- if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
- RewaitSRB( pDCB, pSRB );
+ if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+ dc390_RewaitSRB( pDCB, pSRB );
return;
}
}
@@ -1149,6+1287,8 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) {
if( status == SCSI_STAT_CHECKCOND)
{
+ REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\
+ pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
{
bval = pSRB->SGcount;
@@ -1159,12+1299,10 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) swlval += ptr2->length;
ptr2++;
}
-#ifdef DC390_DEBUG0
- printk("XferredLen=%8x,NotXferLen=%8x,",
- (UINT) pSRB->TotalXferredLen, (UINT) swlval);
-#endif
+ REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\
+ (UINT) pSRB->TotalXferredLen, (UINT) swlval);)
}
- RequestSense( pACB, pDCB, pSRB );
+ dc390_RequestSense( pACB, pDCB, pSRB );
return;
}
else if( status == SCSI_STAT_QUEUEFULL )
@@ -1172,7+1310,7 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) bval = (UCHAR) pDCB->GoingSRBCnt;
bval--;
pDCB->MaxCommand = bval;
- RewaitSRB( pDCB, pSRB );
+ dc390_RewaitSRB( pDCB, pSRB );
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0;
return;
@@ -1182,12+1320,22 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) pSRB->AdaptStatus = H_SEL_TIMEOUT;
pSRB->TargetStatus = 0;
pcmd->result = DID_BAD_TARGET << 16;
+ /* Devices are removed below ... */
}
- else
+ else if (status == SCSI_STAT_BUSY &&
+ (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
+ pACB->scan_devices)
{
pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = status;
+ pcmd->result = (ULONG) (pSRB->EndMessage << 8)
+ /* | (ULONG) status */;
+ }
+ else
+ { /* Another error */
+ pSRB->AdaptStatus = 0;
if( pSRB->RetryCnt )
- {
+ { /* Retry */
pSRB->RetryCnt--;
pSRB->TargetStatus = 0;
pSRB->SGIndex = 0;
@@ -1201,19+1349,19 @@ SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
pSRB->Segmentx.length = pcmd->request_bufflen;
}
- if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
- RewaitSRB( pDCB, pSRB );
+ if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+ dc390_RewaitSRB( pDCB, pSRB );
return;
}
else
- {
+ { /* Report error */
pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
(ULONG) status;
}
}
}
else
- {
+ { /* Target status == 0 */
status = pSRB->AdaptStatus;
if(status & H_OVER_UNDER_RUN)
{
{
if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
{
- if(pcmd->result != (DID_OK << 16))
- {
- if( pcmd->result & SCSI_STAT_CHECKCOND )
- {
- goto RTN_OK;
- }
- else
- {
- pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
- if( (pcmd->target == pACB->max_id) &&
- ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
- {
- pACB->scan_devices = 0;
- }
- }
- }
- else
- {
-RTN_OK:
- pPrevDCB->pNextDCB = pDCB;
- pDCB->pNextDCB = pACB->pLinkDCB;
- if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
- pACB->scan_devices = END_SCAN;
- }
- }
- else if( pSRB->CmdBlock[0] == INQUIRY )
- {
- if( (pcmd->target == pACB->max_id) &&
- (pcmd->lun == pACB->max_lun) )
- {
- pACB->scan_devices = 0;
- }
- ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
- if( pcmd->use_sg )
- ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
- bval1 = ptr->DevType & SCSI_DEVTYPE;
- if(bval1 == SCSI_NODEV)
+#ifdef DC390_DEBUG0
+ printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
+ if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n",
+ pcmd->sense_buffer[0], pcmd->sense_buffer[1],
+ pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
+ else printk ("\n");
+#endif
+ if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
+ ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
+ (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16)
{
- pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
+ /* device not present: remove */
+ dc390_remove_dev (pACB, pDCB);
+
+ if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+ ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
+ pACB->scan_devices = 0;
}
else
{
- pACB->DeviceCnt++;
- pPrevDCB = pDCB;
- pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
- pDCB->DevType = bval1;
- if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
- {
- if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
- (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
- (pDCB->DevMode & TAG_QUEUING_) &&
- (pDCB->DevMode & EN_DISCONNECT_) )
- {
- disable_tag = 0;
- for(i=0; i<BADDEVCNT; i++)
- {
- for(j=0; j<28; j++)
- {
- if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
- break;
- }
- if(j == 28)
- {
- disable_tag = 1;
- break;
- }
- }
-
- if( !disable_tag )
- {
- pDCB->MaxCommand = pACB->TagMaxNum;
- pDCB->SyncMode |= EN_TAG_QUEUING;
- pDCB->TagMask = 0;
- }
- else
- {
- pDCB->SyncMode |= EN_ATN_STOP;
- }
- }
- }
+ /* device present: add */
+ if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+ (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+ pACB->scan_devices = END_SCAN ;
+ /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
}
}
}
-
- save_flags( flags );
- cli();
-/* ReleaseSRB( pDCB, pSRB ); */
+
+ if( pSRB->CmdBlock[0] == INQUIRY &&
+ (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) )
+ {
+ ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+ if( pcmd->use_sg )
+ ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+ if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV)
+ {
+ /* device not present: remove */
+ dc390_remove_dev (pACB, pDCB);
+ }
+ else
+ {
+ /* device found: add */
+ dc390_add_dev (pACB, pDCB, ptr);
+ if (pACB->scan_devices) pACB->DeviceCnt++;
+ }
+ if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
+ (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
+ pACB->scan_devices = 0;
+ };
+/* dc390_ReleaseSRB( pDCB, pSRB ); */
if(pSRB == pDCB->pGoingSRB )
{
pACB->pFreeSRB = pSRB;
pDCB->GoingSRBCnt--;
- DoWaitingSRB( pACB );
- restore_flags(flags);
+ dc390_DoWaitingSRB( pACB );
-/* Notify cmd done */
+ DC390_UNLOCK_ACB_NI;
pcmd->scsi_done( pcmd );
+ DC390_LOCK_ACB_NI;
if( pDCB->QIORBCnt )
- DoNextCmd( pACB, pDCB );
+ dc390_DoNextCmd( pACB, pDCB );
return;
}
-static void
-DoingSRB_Done( PACB pACB )
+/* Remove all SRBs and tell midlevel code DID_RESET */
+void
+dc390_DoingSRB_Done( PACB pACB )
{
- PDCB pDCB, pdcb;
- PSRB psrb, psrb2;
- USHORT cnt, i;
+ PDCB pDCB, pdcb;
+ PSRB psrb, psrb2;
+ UCHAR i;
PSCSICMD pcmd;
pDCB = pACB->pLinkDCB;
pdcb = pDCB;
+ if (! pdcb) return;
do
{
- cnt = pdcb->GoingSRBCnt;
psrb = pdcb->pGoingSRB;
- for( i=0; i<cnt; i++)
+ for( i=0; i<pdcb->GoingSRBCnt; i++)
{
psrb2 = psrb->pNextSRB;
pcmd = psrb->pcmd;
@@ -1381,63+1492,46 @@ DoingSRB_Done( PACB pACB ) psrb->pNextSRB = pACB->pFreeSRB;
pACB->pFreeSRB = psrb;
+ DC390_UNLOCK_ACB_NI;
pcmd->scsi_done( pcmd );
+ DC390_LOCK_ACB_NI;
psrb = psrb2;
}
pdcb->GoingSRBCnt = 0;;
pdcb->pGoingSRB = NULL;
pdcb->TagMask = 0;
pdcb = pdcb->pNextDCB;
- }
- while( pdcb != pDCB );
+ } while( pdcb != pDCB );
}
static void
-DC390_ResetSCSIBus( PACB pACB )
+dc390_ResetSCSIBus( PACB pACB )
{
- USHORT ioport;
- UCHAR bval;
- ULONG flags;
-
- save_flags(flags);
- cli();
pACB->ACBFlag |= RESET_DEV;
- ioport = pACB->IOPortBase;
- bval = DMA_IDLE_CMD;
- outb(bval,ioport+DMA_Cmd);
+ DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+ udelay (250);
+ DC390_write8 (ScsiCmd, NOP_CMD);
- bval = RST_SCSI_BUS_CMD;
- outb(bval,ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
- restore_flags(flags);
return;
}
-
static void
-DC390_ScsiRstDetect( PACB pACB )
+dc390_ScsiRstDetect( PACB pACB )
{
- ULONG wlval, flags;
- USHORT ioport;
- UCHAR bval;
-
-#ifdef DC390_DEBUG0
- printk("RST_DETEC");
-#endif
+ printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+ //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ /* Unlock before ? */
/* delay a second */
- mdelay(1000);
-
- save_flags(flags);
- cli();
-
- ioport = pACB->IOPortBase;
- bval = DMA_IDLE_CMD;
- outb(bval,ioport+DMA_Cmd);
- bval = CLEAR_FIFO_CMD;
- outb(bval,ioport+ScsiCmd);
+ { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
if( pACB->ACBFlag & RESET_DEV )
pACB->ACBFlag |= RESET_DONE;
@@ -1445,30+1539,32 @@ DC390_ScsiRstDetect( PACB pACB ) {
pACB->ACBFlag |= RESET_DETECT;
- ResetDevParam( pACB );
-/* DoingSRB_Done( pACB ); ???? */
- RecoverSRB( pACB );
+ dc390_ResetDevParam( pACB );
+/* dc390_DoingSRB_Done( pACB ); ???? */
+ dc390_RecoverSRB( pACB );
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
- DoWaitingSRB( pACB );
+ dc390_DoWaitingSRB( pACB );
}
- restore_flags(flags);
return;
}
-static void
-RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+static void __inline__
+dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
{
PSCSICMD pcmd;
+ REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
+ pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+
pSRB->SRBFlag |= AUTO_REQSENSE;
- pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
- pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+ pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
+ pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
pSRB->Segment1[1] = pSRB->TotalXferredLen;
pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
+ pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
pcmd = pSRB->pcmd;
@@ -1478,52+1574,40 @@ RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) pSRB->SGcount = 1;
pSRB->SGIndex = 0;
- *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+ pSRB->CmdBlock[0] = REQUEST_SENSE;
pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
- *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+ (USHORT) pSRB->CmdBlock[2] = 0;
+ (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
pSRB->ScsiCmdLen = 6;
pSRB->TotalXferredLen = 0;
pSRB->SGToBeXferLen = 0;
- if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
- RewaitSRB( pDCB, pSRB );
+ if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
+ dc390_RewaitSRB( pDCB, pSRB );
}
-static void
-EnableMsgOut2( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut2( PACB pACB, PSRB pSRB )
{
- USHORT ioport;
- UCHAR bval;
-
- ioport = pACB->IOPortBase;
pSRB->MsgCnt = 1;
- bval = SET_ATN_CMD;
- outb(bval, ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, SET_ATN_CMD);
}
-static void
-EnableMsgOut( PACB pACB, PSRB pSRB )
+static void __inline__
+dc390_EnableMsgOut( PACB pACB, PSRB pSRB )
{
pSRB->MsgOutBuf[0] = MSG_ABORT;
- EnableMsgOut2( pACB, pSRB );
+ dc390_EnableMsgOut2( pACB, pSRB );
+ pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
}
-static void
-DC390_InvalidCmd( PACB pACB )
+static void __inline__
+dc390_InvalidCmd( PACB pACB )
{
- UCHAR bval;
- USHORT ioport;
- PSRB pSRB;
-
- pSRB = pACB->pActiveDCB->pActiveSRB;
- if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
- {
- ioport = pACB->IOPortBase;
- bval = CLEAR_FIFO_CMD;
- outb(bval,(ioport+ScsiCmd));
- }
+ if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
}
* Bus Master Host Adapter *
* (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
***********************************************************************/
-/* Minor enhancements and bugfixes by *
+/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $ */
+/* Enhancements and bugfixes by *
* Kurt Garloff <K.Garloff@ping.de> *
***********************************************************************/
/* HISTORY: *
* *
* REV# DATE NAME DESCRIPTION *
- * 1.00 04/24/96 CLH First release *
- * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable *
+ * 1.00 96/04/24 CLH First release *
+ * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable *
* Device, scan all LUN. Support Pre2.0.10 *
- * 1.02 06/18/96 CLH Fixed bug of Command timeout ... *
- * 1.03 09/25/96 KG Added tmscsim_proc_info() *
- * 1.04 10/11/96 CLH Updating for support KV 2.0.x *
- * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)*
- * 1.06 10/25/96 KG Fixed module support *
- * 1.07 11/09/96 KG Fixed tmscsim_proc_info() *
- * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() *
- * 1.09 11/30/96 KG Added register the allocated IO space *
- * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
+ * 1.02 96/06/18 CLH Fixed bug of Command timeout ... *
+ * 1.03 96/09/25 KG Added tmscsim_proc_info() *
+ * 1.04 96/10/11 CLH Updating for support KV 2.0.x *
+ * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)*
+ * 1.06 96/10/25 KG Fixed module support *
+ * 1.07 96/11/09 KG Fixed tmscsim_proc_info() *
+ * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() *
+ * 1.09 96/11/30 KG Added register the allocated IO space *
+ * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset *
* pending interrupt in DC390_detect() *
- * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater *
- * than 1GB *
- * 1.12 15/02/98 MJ Rewritten PCI probing *
+ * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater *
+ * than 1GB *
+ * 1.12 98/02/15 MJ Rewritten PCI probing *
+ * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,*
+ * changed max devs from 10 to 16 *
+ * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev *
+ * for LUNs if LUN_SCAN (BIOS) not set *
+ * runtime config using /proc interface *
+ * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks *
+ * 1.14c 98/05/07 KG 2.0.x compatibility *
+ * 1.20a 98/05/07 KG changed names of funcs to be consistent *
+ * DC390_ (entry points), dc390_ (internal)*
+ * reworked locking *
+ * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp *
+ * debug output *
+ * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults *
+ * 1.20d 98/05/14 KG bugs: list linkage, clear flag after *
+ * reset on startup, code cleanup *
+ * 1.20e 98/05/15 KG spinlock comments, name space cleanup *
+ * pLastDCB now part of ACB structure *
+ * added stats, timeout for 2.1, TagQ bug *
+ * RESET and INQUIRY interface commands *
+ * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs *
+ * for missing LUNs, pending int *
+ * 1.20g 98/05/19 KG Clean up: Avoid short *
+ * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... *
+ * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask *
+ * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB *
+ * == 0 in remove_dev and DoingSRB_Done *
+ * 1.20k 98/05/25 KG DMA_INT (experimental) *
+ * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; *
+ * 1.20m 98/06/10 KG glitch configurable; made some global *
+ * vars part of ACB; use DC390_readX *
+ * 1.20n 98/06/11 KG startup params *
+ * 1.20o 98/06/15 KG added TagMaxNum to boot/module params *
+ * Device Nr -> Idx, TagMaxNum power of 2 *
+ * 1.20p 98/06/17 KG Docu updates. Reset depends on settings *
+ * pci_set_master added; 2.0.xx: pcibios_* *
+ * used instead of MechNum things ... *
+ * 1.20q 98/06/23 KG Changed defaults. Added debug code for *
+ * removable media and fixed it. TagMaxNum *
+ * fixed for DC390. Locking: ACB, DRV for *
+ * better IRQ sharing. Spelling: Queueing *
+ * Parsing and glitch_cfg changes. Display *
+ * real SyncSpeed value. Made DisConn *
+ * functional (!) *
+ * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set *
+ * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module *
+ * param -1 fixed. *
+ * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,*
+ * phys_to_bus instead of phys_to_virt, *
+ * fixed sel. process, fixed locking, *
+ * added MODULE_XXX infos, changed IRQ *
+ * request flags, disable DMA_INT *
+ * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;*
+ * initfunc -> __init; better abort; *
+ * Timeout for XFER_DONE & BLAST_COMPLETE; *
+ * Allow up to 33 commands being processed *
+ * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing *
+ * all flags. Clear within while() loops *
+ * in DataIn_0/Out_0. Null ptr in dumpinfo *
+ * for pSRB==0. Better locking during init.*
+ * bios_param() now respects part. table. *
+ * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. *
+ * Disallow illegal idx in INQUIRY/REMOVE *
***********************************************************************/
+/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
+#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */
-#define DC390_DEBUG
+/* DEBUG options */
+//#define DC390_DEBUG0
+//#define DC390_DEBUG1
+//#define DC390_DCBDEBUG
+//#define DC390_PARSEDEBUG
+//#define DC390_REMOVABLEDEBUG
-#define SCSI_MALLOC
+/* Debug definitions */
+#ifdef DC390_DEBUG0
+# define DEBUG0(x) x;
+#else
+# define DEBUG0(x)
+#endif
+#ifdef DC390_DEBUG1
+# define DEBUG1(x) x;
+#else
+# define DEBUG1(x)
+#endif
+#ifdef DC390_DCBDEBUG
+# define DCBDEBUG(x) x;
+#else
+# define DCBDEBUG(x)
+#endif
+#ifdef DC390_PARSEDEBUG
+# define PARSEDEBUG(x) x;
+#else
+# define PARSEDEBUG(x)
+#endif
+#ifdef DC390_REMOVABLEDEBUG
+# define REMOVABLEDEBUG(x) x;
+#else
+# define REMOVABLEDEBUG(x)
+#endif
+#define DCBDEBUG1(x)
+/* Includes */
#ifdef MODULE
# include <linux/module.h>
#endif
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/spinlock.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
+#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/config.h>
-#include <linux/init.h>
+#include <linux/version.h>
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
-#include "tmscsim.h"
#include "constants.h"
#include "sd.h"
#include <linux/stat.h>
#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
-struct proc_dir_entry proc_scsi_tmscsim ={
- PROC_SCSI_DC390T, 7 ,"tmscsim",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
- };
+/* Locking */
+
+/* Note: Starting from 2.1.9x, the mid-level scsi code issues a
+ * spinlock_irqsave (&io_request_lock) before calling the driver's
+ * routines, so we don't need to lock.
+ * TODO: Verify, if we are locked in every case!
+ * The policy 3, let the midlevel scsi code do the io_request_locks
+ * and us locking on a driver specific lock, shouldn't hurt anybody; it
+ * just causes a minor performance degradation for setting the locks.
+ */
+
+/* spinlock things
+ * level 3: lock on both adapter specific locks and (global) io_request_lock
+ * level 2: lock on adapter specific locks only
+ * level 1: rely on the locking of the mid level code (io_request_lock)
+ * undef : traditional save_flags; cli; restore_flags;
+ */
-static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
-
-static void SetXferRate( PACB pACB, PDCB pDCB );
-static void DC390_Disconnect( PACB pACB );
-static void DC390_Reselect( PACB pACB );
-static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void DoingSRB_Done( PACB pACB );
-static void DC390_ScsiRstDetect( PACB pACB );
-static void DC390_ResetSCSIBus( PACB pACB );
-static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void EnableMsgOut( PACB pACB, PSRB pSRB );
-static void DC390_InvalidCmd( PACB pACB );
-
-int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# include <linux/init.h>
+# include <asm/spinlock.h>
+#endif
+
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+# define USE_SPINLOCKS 1
+# define NEW_PCI 1
+#else
+# undef NEW_PCI
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# define USE_SPINLOCKS 2
+# endif
+#endif
+
+#ifdef USE_SPINLOCKS
+
+# if USE_SPINLOCKS == 3 /* both */
+
+# if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+# else
+# define DC390_LOCK_INIT
+# endif
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+
+# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+
+# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+# else
+
+# if USE_SPINLOCKS == 2 /* adapter specific locks */
+
+# if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+# else
+# define DC390_LOCK_INIT
+# endif
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS
+# define DC390_DFLAGS unsigned long dflags;
+# define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */
+# define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags)
+# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
+# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
+# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
+//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+
+# else /* USE_SPINLOCKS == 1: global lock io_request_lock */
+
+# define DC390_AFLAGS
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+ spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
+# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags)
+# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags)
+# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags)
+# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags)
+# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock)
+# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock)
+# define DC390_LOCK_ACB /* DC390_LOCK_IO */
+# define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
+# define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
+# define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
+# define DC390_LOCK_INIT /* DC390_LOCK_INIT */
+
+# endif /* 2 */
+# endif /* 3 */
+
+#else /* USE_SPINLOCKS undefined */
+
+# define DC390_AFLAGS unsigned long aflags;
+# define DC390_IFLAGS unsigned long iflags;
+# define DC390_DFLAGS unsigned long dflags;
+# define DC390_LOCK_IO save_flags (iflags); cli ()
+# define DC390_UNLOCK_IO restore_flags (iflags)
+# define DC390_LOCK_DRV save_flags (dflags); cli ()
+# define DC390_UNLOCK_DRV restore_flags (dflags)
+# define DC390_LOCK_DRV_NI
+# define DC390_UNLOCK_DRV_NI
+# define DC390_LOCK_ACB save_flags (aflags); cli ()
+# define DC390_UNLOCK_ACB restore_flags (aflags)
+# define DC390_LOCK_ACB_NI
+# define DC390_UNLOCK_ACB_NI
+# define DC390_LOCK_INIT
+#endif /* def */
+
+
+/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/
+
+#ifdef NEW_PCI
+# define PDEV pdev
+# define PDEVDECL struct pci_dev *pdev
+# define PDEVDECL0 struct pci_dev *pdev = NULL
+# define PDEVDECL1 struct pci_dev *pdev
+# define PDEVSET pACB->pdev=pdev
+# define PDEVSET1 pdev=pACB->pdev
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pdev->bus->number, pdev->devfn
+# define PCI_PRESENT pci_present ()
+# define PCI_SET_MASTER pci_set_master (pdev)
+# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
+# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+#else
+# include <linux/bios32.h>
+# define PDEV pbus, pdevfn
+# define PDEVDECL UCHAR pbus, UCHAR pdevfn
+# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error
+# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */
+# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */
+# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */
+# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv)
+# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv)
+# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv)
+# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv)
+# define PCI_BUS_DEV pbus, pdevfn
+# define PCI_PRESENT pcibios_present ()
+# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn)
+# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn))
+# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port); \
+ error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq); \
+ io_port &= 0xfffe; \
+ if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; }
+#endif
+
+#include "tmscsim.h"
+
+#ifndef __init
+# define __init
+#endif
+
+UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void dc390_SetXferRate( PACB pACB, PDCB pDCB );
+void dc390_Disconnect( PACB pACB );
+void dc390_Reselect( PACB pACB );
+void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+void dc390_DoingSRB_Done( PACB pACB );
+static void dc390_ScsiRstDetect( PACB pACB );
+static void dc390_ResetSCSIBus( PACB pACB );
+static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB );
+static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void dc390_remove_dev (PACB pACB, PDCB pDCB);
+void do_DC390_Interrupt( int, void *, struct pt_regs *);
+
+int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd );
+void dc390_updateDCB (PACB pACB, PDCB pDCB);
#ifdef MODULE
-static int DC390_release(struct Scsi_Host *host);
-static int DC390_shutdown (struct Scsi_Host *host);
+ static int DC390_release(struct Scsi_Host *host);
+ static int dc390_shutdown (struct Scsi_Host *host);
#endif
-static PSHT pSHT_start = NULL;
-static PSH pSH_start = NULL;
-static PSH pSH_current = NULL;
-static PACB pACB_start= NULL;
-static PACB pACB_current = NULL;
-static PDCB pPrevDCB = NULL;
-static USHORT adapterCnt = 0;
-static USHORT InitialTime = 0;
-static USHORT CurrSyncOffset = 0;
-
-static PVOID DC390_phase0[]={
- DC390_DataOut_0,
- DC390_DataIn_0,
- DC390_Command_0,
- DC390_Status_0,
- DC390_Nop_0,
- DC390_Nop_0,
- DC390_MsgOut_0,
- DC390_MsgIn_0,
- DC390_Nop_1
- };
+//static PSHT dc390_pSHT_start = NULL;
+//static PSH dc390_pSH_start = NULL;
+//static PSH dc390_pSH_current = NULL;
+static PACB dc390_pACB_start= NULL;
+static PACB dc390_pACB_current = NULL;
+static UCHAR dc390_adapterCnt = 0;
+static UCHAR dc390_CurrSyncOffset = 0;
+static ULONG dc390_lastabortedpid = 0;
+static ULONG dc390_laststatus = 0;
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+/* Startup values, to be overriden on the commandline */
+int tmscsim[] = {7, 1 /* 8MHz */,
+ PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
+ | SYNC_NEGO_ | TAG_QUEUEING_,
+ MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
+ /* | NO_SEEK */
+# ifdef CONFIG_SCSI_MULTI_LUN
+ | LUN_CHECK
+# endif
+ , 3 /* 16 Tags per LUN */};
+
+# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(tmscsim, "1-5i");
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)");
+# endif
+
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+#endif
-static PVOID DC390_phase1[]={
- DC390_DataOutPhase,
- DC390_DataInPhase,
- DC390_CommandPhase,
- DC390_StatusPhase,
- DC390_Nop_0,
- DC390_Nop_0,
- DC390_MsgOutPhase,
- DC390_MsgInPhase,
- DC390_Nop_1,
+static PVOID dc390_phase0[]={
+ dc390_DataOut_0,
+ dc390_DataIn_0,
+ dc390_Command_0,
+ dc390_Status_0,
+ dc390_Nop_0,
+ dc390_Nop_0,
+ dc390_MsgOut_0,
+ dc390_MsgIn_0,
+ dc390_Nop_1
};
-UCHAR eepromBuf[MAX_ADAPTER_NUM][128];
-
+static PVOID dc390_phase1[]={
+ dc390_DataOutPhase,
+ dc390_DataInPhase,
+ dc390_CommandPhase,
+ dc390_StatusPhase,
+ dc390_Nop_0,
+ dc390_Nop_0,
+ dc390_MsgOutPhase,
+ dc390_MsgInPhase,
+ dc390_Nop_1
+ };
-UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+#ifdef DC390_DEBUG1
+static char* dc390_p0_str[] = {
+ "dc390_DataOut_0",
+ "dc390_DataIn_0",
+ "dc390_Command_0",
+ "dc390_Status_0",
+ "dc390_Nop_0",
+ "dc390_Nop_0",
+ "dc390_MsgOut_0",
+ "dc390_MsgIn_0",
+ "dc390_Nop_1"
+ };
+
+static char* dc390_p1_str[] = {
+ "dc390_DataOutPhase",
+ "dc390_DataInPhase",
+ "dc390_CommandPhase",
+ "dc390_StatusPhase",
+ "dc390_Nop_0",
+ "dc390_Nop_0",
+ "dc390_MsgOutPhase",
+ "dc390_MsgInPhase",
+ "dc390_Nop_1"
+ };
+#endif
-UCHAR baddevname1[2][28] ={
+/* Devices erroneously pretending to be able to do TagQ */
+UCHAR dc390_baddevname1[2][28] ={
"SEAGATE ST3390N 9546",
"HP C3323-300 4269"};
-
#define BADDEVCNT 2
+static char* dc390_adapname = "DC390";
+UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+struct proc_dir_entry DC390_proc_scsi_tmscsim ={
+ PROC_SCSI_DC390T, 7 ,"tmscsim",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+ };
/***********************************************************************
*
*
*
**********************************************************************/
-static void
-QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
+{
+ PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0;
+ while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun)
+ {
+ pDCB = pDCB->pNextDCB;
+ if (pDCB == pACB->pLinkDCB)
+ {
+ printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+ (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
+ return 0;
+ }
+ };
+ DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \
+ (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+ return pDCB;
+};
+
+static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB )
{
- ULONG flags;
PSCSICMD pcmd;
- save_flags(flags);
- cli();
-
if( !pDCB->QIORBCnt )
{
pDCB->pQIORBhead = cmd;
@@ -185,83+524,61 @@ QLinkcmd( PSCSICMD cmd, PDCB pDCB ) cmd->next = NULL;
}
- restore_flags(flags);
}
-static PSCSICMD
-Getcmd( PDCB pDCB )
+static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB )
{
- ULONG flags;
PSCSICMD pcmd;
- save_flags(flags);
- cli();
-
pcmd = pDCB->pQIORBhead;
pDCB->pQIORBhead = pcmd->next;
pcmd->next = NULL;
pDCB->QIORBCnt--;
- restore_flags(flags);
return( pcmd );
}
-static PSRB
-GetSRB( PACB pACB )
+static __inline__ PSRB dc390_GetSRB( PACB pACB )
{
- ULONG flags;
PSRB pSRB;
- save_flags(flags);
- cli();
-
pSRB = pACB->pFreeSRB;
if( pSRB )
{
pACB->pFreeSRB = pSRB->pNextSRB;
pSRB->pNextSRB = NULL;
}
- restore_flags(flags);
+
return( pSRB );
}
-static void
-RewaitSRB0( PDCB pDCB, PSRB pSRB )
+static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB )
{
PSRB psrb1;
- ULONG flags;
-
- save_flags(flags);
- cli();
if( (psrb1 = pDCB->pWaitingSRB) )
{
pSRB->pNextSRB = psrb1;
- pDCB->pWaitingSRB = pSRB;
}
else
{
pSRB->pNextSRB = NULL;
- pDCB->pWaitingSRB = pSRB;
pDCB->pWaitLast = pSRB;
}
- restore_flags(flags);
+ pDCB->pWaitingSRB = pSRB;
}
-static void
-RewaitSRB( PDCB pDCB, PSRB pSRB )
+static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB )
{
PSRB psrb1;
- ULONG flags;
UCHAR bval;
- save_flags(flags);
- cli();
- pDCB->GoingSRBCnt--;
+ pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
+ DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
psrb1 = pDCB->pGoingSRB;
if( pSRB == psrb1 )
{
@@ -289,20+606,14 @@ RewaitSRB( PDCB pDCB, PSRB pSRB )
bval = pSRB->TagNumber;
pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */
- restore_flags(flags);
}
-static void
-DoWaitingSRB( PACB pACB )
+static void dc390_DoWaitingSRB( PACB pACB )
{
- ULONG flags;
PDCB ptr, ptr1;
PSRB pSRB;
- save_flags(flags);
- cli();
-
if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
{
ptr = pACB->pDCBRunRobin;
@@ -324,7+635,7 @@ DoWaitingSRB( PACB pACB ) }
else
{
- if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+ if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
{
ptr1->GoingSRBCnt++;
if( ptr1->pWaitLast == pSRB )
@@ -348,55+659,47 @@ DoWaitingSRB( PACB pACB ) }
}
}
- restore_flags(flags);
return;
}
-static void
-SRBwaiting( PDCB pDCB, PSRB pSRB)
+static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB)
{
if( pDCB->pWaitingSRB )
{
pDCB->pWaitLast->pNextSRB = pSRB;
- pDCB->pWaitLast = pSRB;
pSRB->pNextSRB = NULL;
}
else
{
pDCB->pWaitingSRB = pSRB;
- pDCB->pWaitLast = pSRB;
}
+ pDCB->pWaitLast = pSRB;
}
-static void
-SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+static void dc390_SendSRB( PACB pACB, PSRB pSRB )
{
- ULONG flags;
PDCB pDCB;
- save_flags(flags);
- cli();
-
pDCB = pSRB->pSRBDCB;
if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
{
- SRBwaiting(pDCB, pSRB);
+ dc390_SRBwaiting(pDCB, pSRB);
goto SND_EXIT;
}
if( pDCB->pWaitingSRB )
{
- SRBwaiting(pDCB, pSRB);
-/* pSRB = GetWaitingSRB(pDCB); */
+ dc390_SRBwaiting(pDCB, pSRB);
+/* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */
pSRB = pDCB->pWaitingSRB;
pDCB->pWaitingSRB = pSRB->pNextSRB;
pSRB->pNextSRB = NULL;
}
- if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+ if( !dc390_StartSCSI(pACB, pDCB, pSRB) )
{
pDCB->GoingSRBCnt++;
if( pDCB->pGoingSRB )
@@ -411,13+714,52 @@ SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) }
}
else
- RewaitSRB0( pDCB, pSRB );
+ dc390_RewaitSRB0( pDCB, pSRB );
SND_EXIT:
- restore_flags(flags);
return;
}
+static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
+{
+ pSRB->pSRBDCB = pDCB;
+ pSRB->pcmd = pcmd;
+ pSRB->ScsiCmdLen = pcmd->cmd_len;
+ memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
+
+ if( pcmd->use_sg )
+ {
+ pSRB->SGcount = (UCHAR) pcmd->use_sg;
+ pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+ }
+ else if( pcmd->request_buffer )
+ {
+ pSRB->SGcount = 1;
+ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+ pSRB->Segmentx.length = pcmd->request_bufflen;
+ }
+ else
+ pSRB->SGcount = 0;
+
+ pSRB->SGIndex = 0;
+ pSRB->AdaptStatus = 0;
+ pSRB->TargetStatus = 0;
+ pSRB->MsgCnt = 0;
+ if( pDCB->DevType != TYPE_TAPE )
+ pSRB->RetryCnt = 1;
+ else
+ pSRB->RetryCnt = 0;
+ pSRB->SRBStatus = 0;
+ pSRB->SRBFlag = 0;
+ pSRB->SRBState = 0;
+ pSRB->TotalXferredLen = 0;
+ pSRB->SGBusAddr = 0;
+ pSRB->SGToBeXferLen = 0;
+ pSRB->ScsiPhase = 0;
+ pSRB->EndMessage = 0;
+};
+
/***********************************************************************
* Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
@@ -425,241+767,220 @@ SND_EXIT: *
* Purpose : enqueues a SCSI command
*
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
+ * Inputs : cmd - SCSI command, done - callback function called on
+ * completion, with a pointer to the command descriptor.
*
- * Returns : 0
+ * Returns : (depending on kernel version)
+ * 2.0.x: always return 0
+ * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
+ * TO BE DONE:
+ * new model: return 0 if successful
+ * return 1 if command cannot be queued (queue full)
+ * command will be inserted in midlevel queue then ...
*
***********************************************************************/
-int
-DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
{
- USHORT ioport, i;
Scsi_Cmnd *pcmd;
- struct Scsi_Host *psh;
- PACB pACB;
PDCB pDCB;
PSRB pSRB;
- ULONG flags;
- PUCHAR ptr,ptr1;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
- psh = cmd->host;
- pACB = (PACB ) psh->hostdata;
- ioport = pACB->IOPortBase;
-#ifdef DC390_DEBUG0
-/* if(pACB->scan_devices) */
- printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
-#endif
+ DEBUG0(/* if(pACB->scan_devices) */ \
+ printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+ cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
+
+ DC390_LOCK_ACB;
+
+ /* Assume BAD_TARGET; will be cleared later */
+ cmd->result = DID_BAD_TARGET << 16;
+
+ /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY
+ * commands and alloc a DCB for the device if not yet there. DCB will
+ * be removed in dc390_SRBdone if SEL_TIMEOUT */
if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
- {
pACB->scan_devices = 0;
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
- }
- else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
- {
+
+ else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
pACB->scan_devices = 0;
- pPrevDCB->pNextDCB = pACB->pLinkDCB;
- }
- if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+ if ( ( cmd->target >= pACB->pScsiHost->max_id ) ||
+ (cmd->lun >= pACB->pScsiHost->max_lun) )
{
/* printk("DC390: Ignore target %d lun %d\n",
cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ DC390_UNLOCK_ACB;
done(cmd);
return( 0 );
}
- if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+ if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
{
- if( pACB->DeviceCnt < MAX_DEVICES )
- {
- pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
- pDCB = pACB->pDCB_free;
-#ifdef DC390_DEBUG0
- printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
- DC390_initDCB( pACB, pDCB, cmd );
- }
- else /* ???? */
- {
-/* printk("DC390: Ignore target %d lun %d\n",
- cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+ pACB->scan_devices = 1;
+
+ dc390_initDCB( pACB, &pDCB, cmd );
+ if (!pDCB)
+ {
+ printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target);
+ DC390_UNLOCK_ACB;
done(cmd);
return(0);
- }
+ };
+
}
else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
{
-/* printk("DC390: Ignore target %d lun %d\n",
- cmd->target, cmd->lun); */
- cmd->result = (DID_BAD_TARGET << 16);
+ printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
+ cmd->target, cmd->lun);
+ DC390_UNLOCK_ACB;
done(cmd);
return(0);
}
else
{
- pDCB = pACB->pLinkDCB;
- while( (pDCB->UnitSCSIID != cmd->target) ||
- (pDCB->UnitSCSILUN != cmd->lun) )
- {
- pDCB = pDCB->pNextDCB;
- }
-#ifdef DC390_DEBUG0
- printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
-#endif
+ pDCB = dc390_findDCB (pACB, cmd);
+ if (!pDCB)
+ { /* should never happen */
+ DC390_UNLOCK_ACB;
+ done(cmd);
+ return(0);
+ };
}
+ pACB->Cmds++;
cmd->scsi_done = done;
cmd->result = 0;
- save_flags(flags);
- cli();
-
- if( pDCB->QIORBCnt )
+ if( pDCB->QIORBCnt ) /* Unsent commands ? */
{
- QLinkcmd( cmd, pDCB );
- pcmd = Getcmd( pDCB );
+ dc390_QLinkcmd( cmd, pDCB );
+ pcmd = dc390_Getcmd( pDCB ); /* Get first command */
+ pACB->CmdInQ++;
}
else
pcmd = cmd;
- pSRB = GetSRB( pACB );
+ pSRB = dc390_GetSRB( pACB );
if( !pSRB )
{
- QLinkcmd( pcmd, pDCB );
- restore_flags(flags);
+ dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */
+ pACB->CmdOutOfSRB++;
+ DC390_UNLOCK_ACB;
return(0);
}
-/* BuildSRB(pSRB); */
-
- pSRB->pSRBDCB = pDCB;
- pSRB->pcmd = pcmd;
- ptr = (PUCHAR) pSRB->CmdBlock;
- ptr1 = (PUCHAR) pcmd->cmnd;
- pSRB->ScsiCmdLen = pcmd->cmd_len;
- for(i=0; i< pcmd->cmd_len; i++)
- {
- *ptr = *ptr1;
- ptr++;
- ptr1++;
- }
- if( pcmd->use_sg )
- {
- pSRB->SGcount = (UCHAR) pcmd->use_sg;
- pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
- }
- else if( pcmd->request_buffer )
- {
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
- pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
- pSRB->Segmentx.length = pcmd->request_bufflen;
- }
- else
- pSRB->SGcount = 0;
-
- pSRB->SGIndex = 0;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
- pSRB->MsgCnt = 0;
- if( pDCB->DevType != TYPE_TAPE )
- pSRB->RetryCnt = 1;
- else
- pSRB->RetryCnt = 0;
- pSRB->SRBStatus = 0;
- pSRB->SRBFlag = 0;
- pSRB->SRBState = 0;
- pSRB->TotalXferredLen = 0;
- pSRB->SGPhysAddr = 0;
- pSRB->SGToBeXferLen = 0;
- pSRB->ScsiPhase = 0;
- pSRB->EndMessage = 0;
- SendSRB( pcmd, pACB, pSRB );
+ dc390_BuildSRB (pcmd, pDCB, pSRB);
+ dc390_SendSRB( pACB, pSRB );
- restore_flags(flags);
+ DC390_UNLOCK_ACB;
+ DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);)
return(0);
}
-static void
-DoNextCmd( PACB pACB, PDCB pDCB )
+static void dc390_DoNextCmd( PACB pACB, PDCB pDCB )
{
Scsi_Cmnd *pcmd;
PSRB pSRB;
- ULONG flags;
- PUCHAR ptr,ptr1;
- USHORT i;
-
if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
return;
- save_flags(flags);
- cli();
- pcmd = Getcmd( pDCB );
- pSRB = GetSRB( pACB );
+ pcmd = dc390_Getcmd( pDCB );
+ pSRB = dc390_GetSRB( pACB );
if( !pSRB )
- {
- QLinkcmd( pcmd, pDCB );
- restore_flags(flags);
- return;
- }
-
- pSRB->pSRBDCB = pDCB;
- pSRB->pcmd = pcmd;
- ptr = (PUCHAR) pSRB->CmdBlock;
- ptr1 = (PUCHAR) pcmd->cmnd;
- pSRB->ScsiCmdLen = pcmd->cmd_len;
- for(i=0; i< pcmd->cmd_len; i++)
- {
- *ptr = *ptr1;
- ptr++;
- ptr1++;
- }
- if( pcmd->use_sg )
- {
- pSRB->SGcount = (UCHAR) pcmd->use_sg;
- pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
- }
- else if( pcmd->request_buffer )
- {
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
- pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
- pSRB->Segmentx.length = pcmd->request_bufflen;
- }
+ dc390_QLinkcmd( pcmd, pDCB );
else
- pSRB->SGcount = 0;
+ {
+ dc390_BuildSRB (pcmd, pDCB, pSRB);
+ dc390_SendSRB( pACB, pSRB );
+ };
+}
- pSRB->SGIndex = 0;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
- pSRB->MsgCnt = 0;
- if( pDCB->DevType != TYPE_TAPE )
- pSRB->RetryCnt = 1;
- else
- pSRB->RetryCnt = 0;
- pSRB->SRBStatus = 0;
- pSRB->SRBFlag = 0;
- pSRB->SRBState = 0;
- pSRB->TotalXferredLen = 0;
- pSRB->SGPhysAddr = 0;
- pSRB->SGToBeXferLen = 0;
- pSRB->ScsiPhase = 0;
- pSRB->EndMessage = 0;
- SendSRB( pcmd, pACB, pSRB );
+/* We ignore mapping problems, as we expect everybody to respect
+ * valid partition tables. Waiting for complaints ;-) */
- restore_flags(flags);
- return;
-}
+#ifdef CONFIG_SCSI_DC390T_TRADMAP
+/*
+ * The next function, partsize(), is copied from scsicam.c.
+ *
+ * This is ugly code duplication, but I didn't find another way to solve it:
+ * We want to respect the partition table and if it fails, we apply the
+ * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do
+ * the job, because we don't know, whether the values returned are from
+ * the part. table or determined by setsize(). Unfortunately the setsize()
+ * values differ from the ones chosen by the DC390 BIOS.
+ *
+ * Looking forward to seeing suggestions for a better solution! KG, 98/10/14
+ */
+#include <asm/unaligned.h>
+/*
+ * Function : static int partsize(struct buffer_head *bh, unsigned long
+ * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ * table, storing the results in *cyls, *hds, and *secs
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ */
+
+static int partsize(struct buffer_head *bh, unsigned long capacity,
+ unsigned int *cyls, unsigned int *hds, unsigned int *secs) {
+ struct partition *p, *largest = NULL;
+ int i, largest_cyl;
+ int cyl, ext_cyl, end_head, end_cyl, end_sector;
+ unsigned int logical_end, physical_end, ext_physical_end;
+
+
+ if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
+ for (largest_cyl = -1, p = (struct partition *)
+ (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+ if (!p->sys_ind)
+ continue;
+ cyl = p->cyl + ((p->sector & 0xc0) << 2);
+ if (cyl > largest_cyl) {
+ largest_cyl = cyl;
+ largest = p;
+ }
+ }
+ }
+
+ if (largest) {
+ end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+ end_head = largest->end_head;
+ end_sector = largest->end_sector & 0x3f;
+
+ physical_end = end_cyl * (end_head + 1) * end_sector +
+ end_head * end_sector + end_sector;
+
+ /* This is the actual _sector_ number at the end */
+ logical_end = get_unaligned(&largest->start_sect)
+ + get_unaligned(&largest->nr_sects);
+
+ /* This is for >1023 cylinders */
+ ext_cyl= (logical_end-(end_head * end_sector + end_sector))
+ /(end_head + 1) / end_sector;
+ ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+ end_head * end_sector + end_sector;
+
+ if ((logical_end == physical_end) ||
+ (end_cyl==1023 && ext_physical_end==logical_end)) {
+ *secs = end_sector;
+ *hds = end_head + 1;
+ *cyls = capacity / ((end_head + 1) * end_sector);
+ return 0;
+ }
+ }
+ return -1;
+}
/***********************************************************************
* Function:
@@ -667,30+988,84 @@ DoNextCmd( PACB pACB, PDCB pDCB ) *
* Description:
* Return the disk geometry for the given SCSI device.
+ * Respect the partition table, otherwise try own heuristic
+ *
+ * Note:
+ * In contrary to other externally callable funcs (DC390_), we don't lock
***********************************************************************/
-int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
{
int heads, sectors, cylinders;
- PACB pACB;
-
- pACB = (PACB) disk->device->host->hostdata;
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
+ PACB pACB = (PACB) disk->device->host->hostdata;
+ struct buffer_head *bh;
+ int ret_code = -1;
+ int size = disk->capacity;
- if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+ if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024)))
{
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (heads * sectors);
+ /* try to infer mapping from partition table */
+ ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2,
+ (unsigned int *) geom + 0, (unsigned int *) geom + 1);
+ brelse (bh);
}
+ if (ret_code == -1)
+ {
+ heads = 64;
+ sectors = 32;
+ cylinders = size / (heads * sectors);
+
+ if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = size / (heads * sectors);
+ }
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+ }
return (0);
}
+#else
+int DC390_bios_param (Disk *disk, kdev_t devno, int geom[])
+{
+ return scsicam_bios_param (disk, devno, geom);
+};
+#endif
+
+
+void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
+{
+ USHORT pstat; PDEVDECL1;
+
+ if (pSRB)
+ {
+ printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n",
+ pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
+ pSRB->ScsiPhase);
+ printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
+ };
+ printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus);
+ printk ("DC390: Register dump: SCSI block:\n");
+ printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
+ printk ("DC390: %06x %02x %02x %02x",
+ DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
+ DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
+ printk (" %02x %02x %02x %02x %02x %02x\n",
+ DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
+ DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+ printk ("DC390: Register dump: DMA engine:\n");
+ printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n");
+ printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n",
+ DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
+ DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
+ DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+ PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
+ printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
+ printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n");
+};
/***********************************************************************
@@ -703,35+1078,28 @@ int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]) * Returns : 0 on success, -1 on failure.
***********************************************************************/
-int
-DC390_abort (Scsi_Cmnd *cmd)
+int DC390_abort (Scsi_Cmnd *cmd)
{
- ULONG flags;
- PACB pACB;
- PDCB pDCB, pdcb;
+ PDCB pDCB;
PSRB pSRB, psrb;
- USHORT count, i;
+ ULONG count, i;
PSCSICMD pcmd, pcmd1;
int status;
+ ULONG sbac;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
+ DC390_LOCK_ACB;
-#ifdef DC390_DEBUG0
- printk("DC390 : Abort Cmd.");
-#endif
-
- save_flags(flags);
- cli();
+ pDCB = dc390_findDCB (pACB, cmd);
+ /* abort() is too buggy at the moment. If it's called we are in trouble anyway.
+ * so let's dump some info into the syslog at least. (KG, 98/08/20) */
+ if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0;
+ printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n",
+ cmd->pid, pDCB, pSRB);
+ dc390_dumpinfo (pACB, pDCB, pSRB);
- pACB = (PACB) cmd->host->hostdata;
- pDCB = pACB->pLinkDCB;
- pdcb = pDCB;
- while( (pDCB->UnitSCSIID != cmd->target) ||
- (pDCB->UnitSCSILUN != cmd->lun) )
- {
- pDCB = pDCB->pNextDCB;
- if( pDCB == pdcb )
- goto NOT_RUN;
- }
+ if( !pDCB ) goto NOT_RUN;
if( pDCB->QIORBCnt )
{
@@ -761,7+1129,12 @@ DC390_abort (Scsi_Cmnd *cmd) }
}
}
-
+
+ /* Added 98/07/02 KG */
+ pSRB = pDCB->pActiveSRB;
+ if (pSRB && pSRB->pcmd == cmd )
+ goto ON_GOING;
+
pSRB = pDCB->pWaitingSRB;
if( !pSRB )
goto ON_GOING;
@@ -778,7+1151,7 @@ DC390_abort (Scsi_Cmnd *cmd) while( psrb->pNextSRB->pcmd != cmd )
{
psrb = psrb->pNextSRB;
- if( !(psrb->pNextSRB) )
+ if( !(psrb->pNextSRB) || psrb == pSRB)
goto ON_GOING;
}
pSRB = psrb->pNextSRB;
@@ -795,6+1168,8 @@ IN_WAIT:
ON_GOING:
pSRB = pDCB->pGoingSRB;
+ pDCB->DCBFlag |= ABORT_DEV_;
+ /* Now for the hard part: The command is currently processed */
for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
{
if( pSRB->pcmd != cmd )
@@ -804,6+1179,8 @@ ON_GOING: if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
{
status = SCSI_ABORT_BUSY;
+ printk ("DC390: Abort current command (pid %li, SRB %p)\n",
+ cmd->pid, pSRB);
goto ABO_X;
}
else
@@ -819,20+1196,51 @@ NOT_RUN:
ABO_X:
cmd->result = DID_ABORT << 16;
+ printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status);
+ if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */
+ {
+ /* Let's do something to help the bus getting clean again */
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, DMA_COMMAND);
+ //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ //DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+ DC390_write8 (ScsiCmd, NOP_CMD);
+ //udelay (10000);
+ //DC390_read8 (INT_Status);
+ //DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+ };
+ sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ if (sbac & SCSI_BUSY)
+ { /* clear BSY, SEL and ATN */
+ printk (KERN_WARNING "DC390: Reset SCSI device: ");
+ //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES);
+ //udelay (250);
+ //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ //printk ("%08lx ", sbac);
+ //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM));
+ //udelay (100);
+ //sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ //printk ("%08lx ", sbac);
+ DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+ udelay (250);
+ DC390_write8 (ScsiCmd, NOP_CMD);
+ sbac = DC390_read32 (DMA_ScsiBusCtrl);
+ printk ("%08lx\n", sbac);
+ };
+ dc390_lastabortedpid = cmd->pid;
+ DC390_UNLOCK_ACB;
+ //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
cmd->scsi_done(cmd);
- restore_flags(flags);
return( status );
}
-static void
-ResetDevParam( PACB pACB )
+static void dc390_ResetDevParam( PACB pACB )
{
PDCB pDCB, pdcb;
pDCB = pACB->pLinkDCB;
- if( pDCB == NULL )
- return;
+ if (! pDCB) return;
pdcb = pDCB;
do
{
@@ -840,24+1248,22 @@ ResetDevParam( PACB pACB ) pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
pDCB->CtrlR3 = FAST_CLK;
- pDCB->CtrlR4 &= NEGATE_REQACKDATA;
- pDCB->CtrlR4 |= EATER_25NS;
+ pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
+ pDCB->CtrlR4 |= pACB->glitch_cfg;
pDCB = pDCB->pNextDCB;
}
while( pdcb != pDCB );
}
-static void
-RecoverSRB( PACB pACB )
+static void dc390_RecoverSRB( PACB pACB )
{
PDCB pDCB, pdcb;
PSRB psrb, psrb2;
- USHORT cnt, i;
+ ULONG cnt, i;
pDCB = pACB->pLinkDCB;
- if( pDCB == NULL )
- return;
+ if( !pDCB ) return;
pdcb = pDCB;
do
{
@@ -867,7+1273,7 @@ RecoverSRB( PACB pACB ) {
psrb2 = psrb;
psrb = psrb->pNextSRB;
-/* RewaitSRB( pDCB, psrb ); */
+/* dc390_RewaitSRB( pDCB, psrb ); */
if( pdcb->pWaitingSRB )
{
psrb2->pNextSRB = pdcb->pWaitingSRB;
@@ -884,8+1290,7 @@ RecoverSRB( PACB pACB ) pdcb->pGoingSRB = NULL;
pdcb->TagMask = 0;
pdcb = pdcb->pNextDCB;
- }
- while( pdcb != pDCB );
+ } while( pdcb != pDCB );
}
@@ -901,77+1306,80 @@ RecoverSRB( PACB pACB )
int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
{
- USHORT ioport;
- unsigned long flags;
- PACB pACB;
- UCHAR bval;
- USHORT i;
+ UCHAR bval;
+ ULONG i;
+ DC390_AFLAGS
+ PACB pACB = (PACB) cmd->host->hostdata;
+ printk(KERN_INFO "DC390: RESET ... ");
-#ifdef DC390_DEBUG1
- printk("DC390: RESET,");
-#endif
-
- pACB = (PACB ) cmd->host->hostdata;
- ioport = pACB->IOPortBase;
- save_flags(flags);
- cli();
- bval = inb(ioport+CtrlReg1);
+ DC390_LOCK_ACB;
+ bval = DC390_read8 (CtrlReg1);
bval |= DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* disable interrupt */
- DC390_ResetSCSIBus( pACB );
- for( i=0; i<500; i++ )
- mdelay(1);
- bval = inb(ioport+CtrlReg1);
- bval &= ~DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+ DC390_write8 (CtrlReg1, bval); /* disable interrupt */
+
+ dc390_ResetSCSIBus( pACB );
+ /* Unlock ? */
+ for( i=0; i<600; i++ )
+ udelay(1000);
- bval = DMA_IDLE_CMD;
- outb(bval,ioport+DMA_Cmd);
- bval = CLEAR_FIFO_CMD;
- outb(bval,ioport+ScsiCmd);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ DC390_read8 (INT_Status); /* Reset Pending INT */
- ResetDevParam( pACB );
- DoingSRB_Done( pACB );
+ dc390_ResetDevParam( pACB );
+ dc390_DoingSRB_Done( pACB );
+ /* dc390_RecoverSRB (pACB); */
pACB->pActiveDCB = NULL;
pACB->ACBFlag = 0;
- DoWaitingSRB( pACB );
+ bval = DC390_read8 (CtrlReg1);
+ bval &= ~DIS_INT_ON_SCSI_RST;
+ DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */
- restore_flags(flags);
-#ifdef DC390_DEBUG1
- printk("DC390: RESET1,");
-#endif
+ dc390_DoWaitingSRB( pACB );
+
+ DC390_UNLOCK_ACB;
+ printk("done\n");
return( SCSI_RESET_SUCCESS );
}
-
#include "scsiiom.c"
/***********************************************************************
- * Function : static void DC390_initDCB
+ * Function : static void dc390_initDCB
*
* Purpose : initialize the internal structures for a given DCB
*
* Inputs : cmd - pointer to this scsi cmd request block structure
*
***********************************************************************/
-void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
{
PEEprom prom;
- UCHAR bval;
- USHORT index;
-
- if( pACB->DeviceCnt == 0 )
+ UCHAR index;
+ PDCB pDCB;
+
+ pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
+ DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \
+ cmd->target, cmd->lun, (int)pDCB);)
+
+ *ppDCB = pDCB;
+ if (!pDCB) return;
+ if( pACB->DCBCnt == 0 )
{
pACB->pLinkDCB = pDCB;
pACB->pDCBRunRobin = pDCB;
- pDCB->pNextDCB = pDCB;
- pPrevDCB = pDCB;
}
else
- pPrevDCB->pNextDCB = pDCB;
+ {
+ pACB->pLastDCB->pNextDCB = pDCB;
+ };
+
+ pACB->DCBCnt++;
+
+ pACB->pLastDCB = pDCB;
+ pDCB->pNextDCB = pACB->pLinkDCB;
pDCB->pDCBACB = pACB;
pDCB->QIORBCnt = 0;
@@ -983,122+1391,143 @@ void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) pDCB->pActiveSRB = NULL;
pDCB->TagMask = 0;
pDCB->MaxCommand = 1;
- pDCB->AdaptIndex = pACB->AdapterIndex;
index = pACB->AdapterIndex;
pDCB->DCBFlag = 0;
- prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+ prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2];
pDCB->DevMode = prom->EE_MODE1;
- pDCB->AdpMode = eepromBuf[index][EE_MODE2];
-
- if( pDCB->DevMode & EN_DISCONNECT_ )
- bval = 0xC0;
- else
- bval = 0x80;
- bval |= cmd->lun;
- pDCB->IdentifyMsg = bval;
pDCB->SyncMode = 0;
- if( pDCB->DevMode & SYNC_NEGO_ )
- {
- if( !(cmd->lun) || CurrSyncOffset )
- pDCB->SyncMode = SYNC_ENABLE;
- }
+ dc390_updateDCB(pACB, pDCB);
pDCB->SyncPeriod = 0;
pDCB->SyncOffset = 0;
- pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
-
- pDCB->CtrlR1 = pACB->AdaptSCSIID;
- if( pDCB->DevMode & PARITY_CHK_ )
- pDCB->CtrlR1 |= PARITY_ERR_REPO;
+ pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
pDCB->CtrlR3 = FAST_CLK;
- pDCB->CtrlR4 = EATER_25NS;
- if( pDCB->AdpMode & ACTIVE_NEGATION)
- pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+ pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+ if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+ pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
}
+/***********************************************************************
+ * Function : static void dc390_updateDCB
+ *
+ * Purpose : Set the configuration dependent DCB parameters
+ *
+ ***********************************************************************/
+void dc390_updateDCB (PACB pACB, PDCB pDCB)
+{
+ pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
+
+ if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP;
+ else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP;
+
+ if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) )
+ pDCB->SyncMode |= SYNC_ENABLE;
+ else
+ {
+ pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE);
+ pDCB->SyncOffset &= ~0x0f;
+ };
+
+ if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP;
+
+ pDCB->CtrlR1 = pACB->pScsiHost->this_id;
+ if( pDCB->DevMode & PARITY_CHK_ )
+ pDCB->CtrlR1 |= PARITY_ERR_REPO;
+};
+
/***********************************************************************
- * Function : static void DC390_initSRB
+ * Function : static void dc390_updateDCBs
+ *
+ * Purpose : Set the configuration dependent DCB params for all DCBs
+ *
+ ***********************************************************************/
+static void dc390_updateDCBs (PACB pACB)
+{
+ int i;
+ PDCB pDCB = pACB->pLinkDCB;
+ for (i = 0; i < pACB->DeviceCnt; i++)
+ {
+ dc390_updateDCB (pACB, pDCB);
+ pDCB = pDCB->pNextDCB;
+ };
+};
+
+
+/***********************************************************************
+ * Function : static void dc390_initSRB
*
* Purpose : initialize the internal structures for a given SRB
*
* Inputs : psrb - pointer to this scsi request block structure
*
***********************************************************************/
-void DC390_initSRB( PSRB psrb )
+static void __inline__ dc390_initSRB( PSRB psrb )
{
-#ifdef DC390_DEBUG0
- printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
-#endif
- psrb->PhysSRB = virt_to_bus( psrb );
+ /* psrb->PhysSRB = virt_to_phys( psrb ); */
}
-void DC390_linkSRB( PACB pACB )
+void dc390_linkSRB( PACB pACB )
{
- USHORT count, i;
- PSRB psrb;
+ ULONG count, i;
count = pACB->SRBCount;
-
for( i=0; i< count; i++)
{
if( i != count - 1)
pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
else
pACB->SRB_array[i].pNextSRB = NULL;
- psrb = (PSRB) &pACB->SRB_array[i];
- DC390_initSRB( psrb );
+ dc390_initSRB( &pACB->SRB_array[i] );
}
}
/***********************************************************************
- * Function : static void DC390_initACB
+ * Function : static void dc390_initACB
*
* Purpose : initialize the internal structures for a given SCSI host
*
* Inputs : psh - pointer to this host adapter's structure
*
***********************************************************************/
-__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ))
+void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
{
PACB pACB;
- USHORT i;
+ UCHAR i;
+ DC390_AFLAGS
psh->can_queue = MAX_CMD_QUEUE;
psh->cmd_per_lun = MAX_CMD_PER_LUN;
- psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+ psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
psh->io_port = io_port;
psh->n_io_port = 0x80;
psh->irq = Irq;
pACB = (PACB) psh->hostdata;
+ DC390_LOCK_INIT;
+ DC390_LOCK_ACB;
+ pACB->pScsiHost = psh;
+ pACB->IOPortBase = (USHORT) io_port;
+ pACB->IRQLevel = Irq;
+
+ DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n", \
+ index, psh->this_id, (int)io_port, Irq);)
+
psh->max_id = 8;
-#ifdef CONFIG_SCSI_MULTI_LUN
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+
+ if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] )
+ psh->max_id--;
+ psh->max_lun = 1;
+ if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK )
psh->max_lun = 8;
- else
-#endif
- psh->max_lun = 1;
-
- pACB->max_id = 7;
- if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
- pACB->max_id--;
-#ifdef CONFIG_SCSI_MULTI_LUN
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
- pACB->max_lun = 7;
- else
-#endif
- pACB->max_lun = 0;
- pACB->pScsiHost = psh;
- pACB->IOPortBase = (USHORT) io_port;
pACB->pLinkDCB = NULL;
pACB->pDCBRunRobin = NULL;
pACB->pActiveDCB = NULL;
@@ -1106,42+1535,39 @@ __initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ) pACB->SRBCount = MAX_SRB_CNT;
pACB->AdapterIndex = index;
pACB->status = 0;
- pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
- pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
- pACB->AdaptSCSILUN = 0;
+ psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
pACB->DeviceCnt = 0;
- pACB->IRQLevel = Irq;
- pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+ pACB->DCBCnt = 0;
+ pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
pACB->ACBFlag = 0;
pACB->scan_devices = 1;
- pACB->Gmode2 = eepromBuf[index][EE_MODE2];
- if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
- pACB->LUNchk = 1;
- pACB->pDCB_free = &pACB->DCB_array[0];
- DC390_linkSRB( pACB );
+ pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
+ dc390_linkSRB( pACB );
pACB->pTmpSRB = &pACB->TmpSRB;
- DC390_initSRB( pACB->pTmpSRB );
+ dc390_initSRB( pACB->pTmpSRB );
for(i=0; i<MAX_SCSI_ID; i++)
pACB->DCBmap[i] = 0;
+ pACB->sel_timeout = SEL_TIMEOUT;
+ pACB->glitch_cfg = EATER_25NS;
+ pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0;
}
/***********************************************************************
- * Function : static int DC390_initAdapter
+ * Function : static int dc390_initAdapter
*
* Purpose : initialize the SCSI chip ctrl registers
*
* Inputs : psh - pointer to this host adapter's structure
*
***********************************************************************/
-__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index))
+int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
{
- USHORT ioport;
- UCHAR bval;
PACB pACB, pacb;
- USHORT used_irq = 0;
+ UCHAR used_irq = 0, dstate;
+ int i;
- pacb = pACB_start;
+ pacb = dc390_pACB_start;
if( pacb != NULL )
{
for ( ; (pacb != (PACB) -1) ; )
@@ -1158,49+1584,54 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
if( !used_irq )
{
- if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
+ if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) ))
+ {
+ printk(KERN_ERR "DC390: register IRQ error!\n");
+ return( -1 );
+ }
+ }
+
+ if (check_region (io_port, psh->n_io_port))
{
- printk("DC390: register IRQ error!\n");
+ printk(KERN_ERR "DC390: register IO ports error!\n");
return( -1 );
}
- }
-
- request_region(io_port,psh->n_io_port,"tmscsim");
-
- ioport = (USHORT) io_port;
-
+ else
+ request_region (io_port, psh->n_io_port, "tmscsim");
+
pACB = (PACB) psh->hostdata;
- bval = SEL_TIMEOUT; /* 250ms selection timeout */
- outb(bval,ioport+Scsi_TimeOut);
-
- bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */
- outb(bval,ioport+Clk_Factor);
-
- bval = NOP_CMD; /* NOP cmd - clear command register */
- outb(bval,ioport+ScsiCmd);
+ /* pACB->IOPortBase = (USHORT) io_port; */
- bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */
- outb(bval,ioport+CtrlReg2);
+ DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port); /* Disable SCSI bus reset interrupt */
- bval = FAST_CLK; /* fast clock */
- outb(bval,ioport+CtrlReg3);
-
- bval = EATER_25NS;
- if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
- bval |= NEGATE_REQACKDATA;
- outb(bval,ioport+CtrlReg4);
-
- bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */
- outb(bval,ioport+CtrlReg1);
+ if (pACB->Gmode2 & RST_SCSI_BUS)
+ {
+ dc390_ResetSCSIBus( pACB );
+ /* Unlock before ? */
+ for( i=0; i<600; i++ )
+ udelay(1000);
+ };
+ pACB->ACBFlag = 0;
+
+ DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT); /* 250ms selection timeout */
+ DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ); /* Conversion factor = 0 , 40MHz clock */
+ DC390_write8 (ScsiCmd, NOP_CMD); /* NOP cmd - clear command register */
+ DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD); /* Enable Feature and SCSI-2 */
+ DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */
+ DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */
+ (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+ DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+ dstate = DC390_read8 (DMA_Status);
+ DC390_write8 (DMA_Status, dstate); /* clear */
return(0);
}
-void
-DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval )
+static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )
{
-
UCHAR bval;
bval = 0;
@@ -1208,15+1639,68 @@ DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval ) *regval = 0xc0;
else
*regval = 0x80;
- pci_write_config_byte(pdev, *regval, bval);
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
if(mode == DISABLE_CE)
- pci_write_config_byte(pdev, *regval, bval);
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
udelay(160);
}
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+static void __init dc390_EEpromDefaults (UCHAR index)
+{
+ PUCHAR ptr;
+ UCHAR id;
+ ptr = (PUCHAR) dc390_eepromBuf[index];
+
+ /* Adapter Settings */
+ ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
+ ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+ ptr[EE_DELAY] = 0; /* ?? */
+ ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+
+ /* Device Settings */
+ for (id = 0; id < MAX_SCSI_ID; id++)
+ {
+ ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
+ ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+ };
+ dc390_adapname = "AM53C974";
+}
-void
-DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry )
+static void __init dc390_checkparams (void)
+{
+ PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
+ tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
+ if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+ {
+ tmscsim[0] = 7; tmscsim[1] = 4;
+ tmscsim[2] = 9; tmscsim[3] = 15;
+ tmscsim[4] = 2;
+ printk (KERN_INFO "DC390: Using safe settings.\n");
+ }
+ else
+ {
+ /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
+ if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
+ if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
+ };
+};
+/* Override defaults on cmdline:
+ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
+ */
+void __init dc390_setup (char *str, int *ints)
+{
+ int i;
+ for (i = 0; i < ints[0]; i++)
+ tmscsim[i] = ints[i+1];
+ if (ints[0] > 5)
+ printk (KERN_NOTICE "DC390: ignore extra params!\n");
+ /* dc390_checkparams (); */
+};
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+
+static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
{
UCHAR bval;
@@ -1225,28+1709,27 @@ DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry ) {
bval = 0x40;
*regval = 0x80;
- pci_write_config_byte(pdev, *regval, bval);
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
}
udelay(160);
bval |= 0x80;
- pci_write_config_byte(pdev, *regval, bval);
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
udelay(160);
bval = 0;
- pci_write_config_byte(pdev, *regval, bval);
+ PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
udelay(160);
}
-UCHAR
-DC390_EEpromInDO( struct pci_dev *pdev )
+static UCHAR __init dc390_EEpromInDO( PDEVDECL )
{
UCHAR bval;
- pci_write_config_byte(pdev, 0x80, 0x80);
+ PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
udelay(160);
- pci_write_config_byte(pdev, 0x80, 0x40);
+ PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
udelay(160);
- pci_read_config_byte(pdev, 0x00, &bval);
+ PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
if(bval == 0x22)
return(1);
else
@@ -1254,8+1737,7 @@ DC390_EEpromInDO( struct pci_dev *pdev ) }
-USHORT
-EEpromGetData1( struct pci_dev *pdev )
+static USHORT __init dc390_EEpromGetData1( PDEVDECL )
{
UCHAR i;
UCHAR carryFlag;
@@ -1265,67+1747,59 @@ EEpromGetData1( struct pci_dev *pdev ) for(i=0; i<16; i++)
{
wval <<= 1;
- carryFlag = DC390_EEpromInDO(pdev);
+ carryFlag = dc390_EEpromInDO(PDEV);
wval |= carryFlag;
}
return(wval);
}
-void
-DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd )
+static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
{
UCHAR i,j;
- USHORT carryFlag;
+ UCHAR carryFlag;
carryFlag = 1;
j = 0x80;
for(i=0; i<9; i++)
{
- DC390_EEpromOutDI(pdev,regval,carryFlag);
+ dc390_EEpromOutDI(PDEV,regval,carryFlag);
carryFlag = (EEpromCmd & j) ? 1 : 0;
j >>= 1;
}
}
-void
-DC390_ReadEEprom( struct pci_dev *pdev, int index )
+static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
{
UCHAR regval,cmd;
- PUSHORT ptr;
- USHORT i;
+ UCHAR i;
- ptr = (PUSHORT) &eepromBuf[index][0];
cmd = EEPROM_READ;
for(i=0; i<0x40; i++)
{
- DC390_EnDisableCE(ENABLE_CE, pdev, ®val);
- DC390_Prepare(pdev, ®val, cmd);
- *ptr = EEpromGetData1(pdev);
- ptr++;
- cmd++;
- DC390_EnDisableCE(DISABLE_CE, pdev, ®val);
+ dc390_EnDisableCE(ENABLE_CE, PDEV, ®val);
+ dc390_Prepare(PDEV, ®val, cmd++);
+ *ptr++ = dc390_EEpromGetData1(PDEV);
+ dc390_EnDisableCE(DISABLE_CE, PDEV, ®val);
}
}
-USHORT
-DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index )
+static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
{
- USHORT wval, rc, *ptr;
UCHAR i;
+ char EEbuf[128];
+ USHORT wval, *ptr = (PUSHORT)EEbuf;
- DC390_ReadEEprom( pdev, index );
+ dc390_ReadEEprom( PDEV, ptr );
+ memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+ memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID],
+ &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
wval = 0;
- ptr = (PUSHORT) &eepromBuf[index][0];
- for(i=0; i<128 ;i+=2, ptr++)
+ for(i=0; i<0x40; i++, ptr++)
wval += *ptr;
- if( wval == 0x1234 )
- rc = 0;
- else
- rc = -1;
- return( rc );
+ return (wval == 0x1234 ? 0 : 1);
}
@@ -1338,71+1812,95 @@ DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index ) *
* Preconditions : when this function is called, the chip_type
* field of the pACB structure MUST have been set.
+ *
+ * Note: written in capitals, because the locking is only done here,
+ * not in DC390_detect, called from outside
***********************************************************************/
-__initfunc(static int
-DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index))
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index)
{
PSH psh;
PACB pACB;
-
- if( !DC390_CheckEEpromCheckSum( pdev, index ) )
+ DC390_AFLAGS
+
+ if (dc390_CheckEEpromCheckSum (PDEV, index))
{
- psh = scsi_register( psht, sizeof(DC390_ACB) );
- if( !psh )
- return( -1 );
- if( !pSH_start )
- {
- pSH_start = psh;
- pSH_current = psh;
- }
- else
- {
- pSH_current->next = psh;
- pSH_current = psh;
- }
+#ifdef CONFIG_SCSI_DC390T_NOGENSUPP
+ printk (KERN_ERR "DC390_init: No EEPROM found!\n");
+ return( -1 );
+#else
+ int period;
+ printk (KERN_INFO "DC390_init: No EEPROM found!\n");
+ printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n");
+ dc390_checkparams ();
+ period = dc390_clock_period1[tmscsim[1]];
+ printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz),"
+ " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1],
+ 40 / period, ((40%period)*10 + period/2) / period,
+ (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]));
+ dc390_EEpromDefaults (index);
+#endif
+ };
+
+ psh = scsi_register( psht, sizeof(DC390_ACB) );
+ if( !psh ) return( -1 );
+
+ pACB = (PACB) psh->hostdata;
+ DC390_LOCK_INIT;
+ DC390_LOCK_ACB;
-#ifdef DC390_DEBUG0
- printk("DC390: pSH = %8x,", (UINT) psh);
- printk("DC390: Index %02i,", index);
+#if 0
+ if( !dc390_pSH_start )
+ {
+ dc390_pSH_start = psh;
+ dc390_pSH_current = psh;
+ }
+ else
+ {
+ dc390_pSH_current->next = psh;
+ dc390_pSH_current = psh;
+ }
#endif
- DC390_initACB( psh, io_port, Irq, index );
- if( !DC390_initAdapter( psh, io_port, Irq, index ) )
- {
- pACB = (PACB) psh->hostdata;
- if( !pACB_start )
- {
- pACB_start = pACB;
- pACB_current = pACB;
- pACB->pNextACB = (PACB) -1;
- }
- else
- {
- pACB_current->pNextACB = pACB;
- pACB_current = pACB;
- pACB->pNextACB = (PACB) -1;
- }
+ DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);)
+ DEBUG0(printk("DC390: Index %02i,", index);)
-#ifdef DC390_DEBUG0
- printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
- (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
- printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
- sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
-#endif
+ dc390_initACB( psh, io_port, Irq, index );
+ PDEVSET;
+
+ DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */
+ if( !dc390_initAdapter( psh, io_port, Irq, index ) )
+ {
+ pACB = (PACB) psh->hostdata;
+ if( !dc390_pACB_start )
+ {
+ dc390_pACB_start = pACB;
+ dc390_pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
}
else
{
- pSH_start = NULL;
- scsi_unregister( psh );
- return( -1 );
+ dc390_pACB_current->pNextACB = pACB;
+ dc390_pACB_current = pACB;
+ pACB->pNextACB = (PACB) -1;
}
- return( 0 );
+
+ DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+ (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
+ DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
+ sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
+
+ DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */
+
+ DC390_UNLOCK_ACB;
+ return (0);
}
else
{
- printk("DC390_init: EEPROM reading error!\n");
+ //dc390_pSH_start = NULL;
+ scsi_unregister( psh );
+ DC390_UNLOCK_ACB;
return( -1 );
}
}
@@ -1421,54+1919,437 @@ DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index *
***********************************************************************/
-__initfunc(int
-DC390_detect(Scsi_Host_Template *psht))
+#ifndef NEW_PCI
+/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering:
+ * We use pci_set_master () for 2.1.x and this func for 2.0.x: */
+static void __init dc390_set_master (PDEVDECL)
{
- struct pci_dev *pdev = NULL;
- UINT irq;
- UINT io_port;
- USHORT adaptCnt = 0; /* Number of boards detected */
+ USHORT cmd;
+ UCHAR lat;
+
+ PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+
+ if (! (cmd & PCI_COMMAND_MASTER)) {
+ printk("PCI: Enabling bus mastering for device %02x:%02x\n",
+ PCI_BUS_DEV);
+ cmd |= PCI_COMMAND_MASTER;
+ PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd);
+ }
+ PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16 /* || lat == 255 */) {
+ printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n",
+ PCI_BUS_DEV, lat);
+ PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64);
+ }
+
+};
+#endif /* ! NEW_PCI */
- psht->proc_dir = &proc_scsi_tmscsim;
+static void __init dc390_set_pci_cfg (PDEVDECL)
+{
+ USHORT cmd;
+ PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
+ PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd);
+ PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
+};
+
+
+int __init DC390_detect (Scsi_Host_Template *psht)
+{
+ PDEVDECL0;
+ UCHAR irq;
+ UINT io_port;
+ UCHAR adaptCnt = 0; /* Number of boards detected */
+ DC390_IFLAGS DC390_DFLAGS
- InitialTime = 1;
- pSHT_start = psht;
- pACB_start = NULL;
+ DC390_LOCK_DRV;
+ //dc390_pSHT_start = psht;
+ dc390_pACB_start = NULL;
- if ( pci_present() )
- while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
+ if ( PCI_PRESENT )
+ while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
{
- io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
- irq = pdev->irq;
-#ifdef DC390_DEBUG0
- printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
-#endif
- if( !DC390_init(psht, io_port, irq, pdev, adaptCnt))
+ DC390_LOCK_IO; /* Remove this when going to new eh */
+ PCI_GET_IO_AND_IRQ;
+ DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);)
+
+ if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt))
+ {
+ PCI_SET_MASTER;
+ dc390_set_pci_cfg (PDEV);
adaptCnt++;
+ };
+ DC390_UNLOCK_IO; /* Remove when going to new eh */
}
-
- InitialTime = 0;
- adapterCnt = adaptCnt;
+ else
+ printk (KERN_ERR "DC390: No PCI BIOS found!\n");
+
+ if (adaptCnt)
+ psht->proc_dir = &DC390_proc_scsi_tmscsim;
+
+ printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt);
+ dc390_adapterCnt = adaptCnt;
+ DC390_UNLOCK_DRV;
return( adaptCnt );
}
+static void dc390_inquiry_done (Scsi_Cmnd* cmd)
+{
+ printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
+ cmd->target, cmd->lun, cmd->result);
+ if (cmd->result)
+ {
+ PACB pACB = (PACB)cmd->host->hostdata;
+ PDCB pDCB = dc390_findDCB (pACB, cmd);
+ printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
+ if (pDCB)
+ {
+ pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ );
+ dc390_updateDCB (pACB, pDCB);
+ };
+ };
+ kfree (cmd->buffer);
+ kfree (cmd);
+};
+
+void dc390_inquiry (PACB pACB, PDCB pDCB)
+{
+ char* buffer;
+ Scsi_Cmnd* cmd;
+ buffer = kmalloc (256, GFP_ATOMIC);
+ cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC);
+
+ memset (buffer, 0, 256);
+ memset (cmd, 0, sizeof(Scsi_Cmnd));
+ cmd->cmnd[0] = INQUIRY;
+ cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0;
+ cmd->cmnd[4] = 0xff;
+
+ cmd->cmd_len = 6; cmd->old_cmd_len = 6;
+ cmd->host = pACB->pScsiHost;
+ cmd->target = pDCB->UnitSCSIID;
+ cmd->lun = pDCB->UnitSCSILUN;
+ cmd->serial_number = 1;
+ cmd->bufflen = 128;
+ cmd->buffer = buffer;
+ cmd->request_bufflen = 128;
+ cmd->request_buffer = &buffer[128];
+ cmd->done = dc390_inquiry_done;
+ cmd->scsi_done = dc390_inquiry_done;
+ cmd->timeout_per_command = HZ;
+
+ cmd->request.rq_status = RQ_SCSI_BUSY;
+
+ printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ DC390_queue_command (cmd, dc390_inquiry_done);
+};
+
/********************************************************************
- * Function: tmscsim_set_info()
- *
- * Purpose: Set adapter info (!)
+ * Function: dc390_set_info()
*
- * Not yet implemented
+ * Purpose: Change adapter config
*
+ * Strings are parsed similar to the output of tmscsim_proc_info ()
+ * '-' means no change
*******************************************************************/
-int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+static int dc390_scanf (char** p1, char** p2, int* var)
+{
+ *p2 = *p1;
+ *var = simple_strtoul (*p2, p1, 10);
+ if (*p2 == *p1) return -1;
+ *p1 = strtok (0, " \t\n:=,;.");
+ return 0;
+};
+
+#define SCANF(p1, p2, var, min, max) \
+if (dc390_scanf (&p1, &p2, &var)) goto einv; \
+else if (var<min || var>max) goto einv2
+
+static int dc390_yesno (char** p, char* var, char bmask)
+{
+ switch (**p)
+ {
+ case 'Y': *var |= bmask; break;
+ case 'N': *var &= ~bmask; break;
+ case '-': break;
+ default: return -1;
+ }
+ *p = strtok (0, " \t\n:=,;");
+ return 0;
+};
+
+#define YESNO(p, var, bmask) \
+if (dc390_yesno (&p, &var, bmask)) goto einv; \
+else dc390_updateDCB (pACB, pDCB); \
+if (!p) goto ok
+
+static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
{
- return(-ENOSYS); /* Currently this is a no-op */
+ int dum;
+ if (! memcmp (*p1, txt, strlen(txt)))
+ {
+ *p2 = strtok (0, " \t\n:=,;");
+ if (!*p2) return -1;
+ dum = simple_strtoul (*p2, p1, 10);
+ if (*p2 == *p1) return -1;
+ if (dum >= 0 && dum <= max)
+ { *var = (dum * 100) / scale; }
+ else return -2;
+ *p1 = strtok (0, " \t\n:=,;");
+ if (*ign && *p1 && strlen(*p1) >= strlen(ign) &&
+ !(memcmp (*p1, ign, strlen(ign))))
+ *p1 = strtok (0, " \t\n:=,;");
+
+ }
+ return 0;
+};
+
+#define SEARCH(p1, p2, var, txt, max) \
+if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \
+else if (!p1) goto ok2
+
+#define SEARCH2(p1, p2, var, txt, max, scale) \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \
+else if (!p1) goto ok2
+
+#define SEARCH3(p1, p2, var, txt, max, scale, ign) \
+if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \
+else if (!p1) goto ok2
+
+
+#ifdef DC390_PARSEDEBUG
+static char _prstr[256];
+char* prstr (char* p, char* e)
+{
+ char* c = _prstr;
+ while (p < e)
+ if (*p == 0) { *c++ = ':'; p++; }
+ else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
+ else *c++ = *p++;
+ *c = 0;
+ return _prstr;
+};
+#endif
+
+int dc390_set_info (char *buffer, int length, PACB pACB)
+{
+ char *pos = buffer, *p0 = buffer;
+ char needs_inquiry = 0;
+ int dum = 0;
+ char dev;
+ PDCB pDCB = pACB->pLinkDCB;
+ DC390_IFLAGS
+ DC390_AFLAGS
+ pos[length] = 0;
+
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
+ /* UPPERCASE */
+ /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
+ while (*pos)
+ { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
+
+ /* We should protect __strtok ! */
+ /* spin_lock (strtok_lock); */
+
+ /* Remove WS */
+ pos = strtok (buffer, " \t:\n=,;");
+ if (!pos) goto ok;
+
+ next:
+ if (!memcmp (pos, "RESET", 5)) goto reset;
+ else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
+ else if (!memcmp (pos, "REMOVE", 6)) goto remove;
+
+ if (isdigit (*pos))
+ {
+ /* Device config line */
+ int dev, id, lun; char* pdec;
+ char olddevmode;
+
+ SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
+ if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+ if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+ if (!pos) goto einv;
+
+ PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
+ pDCB = pACB->pLinkDCB;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ /* Sanity Check */
+ if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun)
+ {
+ printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
+ dev, id, lun);
+ goto einv2;
+ };
+
+ olddevmode = pDCB->DevMode;
+ YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+ if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+ if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
+ YESNO (pos, pDCB->DevMode, SEND_START_);
+ needs_inquiry++;
+ YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+ if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
+ YESNO (pos, pDCB->SyncMode, EN_ATN_STOP);
+
+ dc390_updateDCB (pACB, pDCB);
+ if (!pos) goto ok;
+
+ olddevmode = pDCB->NegoPeriod;
+ /* Look for decimal point (Speed) */
+ pdec = pos;
+ while (pdec++ < &buffer[length]) if (*pdec == '.') break;
+ /* NegoPeriod */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 76, 800);
+ pDCB->NegoPeriod = dum >> 2;
+ if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+ if (!pos) goto ok;
+ if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+ }
+ else pos = strtok (0, " \t\n:=,;.");
+ if (!pos) goto ok;
+
+ /* Speed: NegoPeriod */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 1, 13);
+ pDCB->NegoPeriod = (1000/dum) >> 2;
+ if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
+ if (!pos) goto ok;
+ /* decimal */
+ if (pos-1 == pdec)
+ {
+ int dumold = dum;
+ dum = simple_strtoul (pos, &p0, 10) * 10;
+ for (; p0-pos > 1; p0--) dum /= 10;
+ pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
+ if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
+ if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
+ pos = strtok (0, " \t\n:=,;");
+ if (!pos) goto ok;
+ };
+ if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+ }
+ else pos = strtok (0, " \t\n:=,;");
+ /* dc390_updateDCB (pACB, pDCB); */
+ if (!pos) goto ok;
+
+ olddevmode = pDCB->SyncOffset;
+ /* SyncOffs */
+ if (*pos != '-')
+ {
+ SCANF (pos, p0, dum, 0, 0x0f);
+ pDCB->SyncOffset = dum;
+ if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
+ }
+ else pos = strtok (0, " \t\n:=,;");
+ dc390_updateDCB (pACB, pDCB);
+ }
+ else
+ {
+ char* p1 = pos; UCHAR dum;
+ PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
+ dum = GLITCH_TO_NS (pACB->glitch_cfg);
+ /* Adapter setting */
+ SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8);
+ SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8);
+ SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7);
+ SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+ SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+ SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+ SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+ ok2:
+ pACB->glitch_cfg = NS_TO_GLITCH (dum);
+ if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
+ dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
+ pACB->TagMaxNum &= (1 << --dum);
+ if (pos == p1) goto einv;
+ dc390_updateDCBs (pACB);
+ }
+ if (pos) goto next;
+
+ ok:
+ /* spin_unlock (strtok_lock); */
+ DC390_UNLOCK_ACB;
+ if (needs_inquiry)
+ { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
+ DC390_UNLOCK_IO;
+ return (length);
+
+ einv2:
+ pos = p0;
+ einv:
+ /* spin_unlock (strtok_lock); */
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
+ return (-EINVAL);
+
+ reset:
+ {
+ Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost;
+ printk (KERN_WARNING "DC390: Driver reset requested!\n");
+ DC390_UNLOCK_ACB;
+ DC390_reset (&cmd, 0);
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ inquiry:
+ {
+ pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ dev = simple_strtoul (pos, &p0, 10);
+ if (dev >= pACB->DCBCnt) goto einv_dev;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
+ dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ DC390_UNLOCK_ACB;
+ dc390_inquiry (pACB, pDCB);
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ remove:
+ {
+ pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+ dev = simple_strtoul (pos, &p0, 10);
+ if (dev >= pACB->DCBCnt) goto einv_dev;
+ for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
+ printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
+ dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ dc390_remove_dev (pACB, pDCB);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ };
+ return (length);
+
+ einv_dev:
+ printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n",
+ dev, pACB->DCBCnt - 1);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
+ return (-EINVAL);
+
+
}
+#undef SEARCH
+#undef YESNO
+#undef SCANF
+
/********************************************************************
- * Function: tmscsim_proc_info(char* buffer, char **start,
+ * Function: DC390_proc_info(char* buffer, char **start,
* off_t offset, int length, int hostno, int inout)
*
* Purpose: return SCSI Adapter/Device Info
@@ -1491,79+2372,86 @@ int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt) #undef SPRINTF
#define SPRINTF(args...) pos += sprintf(pos, ## args)
-#define YESNO(YN)\
-if (YN) SPRINTF(" Yes ");\
-else SPRINTF(" No ")
+#define YESNO(YN) \
+ if (YN) SPRINTF(" Yes "); \
+ else SPRINTF(" No ")
+
-int tmscsim_proc_info(char *buffer, char **start,
- off_t offset, int length, int hostno, int inout)
+int DC390_proc_info (char *buffer, char **start,
+ off_t offset, int length, int hostno, int inout)
{
int dev, spd, spd1;
char *pos = buffer;
PSH shpnt;
- PACB acbpnt;
- PDCB dcbpnt;
- unsigned long flags;
-/* Scsi_Cmnd *ptr; */
+ PACB pACB;
+ PDCB pDCB;
+ DC390_AFLAGS
- acbpnt = pACB_start;
+ pACB = dc390_pACB_start;
- while(acbpnt != (PACB)-1)
+ while(pACB != (PACB)-1)
{
- shpnt = acbpnt->pScsiHost;
+ shpnt = pACB->pScsiHost;
if (shpnt->host_no == hostno) break;
- acbpnt = acbpnt->pNextACB;
+ pACB = pACB->pNextACB;
}
- if (acbpnt == (PACB)-1) return(-ESRCH);
+ if (pACB == (PACB)-1) return(-ESRCH);
if(!shpnt) return(-ESRCH);
if(inout) /* Has data been written to the file ? */
- return(tmscsim_set_info(buffer, length, shpnt));
+ return dc390_set_info(buffer, length, pACB);
+
+ SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, ");
+ SPRINTF("Driver Version %s\n", DC390_VERSION);
- SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
- SPRINTF("Driver Version 1.12, 1998/02/25\n");
-
- save_flags(flags);
- cli();
+ DC390_LOCK_ACB;
SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
- SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
- SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
- SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+ SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
+ SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
+ SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel);
- SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
- SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+ SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
+ SPRINTF("AdapterID %i, SelTimeout %i ms\n",
+ shpnt->this_id, (pACB->sel_timeout*164)/100);
- SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+ SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n",
+ pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12);
- SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+ SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n",
+ pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB);
+ SPRINTF(" Lost arbitrations %li\n", pACB->SelLost);
+
+ SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
- SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+ SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n");
- dcbpnt = acbpnt->pLinkDCB;
- for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+ pDCB = pACB->pLinkDCB;
+ for (dev = 0; dev < pACB->DCBCnt; dev++)
{
- SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
- YESNO(dcbpnt->DevMode & PARITY_CHK_);
- YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
- YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
- YESNO(dcbpnt->DevMode & SEND_START_);
- YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
- SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2);
- if (dcbpnt->SyncOffset & 0x0f)
+ SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+ YESNO(pDCB->DevMode & PARITY_CHK_);
+ YESNO(pDCB->SyncMode & SYNC_NEGO_DONE);
+ YESNO(pDCB->DevMode & EN_DISCONNECT_);
+ //YESNO(pDCB->SyncMode & EN_ATN_STOP);
+ YESNO(pDCB->DevMode & SEND_START_);
+ YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
+ YESNO(pDCB->SyncMode & EN_ATN_STOP);
+ if (pDCB->SyncOffset & 0x0f)
{
- spd = 1000/(dcbpnt->NegoPeriod <<2);
- spd1 = 1000%(dcbpnt->NegoPeriod <<2);
- spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
- SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+ int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++;
+ SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2);
+ spd = 40/(sp); spd1 = 40%(sp);
+ spd1 = (spd1 * 10 + sp/2) / (sp);
+ SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f));
}
- else SPRINTF("\n");
+ else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2);
/* Add more info ...*/
- dcbpnt = dcbpnt->pNextDCB;
+ pDCB = pDCB->pNextDCB;
}
- restore_flags(flags);
+ DC390_UNLOCK_ACB;
*start = buffer + offset;
if (pos - buffer < offset)
@@ -1574,75+2462,92 @@ int tmscsim_proc_info(char *buffer, char **start, return length;
}
+#undef YESNO
+#undef SPRINTF
#ifdef MODULE
/***********************************************************************
- * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ * Function : static int dc390_shutdown (struct Scsi_Host *host)
*
* Purpose : does a clean (we hope) shutdown of the SCSI chip.
* Use prior to dumping core, unloading the driver, etc.
*
* Returns : 0 on success
***********************************************************************/
-static int
-DC390_shutdown (struct Scsi_Host *host)
+static int dc390_shutdown (struct Scsi_Host *host)
{
UCHAR bval;
- USHORT ioport;
- unsigned long flags;
PACB pACB = (PACB)(host->hostdata);
-
- ioport = (unsigned int) pACB->IOPortBase;
-
- save_flags (flags);
- cli();
-
+
/* pACB->soft_reset(host); */
-#ifdef DC390_DEBUG0
- printk("DC390: shutdown,");
-#endif
+ printk(KERN_INFO "DC390: shutdown\n");
- bval = inb(ioport+CtrlReg1);
+ pACB->ACBFlag = RESET_DONE;
+ bval = DC390_read8 (CtrlReg1);
bval |= DIS_INT_ON_SCSI_RST;
- outb(bval,ioport+CtrlReg1); /* disable interrupt */
- DC390_ResetSCSIBus( pACB );
+ DC390_write8 (CtrlReg1, bval); /* disable interrupt */
+ if (pACB->Gmode2 & RST_SCSI_BUS)
+ dc390_ResetSCSIBus (pACB);
- restore_flags (flags);
return( 0 );
}
+void dc390_freeDCBs (struct Scsi_Host *host)
+{
+ PDCB pDCB, nDCB;
+ PACB pACB = (PACB)(host->hostdata);
+
+ pDCB = pACB->pLinkDCB;
+ if (!pDCB) return;
+ do
+ {
+ nDCB = pDCB->pNextDCB;
+ DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\
+ pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
+ kfree (pDCB);
+ pDCB = nDCB;
+ } while (pDCB && pDCB != pACB->pLinkDCB);
+
+};
int DC390_release(struct Scsi_Host *host)
{
- int irq_count;
- struct Scsi_Host *tmp;
+ int irq_count;
+ PACB pACB;
+ DC390_AFLAGS DC390_IFLAGS
+#if USE_SPINLOCKS > 1
+ PACB pACB = (PACB)(host->hostdata);
+#endif
+
+ DC390_LOCK_IO;
+ DC390_LOCK_ACB;
- DC390_shutdown (host);
+ dc390_shutdown (host);
if (host->irq != IRQ_NONE)
{
- for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+ for (irq_count = 0, pACB = dc390_pACB_start;
+ pACB && pACB != (PACB)-1; pACB = pACB->pNextACB)
{
- if ( tmp->irq == host->irq )
+ if ( pACB->IRQLevel == host->irq )
++irq_count;
}
if (irq_count == 1)
{
-#ifdef DC390_DEBUG0
- printk("DC390: Free IRQ %i.",host->irq);
-#endif
+ DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);)
free_irq(host->irq,NULL);
}
}
release_region(host->io_port,host->n_io_port);
-
+ dc390_freeDCBs (host);
+ DC390_UNLOCK_ACB;
+ DC390_UNLOCK_IO;
return( 1 );
}
Scsi_Host_Template driver_template = DC390_T;
#include "scsi_module.c"
#endif /* def MODULE */
-
;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter *
;* Device Driver *
;***********************************************************************/
+/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */
#ifndef _TMSCSIM_H
#define _TMSCSIM_H
#define IRQ_NONE 255
+#define MAX_ADAPTER_NUM 4
+#define MAX_SG_LIST_BUF 16
+#define MAX_CMD_PER_LUN 8
+#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1
+#define MAX_SCSI_ID 8
+#define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */
+#define END_SCAN 2
+
+#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
+
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
@@ -54,17+65,6 @@ ULONG SGXPtr; } SGentry1, *PSGE;
-#define MAX_ADAPTER_NUM 4
-#define MAX_DEVICES 10
-#define MAX_SG_LIST_BUF 16
-#define MAX_CMD_QUEUE 20
-#define MAX_CMD_PER_LUN 8
-#define MAX_SCSI_ID 8
-#define MAX_SRB_CNT MAX_CMD_QUEUE+4
-#define END_SCAN 2
-
-#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
-
/*
;-----------------------------------------------------------------------
; SCSI Request Block
@@ -79,40+79,46 @@ struct _DCB *pSRBDCB; PSCSICMD pcmd;
PSGL pSegmentList;
-ULONG PhysSRB;
+ULONG Segment0[2];
+ULONG Segment1[2];
+
+/* 0x2c:*/
ULONG TotalXferredLen;
-ULONG SGPhysAddr; /*;a segment starting address */
+ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/
ULONG SGToBeXferLen; /*; to be xfer length */
+ULONG SRBState;
+/* 0x3c: */
+UCHAR MsgInBuf[6];
+UCHAR MsgOutBuf[6];
+
+/* 0x48: */
SGL Segmentx; /* make a one entry of S/G list table */
PUCHAR pMsgPtr;
-USHORT SRBState;
-USHORT Revxx2; /* ??? */
-UCHAR MsgInBuf[6];
-UCHAR MsgOutBuf[6];
+UCHAR ScsiCmdLen;
+UCHAR ScsiPhase;
UCHAR AdaptStatus;
UCHAR TargetStatus;
+
+/* 0x5c: */
UCHAR MsgCnt;
UCHAR EndMessage;
+UCHAR RetryCnt;
+UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
+ /*; b4-settimeout,b5-Residual valid */
UCHAR TagNumber;
UCHAR SGcount;
UCHAR SGIndex;
-UCHAR IORBFlag; /*;81h-Reset, 2-retry */
-
UCHAR SRBStatus;
-UCHAR RetryCnt;
-UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
- /*; b4-settimeout,b5-Residual valid */
-UCHAR ScsiCmdLen;
-UCHAR ScsiPhase;
-UCHAR Reserved3[3]; /*;for dword alignment */
-ULONG Segment0[2];
-ULONG Segment1[2];
+ //UCHAR IORBFlag; /*;81h-Reset, 2-retry */
+
+/* 0x64: */
};
+
typedef struct _SRB DC390_SRB, *PSRB;
/*
@@ -129,42+135,44 @@ PSCSICMD pQIORBhead; PSCSICMD pQIORBtail;
PSCSICMD AboIORBhead;
PSCSICMD AboIORBtail;
-USHORT QIORBCnt;
-USHORT AboIORBcnt;
+ULONG QIORBCnt;
+ULONG AboIORBcnt;
+/* 0x20: */
PSRB pWaitingSRB;
PSRB pWaitLast;
PSRB pGoingSRB;
PSRB pGoingLast;
PSRB pActiveSRB;
-USHORT GoingSRBCnt;
-USHORT WaitSRBCnt; /* ??? */
+UCHAR GoingSRBCnt;
+UCHAR WaitSRBCnt; /* ??? */
+UCHAR DevType;
+UCHAR MaxCommand;
+/* 0x38: */
ULONG TagMask;
-USHORT MaxCommand;
-USHORT AdaptIndex; /*; UnitInfo struc start */
-USHORT UnitIndex; /*; nth Unit on this card */
UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */
UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */
-
+UCHAR DevMode;
UCHAR IdentifyMsg;
+
UCHAR CtrlR1;
UCHAR CtrlR3;
UCHAR CtrlR4;
-UCHAR InqDataBuf[8];
-UCHAR CapacityBuf[8];
-UCHAR DevMode;
-UCHAR AdpMode;
+UCHAR DCBFlag;
+
+/* 0x44: */
UCHAR SyncMode; /*; 0:async mode */
UCHAR NegoPeriod; /*;for nego. */
UCHAR SyncPeriod; /*;for reg. */
UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */
-UCHAR UnitCtrlFlag;
-UCHAR DCBFlag;
-UCHAR DevType;
-UCHAR Reserved2[3]; /*;for dword alignment */
+
+/* 0x48:*/
+//UCHAR InqDataBuf[8];
+//UCHAR CapacityBuf[8];
+/* 0x58: */
};
typedef struct _DCB DC390_DCB, *PDCB;
@@ -175,40+183,55 @@ typedef struct _DCB DC390_DCB, *PDCB; */
struct _ACB
{
-ULONG PhysACB;
PSH pScsiHost;
struct _ACB *pNextACB;
USHORT IOPortBase;
-USHORT Revxx1; /* ??? */
+UCHAR IRQLevel;
+UCHAR status;
+
+UCHAR SRBCount;
+UCHAR AdapterIndex; /*; nth Adapter this driver */
+UCHAR DeviceCnt;
+UCHAR DCBCnt;
+
+/* 0x10: */
+UCHAR TagMaxNum;
+UCHAR ACBFlag;
+UCHAR Gmode2;
+UCHAR scan_devices;
PDCB pLinkDCB;
+PDCB pLastDCB;
PDCB pDCBRunRobin;
PDCB pActiveDCB;
-PDCB pDCB_free;
PSRB pFreeSRB;
PSRB pTmpSRB;
-USHORT SRBCount;
-USHORT AdapterIndex; /*; nth Adapter this driver */
-USHORT max_id;
-USHORT max_lun;
+
+/* 0x2c: */
UCHAR msgin123[4];
-UCHAR status;
-UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */
-UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */
-UCHAR DeviceCnt;
-UCHAR IRQLevel;
-UCHAR TagMaxNum;
-UCHAR ACBFlag;
-UCHAR Gmode2;
-UCHAR LUNchk;
-UCHAR scan_devices;
-UCHAR HostID_Bit;
-UCHAR Reserved1[1]; /*;for dword alignment */
UCHAR DCBmap[MAX_SCSI_ID];
-DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */
-DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */
+
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+spinlock_t lock;
+#endif
+UCHAR sel_timeout;
+UCHAR glitch_cfg;
+
+UCHAR reserved[2]; /* alignment */
+
+PDEVDECL1; /* Pointer to PCI cfg. space */
+/* 0x44/0x40: */
+ULONG Cmds;
+ULONG CmdInQ;
+ULONG CmdOutOfSRB;
+ULONG SelLost;
+
+/* 0x50/0x4c: */
DC390_SRB TmpSRB;
+/* 0xb4/0xb0: */
+DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */
+/* 0x7bc/0x7b8: */
};
typedef struct _ACB DC390_ACB, *PACB;
@@ -278,14+301,6 @@ typedef struct _ACB DC390_ACB, *PACB; #define DO_SYNC_NEGO BIT13
#define SRB_UNEXPECT_RESEL BIT14
-/*;---ACBFlag */
-#define RESET_DEV BIT0
-#define RESET_DETECT BIT1
-#define RESET_DONE BIT2
-
-/*;---DCBFlag */
-#define ABORT_DEV_ BIT0
-
/*;---SRBstatus */
#define SRB_OK BIT0
#define ABORTION BIT1
@@ -294,6+309,14 @@ typedef struct _ACB DC390_ACB, *PACB; #define PARITY_ERROR BIT4
#define SRB_ERROR BIT5
+/*;---ACBFlag */
+#define RESET_DEV BIT0
+#define RESET_DETECT BIT1
+#define RESET_DONE BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_ BIT0
+
/*;---SRBFlag */
#define DATAOUT BIT7
#define DATAIN BIT6
@@ -316,7+339,7 @@ typedef struct _ACB DC390_ACB, *PACB; #define H_BAD_CCB_OR_SG 0x1A
#define H_ABORT 0x0FF
-/*; SCSI Status byte codes*/
+/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */
#define SCSI_STAT_GOOD 0x0 /*; Good status */
#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */
#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */
@@ -335,9+358,9 @@ typedef struct _ACB DC390_ACB, *PACB; #define SYNC_DISABLE 0
#define SYNC_ENABLE BIT0
#define SYNC_NEGO_DONE BIT1
-#define WIDE_ENABLE BIT2
-#define WIDE_NEGO_DONE BIT3
-#define EN_TAG_QUEUING BIT4
+#define WIDE_ENABLE BIT2 /* Not used ;-) */
+#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */
+#define EN_TAG_QUEUEING BIT4
#define EN_ATN_STOP BIT5
#define SYNC_NEGO_OFFSET 15
@@ -352,7+375,7 @@ typedef struct _ACB DC390_ACB, *PACB; #define SCSI_MSG_OUT 6
#define SCSI_MSG_IN 7
-/*;----SCSI MSG BYTE*/
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */
#define MSG_COMPLETE 0x00
#define MSG_EXTENDED 0x01
#define MSG_SAVE_PTR 0x02
@@ -373,13+396,6 @@ typedef struct _ACB DC390_ACB, *PACB; #define MSG_IDENTIFY 0x80
#define MSG_HOST_ID 0x0C0
-/*;----SCSI STATUS BYTE*/
-#define STATUS_GOOD 0x00
-#define CHECK_CONDITION_ 0x02
-#define STATUS_BUSY 0x08
-#define STATUS_INTERMEDIATE 0x10
-#define RESERVE_CONFLICT 0x18
-
/* cmd->result */
#define STATUS_MASK_ 0xFF
#define MSG_MASK 0xFF00
@@ -389,7+405,7 @@ typedef struct _ACB DC390_ACB, *PACB; ** Inquiry Data format
*/
-typedef struct _SCSIInqData { /* INQ */
+typedef struct _SCSIInqData { /* INQUIRY */
UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/
UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */
@@ -412,6+428,7 @@ typedef struct _SCSIInqData { /* INQ */
#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */
#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */
+#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */
/* Inquiry byte 1 mask */
@@ -420,18+437,10 @@ typedef struct _SCSIInqData { /* INQ */
/* Peripheral Device Type definitions */
+/* see include/scsi/scsi.h for the rest */
-#define SCSI_DASD 0x00 /* Direct-access Device */
-#define SCSI_SEQACESS 0x01 /* Sequential-access device */
-#define SCSI_PRINTER 0x02 /* Printer device */
-#define SCSI_PROCESSOR 0x03 /* Processor device */
-#define SCSI_WRITEONCE 0x04 /* Write-once device */
-#define SCSI_CDROM 0x05 /* CD-ROM device */
-#define SCSI_SCANNER 0x06 /* Scanner device */
-#define SCSI_OPTICAL 0x07 /* Optical memory device */
-#define SCSI_MEDCHGR 0x08 /* Medium changer device */
-#define SCSI_COMM 0x09 /* Communications device */
-#define SCSI_NODEV 0x1F /* Unknown or no device type */
+#define TYPE_PRINTER 0x02 /* Printer device */
+#define TYPE_COMM 0x09 /* Communications device */
/*
** Inquiry flag definitions (Inq data byte 7)
@@ -459,17+468,24 @@ UCHAR xx1; UCHAR xx2;
} EEprom, *PEEprom;
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2 65
-#define EE_DELAY 66
-#define EE_TAG_CMD_NUM 67
+#define REAL_EE_ADAPT_SCSI_ID 64
+#define REAL_EE_MODE2 65
+#define REAL_EE_DELAY 66
+#define REAL_EE_TAG_CMD_NUM 67
+
+#define EE_ADAPT_SCSI_ID 32
+#define EE_MODE2 33
+#define EE_DELAY 34
+#define EE_TAG_CMD_NUM 35
+
+#define EE_LEN 40
/*; EE_MODE1 bits definition*/
#define PARITY_CHK_ BIT0
#define SYNC_NEGO_ BIT1
#define EN_DISCONNECT_ BIT2
#define SEND_START_ BIT3
-#define TAG_QUEUING_ BIT4
+#define TAG_QUEUEING_ BIT4
/*; EE_MODE2 bits definition*/
#define MORE2_DRV BIT0
@@ -494,34+510,42 @@ UCHAR xx2; ;====================
*/
-/*; Command Reg.(+0CH) */
+/*; Command Reg.(+0CH) (rw) */
#define DMA_COMMAND BIT7
#define NOP_CMD 0
#define CLEAR_FIFO_CMD 1
#define RST_DEVICE_CMD 2
#define RST_SCSI_BUS_CMD 3
+
#define INFO_XFER_CMD 0x10
#define INITIATOR_CMD_CMPLTE 0x11
#define MSG_ACCEPTED_CMD 0x12
#define XFER_PAD_BYTE 0x18
#define SET_ATN_CMD 0x1A
#define RESET_ATN_CMD 0x1B
-#define SELECT_W_ATN 0x42
+
+#define SEL_WO_ATN 0x41 /* currently not used */
+#define SEL_W_ATN 0x42
#define SEL_W_ATN_STOP 0x43
+#define SEL_W_ATN3 0x46
#define EN_SEL_RESEL 0x44
-#define SEL_W_ATN2 0x46
+#define DIS_SEL_RESEL 0x45 /* currently not used */
+#define RESEL 0x40 /* " */
+#define RESEL_ATN3 0x47 /* " */
+
#define DATA_XFER_CMD INFO_XFER_CMD
-/*; SCSI Status Reg.(+10H) */
+/*; SCSI Status Reg.(+10H) (r) */
#define INTERRUPT BIT7
#define ILLEGAL_OP_ERR BIT6
#define PARITY_ERR BIT5
#define COUNT_2_ZERO BIT4
#define GROUP_CODE_VALID BIT3
-#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
+/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
-/*; Interrupt Status Reg.(+14H) */
+/*; Interrupt Status Reg.(+14H) (r) */
#define SCSI_RESET BIT7
#define INVALID_CMD BIT6
#define DISCONNECTED BIT5
@@ -531,11+555,12 @@ UCHAR xx2; #define SEL_ATTENTION BIT1
#define SELECTED BIT0
-/*; Internal State Reg.(+18H) */
+/*; Internal State Reg.(+18H) (r) */
#define SYNC_OFFSET_FLAG BIT3
#define INTRN_STATE_MASK (BIT2+BIT1+BIT0)
+/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
-/*; Clock Factor Reg.(+24H) */
+/*; Clock Factor Reg.(+24H) (w) */
#define CLK_FREQ_40MHZ 0
#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0)
#define CLK_FREQ_30MHZ (BIT2+BIT1)
@@ -544,47+569,54 @@ UCHAR xx2; #define CLK_FREQ_15MHZ (BIT1+BIT0)
#define CLK_FREQ_10MHZ BIT1
-/*; Control Reg. 1(+20H) */
+/*; Control Reg. 1(+20H) (rw) */
#define EXTENDED_TIMING BIT7
#define DIS_INT_ON_SCSI_RST BIT6
#define PARITY_ERR_REPO BIT4
-#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0)
+#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */
-/*; Control Reg. 2(+2CH) */
+/*; Control Reg. 2(+2CH) (rw) */
#define EN_FEATURE BIT6
#define EN_SCSI2_CMD BIT3
-/*; Control Reg. 3(+30H) */
+/*; Control Reg. 3(+30H) (rw) */
#define ID_MSG_CHECK BIT7
#define EN_QTAG_MSG BIT6
#define EN_GRP2_CMD BIT5
#define FAST_SCSI BIT4 /* ;10MB/SEC */
#define FAST_CLK BIT3 /* ;25 - 40 MHZ */
-/*; Control Reg. 4(+34H) */
+/*; Control Reg. 4(+34H) (rw) */
#define EATER_12NS 0
#define EATER_25NS BIT7
#define EATER_35NS BIT6
#define EATER_0NS (BIT7+BIT6)
+#define REDUCED_POWER BIT5
+#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */
#define NEGATE_REQACKDATA BIT2
#define NEGATE_REQACK BIT3
+
+#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
+#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
+
/*
;====================
; DMA Register
;====================
*/
-/*; DMA Command Reg.(+40H) */
+/*; DMA Command Reg.(+40H) (rw) */
#define READ_DIRECTION BIT7
#define WRITE_DIRECTION 0
#define EN_DMA_INT BIT6
-#define MAP_TO_MDL BIT5
-#define DIAGNOSTIC BIT4
+#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */
+#define MAP_TO_MDL BIT4
+#define DIAGNOSTIC BIT2
#define DMA_IDLE_CMD 0
#define DMA_BLAST_CMD BIT0
#define DMA_ABORT_CMD BIT1
#define DMA_START_CMD (BIT1+BIT0)
-/*; DMA Status Reg.(+54H) */
+/*; DMA Status Reg.(+54H) (r) */
#define PCI_MS_ABORT BIT6
#define BLAST_COMPLETE BIT5
#define SCSI_INTERRUPT BIT4
@@ -593,71+625,77 @@ UCHAR xx2; #define DMA_XFER_ERROR BIT1
#define POWER_DOWN BIT0
-/*
-; DMA SCSI Bus and Ctrl.(+70H)
-;EN_INT_ON_PCI_ABORT
-*/
+/*; DMA SCSI Bus and Ctrl.(+70H) */
+#define EN_INT_ON_PCI_ABORT BIT25
+#define WRT_ERASE_DMA_STAT BIT24
+#define PW_DOWN_CTRL BIT21
+#define SCSI_BUSY BIT20
+#define SCLK BIT19
+#define SCAM BIT18
+#define SCSI_LINES 0x0003ffff
/*
;==========================================================
; SCSI Chip register address offset
;==========================================================
+;Registers are rw unless declared otherwise
*/
-#define CtcReg_Low 0x00
-#define CtcReg_Mid 0x04
+#define CtcReg_Low 0x00 /* r curr. transfer count */
+#define CtcReg_Mid 0x04 /* r */
+#define CtcReg_High 0x38 /* r */
#define ScsiFifo 0x08
#define ScsiCmd 0x0C
-#define Scsi_Status 0x10
-#define INT_Status 0x14
-#define Sync_Period 0x18
-#define Sync_Offset 0x1C
-#define CtrlReg1 0x20
-#define Clk_Factor 0x24
+#define Scsi_Status 0x10 /* r */
+#define INT_Status 0x14 /* r */
+#define Sync_Period 0x18 /* w */
+#define Sync_Offset 0x1C /* w */
+#define Clk_Factor 0x24 /* w */
+#define CtrlReg1 0x20
#define CtrlReg2 0x2C
#define CtrlReg3 0x30
#define CtrlReg4 0x34
-#define CtcReg_High 0x38
#define DMA_Cmd 0x40
-#define DMA_XferCnt 0x44
-#define DMA_XferAddr 0x48
-#define DMA_Wk_ByteCntr 0x4C
-#define DMA_Wk_AddrCntr 0x50
-#define DMA_Status 0x54
-#define DMA_MDL_Addr 0x58
-#define DMA_Wk_MDL_Cntr 0x5C
-#define DMA_ScsiBusCtrl 0x70
-
-#define StcReg_Low CtcReg_Low
-#define StcReg_Mid CtcReg_Mid
-#define Scsi_Dest_ID Scsi_Status
-#define Scsi_TimeOut INT_Status
-#define Intern_State Sync_Period
-#define Current_Fifo Sync_Offset
-#define StcReg_High CtcReg_High
-
-#define am_target Scsi_Status
-#define am_timeout INT_Status
-#define am_seq_step Sync_Period
-#define am_fifo_count Sync_Offset
-
-
-#define DC390_read8(address) \
- inb(DC390_ioport + (address)))
-
-#define DC390_read16(address) \
- inw(DC390_ioport + (address)))
-
-#define DC390_read32(address) \
- inl(DC390_ioport + (address)))
-
-#define DC390_write8(address,value) \
- outb((value), DC390_ioport + (address)))
-
-#define DC390_write16(address,value) \
- outw((value), DC390_ioport + (address)))
-
-#define DC390_write32(address,value) \
- outl((value), DC390_ioport + (address)))
+#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */
+#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */
+#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */
+#define DMA_Wk_AddrCntr 0x50 /* r working address counter */
+#define DMA_Status 0x54 /* r */
+#define DMA_MDL_Addr 0x58 /* rw starting MDL address */
+#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */
+#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */
+
+#define StcReg_Low CtcReg_Low /* w start transfer count */
+#define StcReg_Mid CtcReg_Mid /* w */
+#define StcReg_High CtcReg_High /* w */
+#define Scsi_Dest_ID Scsi_Status /* w */
+#define Scsi_TimeOut INT_Status /* w */
+#define Intern_State Sync_Period /* r */
+#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */
+
+
+#define DC390_read8(address) \
+ (inb (pACB->IOPortBase + (address)))
+
+#define DC390_read8_(address, base) \
+ (inb ((USHORT)(base) + (address)))
+
+#define DC390_read16(address) \
+ (inw (pACB->IOPortBase + (address)))
+
+#define DC390_read32(address) \
+ (inl (pACB->IOPortBase + (address)))
+
+#define DC390_write8(address,value) \
+ outb ((value), pACB->IOPortBase + (address))
+
+#define DC390_write8_(address,value,base) \
+ outb ((value), (USHORT)(base) + (address))
+
+#define DC390_write16(address,value) \
+ outw ((value), pACB->IOPortBase + (address))
+
+#define DC390_write32(address,value) \
+ outl ((value), pACB->IOPortBase + (address))
#endif /* _TMSCSIM_H */
*
* linux/fs/autofs/autofs_i.h
*
- * Copyright 1997 Transmeta Corporation - All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
struct autofs_dir_ent {
int hash;
- struct autofs_dir_ent *next;
- struct autofs_dir_ent **back;
char *name;
int len;
ino_t ino;
+ struct dentry *dentry;
+ /* Linked list of entries */
+ struct autofs_dir_ent *next;
+ struct autofs_dir_ent **back;
/* The following entries are for the expiry system */
unsigned long last_usage;
struct autofs_dir_ent *exp_next;
@@ -123,7+125,7 @@ void autofs_initialize_hash(struct autofs_dirhash *); struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *);
void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
void autofs_hash_delete(struct autofs_dir_ent *);
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *);
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *);
void autofs_hash_nuke(struct autofs_dirhash *);
/* Expiration-handling functions */
*
* linux/fs/autofs/dir.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -59,13+59,11 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, return ent; /* Symlinks are always expirable */
/* Get the dentry for the autofs subdirectory */
- dentry = lookup_dentry(ent->name, dget(sb->s_root), 0);
+ dentry = ent->dentry;
- if ( IS_ERR(dentry) ) {
- printk("autofs: no such dentry on expiry queue: %s\n",
- ent->name);
+ if ( !dentry ) {
+ printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
autofs_delete_usage(ent);
- continue;
}
if ( !dentry->d_inode ) {
@@ -79,24+77,12 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, /* Make sure entry is mounted and unused; note that dentry will
point to the mounted-on-top root. */
if ( !S_ISDIR(dentry->d_inode->i_mode)
- || dentry->d_covers == dentry ) {
- dput(dentry);
+ || dentry->d_mounts == dentry ) {
DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
continue;
}
- /*
- * Now, this is known to be a mount point; therefore the dentry
- * will be held by the superblock. is_root_busy() will break if
- * we hold a use count here, so we have to dput() it before calling
- * is_root_busy(). However, since it is a mount point (already
- * verified), dput() will be a nonblocking operation and the use
- * count will not go to zero; therefore the call to is_root_busy()
- * here is legal.
- */
- dput(dentry);
-
- if ( !is_root_busy(dentry) ) {
+ if ( !is_root_busy(dentry->d_mounts) ) {
DPRINTK(("autofs: signaling expire on %s\n", ent->name));
return ent; /* Expirable! */
}
@@ -136,6+122,8 @@ void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) autofs_say(ent->name,ent->len);
autofs_init_usage(dh,ent);
+ if ( ent->dentry )
+ ent->dentry->d_count++;
dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE];
ent->next = *dhnp;
@@ -153,6+141,8 @@ void autofs_hash_delete(struct autofs_dir_ent *ent)
autofs_delete_usage(ent);
+ if ( ent->dentry )
+ dput(ent->dentry);
kfree(ent->name);
kfree(ent);
}
@@ -161,8+151,12 @@ void autofs_hash_delete(struct autofs_dir_ent *ent) * Used by readdir(). We must validate "ptr", so we can't simply make it
* a pointer. Values below 0xffff are reserved; calling with any value
* <= 0x10000 will return the first entry found.
+ *
+ * "last" can be NULL or the value returned by the last search *if* we
+ * want the next sequential entry.
*/
-struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *ptr)
+struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh,
+ off_t *ptr, struct autofs_dir_ent *last)
{
int bucket, ecount, i;
struct autofs_dir_ent *ent;
@@ -176,19+170,23 @@ struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *
DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount));
- ent = NULL;
-
- while ( bucket < AUTOFS_HASH_SIZE ) {
- ent = dh->h[bucket];
- for ( i = ecount ; ent && i ; i-- )
- ent = ent->next;
-
- if (ent) {
- ecount++; /* Point to *next* entry */
- break;
+ ent = last ? last->next : NULL;
+
+ if ( ent ) {
+ ecount++;
+ } else {
+ while ( bucket < AUTOFS_HASH_SIZE ) {
+ ent = dh->h[bucket];
+ for ( i = ecount ; ent && i ; i-- )
+ ent = ent->next;
+
+ if (ent) {
+ ecount++; /* Point to *next* entry */
+ break;
+ }
+
+ bucket++; ecount = 0;
}
-
- bucket++; ecount = 0;
}
#ifdef DEBUG
@@ -214,6+212,8 @@ void autofs_hash_nuke(struct autofs_dirhash *dh) for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
for ( ent = dh->h[i] ; ent ; ent = nent ) {
nent = ent->next;
+ if ( ent->dentry )
+ dput(ent->dentry);
kfree(ent->name);
kfree(ent);
}
*
* linux/fs/autofs/init.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
*
* linux/fs/autofs/inode.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
*
* linux/fs/autofs/root.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -66,7+66,7 @@ struct inode_operations autofs_root_inode_operations = {
static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct autofs_dir_ent *ent;
+ struct autofs_dir_ent *ent = NULL;
struct autofs_dirhash *dirhash;
struct inode * inode = filp->f_dentry->d_inode;
off_t onr, nr;
@@ -90,10+90,12 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi filp->f_pos = ++nr;
/* fall through */
default:
- while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr) ) {
- if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
- return 0;
- filp->f_pos = nr;
+ while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
+ if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) {
+ if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0)
+ return 0;
+ filp->f_pos = nr;
+ }
}
break;
}
@@ -110,8+112,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
do {
if ( status && dentry->d_inode ) {
- printk("autofs warning: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name);
- break;
+ printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
+ return 0; /* Try to get the kernel to invalidate this dentry */
}
/* Turn this into a real negative dentry? */
@@ -148,8+150,9 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
/* We don't update the usages for the autofs daemon itself, this
is necessary for recursive autofs mounts */
- if ( !autofs_oz_mode(sbi) )
+ if ( !autofs_oz_mode(sbi) ) {
autofs_update_usage(&sbi->dirhash,ent);
+ }
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
return 1;
@@ -193,7+196,8 @@ static int autofs_revalidate(struct dentry * dentry) /* Update the usage list */
if ( !autofs_oz_mode(sbi) ) {
ent = (struct autofs_dir_ent *) dentry->d_time;
- autofs_update_usage(&sbi->dirhash,ent);
+ if ( ent )
+ autofs_update_usage(&sbi->dirhash,ent);
}
return 1;
}
@@ -207,7+211,6 @@ static struct dentry_operations autofs_dentry_operations = { static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
{
struct autofs_sb_info *sbi;
- struct inode *res;
int oz_mode;
DPRINTK(("autofs_root_lookup: name = "));
@@ -216,7+219,6 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry) if (!S_ISDIR(dir->i_mode))
return -ENOTDIR;
- res = NULL;
sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
oz_mode = autofs_oz_mode(sbi);
@@ -249,6+251,15 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry) return -ERESTARTNOINTR;
}
+ /*
+ * If this dentry is unhashed, then we shouldn't honour this
+ * lookup even if the dentry is positive. Returning ENOENT here
+ * doesn't do the right thing for all system calls, but it should
+ * be OK for the operations we permit from an autofs.
+ */
+ if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+ return -ENOENT;
+
return 0;
}
@@ -304,6+315,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c ent->ino = AUTOFS_FIRST_SYMLINK + n;
ent->hash = dentry->d_name.hash;
memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
+ ent->dentry = NULL; /* We don't keep the dentry for symlinks */
autofs_hash_insert(dh,ent);
d_instantiate(dentry, iget(dir->i_sb,ent->ino));
@@ -339,7+351,8 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry) n = ent->ino - AUTOFS_FIRST_SYMLINK;
if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) )
return -EINVAL; /* Not a symlink inode, can't unlink */
-
+
+ dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
autofs_hash_delete(ent);
clear_bit(n,sbi->symlink_bitmap);
kfree(sbi->symlink[n].data);
@@ -364,6+377,11 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry) if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
return -ENOTDIR; /* Not a directory */
+ if ( ent->dentry != dentry ) {
+ printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
+ }
+
+ dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
autofs_hash_delete(ent);
dir->i_nlink--;
d_drop(dentry);
@@ -399,12+417,14 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) return -ENOSPC;
}
+ dir->i_nlink++;
+ d_instantiate(dentry, iget(dir->i_sb,ent->ino));
+
ent->hash = dentry->d_name.hash;
memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
ent->ino = sbi->next_dir_ino++;
+ ent->dentry = dentry;
autofs_hash_insert(dh,ent);
- dir->i_nlink++;
- d_instantiate(dentry, iget(dir->i_sb,ent->ino));
return 0;
}
*
* linux/fs/autofs/symlink.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
*
* linux/fs/autofs/waitq.c
*
- * Copyright 1997 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
is better if we don't reassign numbers easily even across filesystems */
static int autofs_next_wait_queue = 1;
+/* These are the signals we allow interrupting a pending mount */
+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
void autofs_catatonic_mode(struct autofs_sb_info *sbi)
{
struct autofs_wait_queue *wq, *nwq;
@@ -133,9+136,25 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr * name) } else
wq->wait_ctr++;
+ /* wq->name is NULL if and only if the lock is already released */
+
if ( wq->name ) {
- /* wq->name is NULL if and only if the lock is released */
+ /* Block all but "shutdown" signals while waiting */
+ sigset_t oldset;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(¤t->sigmask_lock, irqflags);
+ oldset = current->blocked;
+ siginitsetinv(¤t->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(¤t->sigmask_lock, irqflags);
+
interruptible_sleep_on(&wq->queue);
+
+ spin_lock_irqsave(¤t->sigmask_lock, irqflags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(¤t->sigmask_lock, irqflags);
} else {
DPRINTK(("autofs_wait: skipped sleeping\n"));
}
@@ -608,7+608,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) base, as well as whatever program they might try to exec. This
is because the brk will follow the loader, and is not movable. */
- load_bias = (elf_ex.e_type == ET_DYN ? ELF_ET_DYN_BASE : 0);
+ load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0);
/* Now we do a little grungy work by mmaping the ELF image into
the correct location in memory. At this point, we assume that
@@ -618,51+618,50 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) 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, elf_flags;
- unsigned long vaddr;
+ int elf_prot = 0, elf_flags;
+ unsigned long vaddr;
- 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;
+ if (elf_ppnt->p_type != PT_LOAD)
+ continue;
- elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+ 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;
- vaddr = elf_ppnt->p_vaddr;
- if (elf_ex.e_type == ET_EXEC || load_addr_set) {
- elf_flags |= MAP_FIXED;
- }
+ elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+ vaddr = elf_ppnt->p_vaddr;
+ if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+ elf_flags |= MAP_FIXED;
+ }
- error = do_mmap(file,
- ELF_PAGESTART(load_bias + vaddr),
- (elf_ppnt->p_filesz +
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot, elf_flags,
- (elf_ppnt->p_offset -
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
-
- if (!load_addr_set) {
- load_addr_set = 1;
- load_addr = (elf_ppnt->p_vaddr -
- elf_ppnt->p_offset);
- if (elf_ex.e_type == ET_DYN) {
- load_bias = error - ELF_PAGESTART(load_bias + vaddr);
- load_addr += error;
- }
+ error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr),
+ (elf_ppnt->p_filesz +
+ ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+ elf_prot, elf_flags, (elf_ppnt->p_offset -
+ ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
+ if (!load_addr_set) {
+ load_addr_set = 1;
+ load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
+ if (elf_ex.e_type == ET_DYN) {
+ load_bias += error -
+ ELF_PAGESTART(load_bias + vaddr);
+ load_addr += error;
}
- 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 ((elf_ppnt->p_flags & PF_X) && end_code < k)
- 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;
}
+ 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 ((elf_ppnt->p_flags & PF_X) && end_code < k)
+ 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);
fput(file); /* all done with the file */
#include <asm/unaligned.h>
#include <asm/semaphore.h>
#include <asm/spinlock.h>
-#include <asm/namei.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+/*
+ * The bitmask for a lookup event:
+ * - follow links at the end
+ * - require a directory
+ * - ending slashes ok even for nonexistent files
+ * - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW (1)
+#define LOOKUP_DIRECTORY (2)
+#define LOOKUP_SLASHOK (4)
+#define LOOKUP_CONTINUE (8)
+
+#include <asm/namei.h>
+
/* This can be removed after the beta phase. */
#define CACHE_SUPERVISE /* debug the correctness of dcache entries */
#undef DEBUG /* some other debugging */
@@ -282,18+295,6 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) return result;
}
-/*
- * The bitmask for a lookup event:
- * - follow links at the end
- * - require a directory
- * - ending slashes ok even for nonexistent files
- * - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW (1)
-#define LOOKUP_DIRECTORY (2)
-#define LOOKUP_SLASHOK (4)
-#define LOOKUP_CONTINUE (8)
-
static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow)
{
struct inode * inode = dentry->d_inode;
@@ -342,10+343,10 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, unsigned if (*name == '/') {
if (base)
dput(base);
- base = dget(current->fs->root);
do {
name++;
} while (*name == '/');
+ base = dget(current->fs->root);
} else if (!base) {
base = dget(current->fs->pwd);
}
@@ -43,5+43,14 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) current->fsgid = exp->ex_anon_gid;
for (i = 0; i < NGROUPS; i++)
current->groups[i] = cred->cr_groups[i];
+
+ if ((cred->cr_uid)) {
+ cap_lower(current->cap_effective, CAP_DAC_OVERRIDE);
+ cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH);
+ } else {
+ cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+ cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+ }
+
rqstp->rq_userset = 1;
}
@@ -457,14+457,17 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, char *path, struct knfs_fh *f)
{
struct svc_export *exp;
- struct dentry *dentry;
+ struct dentry *dentry = NULL;
struct inode *inode;
struct svc_fh fh;
int err;
+ err = -EPERM;
if (path) {
- dentry = lookup_dentry(path, NULL, 0);
-
+ if (!(dentry = lookup_dentry(path, NULL, 0))) {
+ printk("nfsd: exp_rootfh path not found %s", path);
+ return -EPERM;
+ }
dev = dentry->d_inode->i_dev;
ino = dentry->d_inode->i_ino;
@@ -474,17+477,21 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, } else {
dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
clp->cl_ident, dev, ino);
- exp = exp_get(clp, dev, ino);
- dentry = dget(exp->ex_dentry);
+ if ((exp = exp_get(clp, dev, ino)))
+ if (!(dentry = dget(exp->ex_dentry))) {
+ printk("exp_rootfh: Aieee, NULL dentry\n");
+ return -EPERM;
+ }
}
- err = -EPERM;
- if (!exp)
+ if (!exp) {
+ dprintk("nfsd: exp_rootfh export not found.\n");
goto out;
+ }
inode = dentry->d_inode;
if (!inode) {
printk("exp_rootfh: Aieee, NULL d_inode\n");
- return -EPERM;
+ goto out;
}
if (inode->i_dev != dev || inode->i_ino != ino) {
printk("exp_rootfh: Aieee, ino/dev mismatch\n");
@@ -1061,31+1061,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) goto out;
/*
- * Security: Check that the export is valid for dentry <gam3@acm.org>
- */
- if (fh->fh_dev != fh->fh_xdev) {
- printk("fh_verify: Security: export on other device"
- " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
- goto out;
- } else {
- struct dentry *tdentry = dentry;
-
- do {
- if (exp->ex_dentry == tdentry) {
- error = 0;
- break;
- }
- if (tdentry->d_parent == tdentry)
- break;
- } while ((tdentry = tdentry->d_parent));
- if (error) {
- printk("fh_verify: Security: %s/%s bad export.\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name);
- goto out;
- }
- }
- /*
* Note: it's possible the returned dentry won't be the one in the
* file handle. We can correct the file handle for our use, but
* unfortunately the client will keep sending the broken one. Let's
@@ -1105,6+1080,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) check_type:
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
+ exp = fhp->fh_export;
if (type > 0 && (inode->i_mode & S_IFMT) != type) {
error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
goto out;
@@ -1114,9+1090,45 @@ check_type: goto out;
}
+ /*
+ * Security: Check that the export is valid for dentry <gam3@acm.org>
+ */
+ if (fh->fh_dev != fh->fh_xdev) {
+ printk("fh_verify: Security: export on other device"
+ " (%d, %d).\n", fh->fh_dev, fh->fh_xdev);
+ goto out;
+ } else if (exp->ex_dentry != dentry) {
+ struct dentry *tdentry = dentry;
+ int err2 = 0;
+
+ error = nfserr_stale;
+ do {
+ tdentry = tdentry->d_parent;
+ if (exp->ex_dentry == tdentry) {
+ error = 0;
+ break;
+ }
+ if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) {
+ error = err2;
+#ifdef NFSD_PARANOIA
+ goto out1;
+#else
+ goto out;
+#endif
+ }
+ } while ((tdentry != tdentry->d_parent));
+ if (error) {
+ printk("fh_verify: Security: %s/%s bad export.\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ goto out;
+ }
+ }
+
/* Finally, check access permissions. */
- error = nfsd_permission(fhp->fh_export, dentry, access);
+ error = nfsd_permission(exp, dentry, access);
#ifdef NFSD_PARANOIA
+out1:
if (error)
printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
free_wait(&wait_table);
free_page((unsigned long) wait_table.entry);
}
-out_nowait:
unlock_kernel();
return retval;
}
*/
#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
typedef struct { } spinlock_t;
- #define SPIN_LOCK_UNLOCKED { }
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
#else
typedef struct { int gcc_is_buggy; } spinlock_t;
- #define SPIN_LOCK_UNLOCKED { 0 }
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#endif
#define spin_lock_init(lock) do { } while(0)
typedef struct {
volatile unsigned int lock;
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#define spin_lock_init(x) do { (x)->lock = 0; } while (0)
#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
@@ -61,7+61,7 @@ typedef struct { volatile unsigned int babble;
const char *module;
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0, 25, __BASE_FILE__ }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
#include <linux/kernel.h>
@@ -90,7+90,7 @@ typedef struct { * read-locks.
*/
typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+#define RW_LOCK_UNLOCKED (rwlock_t) { }
#define read_lock(lock) do { } while(0)
#define read_unlock(lock) do { } while(0)
@@ -120,7+120,7 @@ typedef struct { volatile unsigned int lock;
} spinlock_t;
-#define SPIN_LOCK_UNLOCKED { 0 }
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#define spin_lock_init(x) do { (x)->lock = 0; } while(0)
/*
@@ -188,7+188,7 @@ typedef struct { unsigned long previous;
} rwlock_t;
-#define RW_LOCK_UNLOCKED { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
/*
* On x86, we implement read-write locks as a 32-bit counter
@@ -88,7+88,7 @@ static inline unsigned long _get_base(char * addr) "1:\t" \
"movl %0,%%" #seg "\n" \
"2:\n" \
- ".section fixup,\"ax\"\n" \
+ ".section .fixup,\"ax\"\n" \
"3:\t" \
"pushl $0\n\t" \
"popl %%" #seg "\n\t" \
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x0000016c
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_rlim 0x00000170
+#define AOFF_task_user 0x00000170
+#define ASIZ_task_user 0x00000004
+#define AOFF_task_rlim 0x00000174
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x000001c0
+#define AOFF_task_used_math 0x000001c4
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x000001c2
+#define AOFF_task_comm 0x000001c6
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x000001d4
+#define AOFF_task_link_count 0x000001d8
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x000001d8
+#define AOFF_task_tty 0x000001dc
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x000001dc
+#define AOFF_task_semundo 0x000001e0
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x000001e0
+#define AOFF_task_semsleeping 0x000001e4
#define ASIZ_task_semsleeping 0x00000004
#define AOFF_task_tss 0x000001e8
#define ASIZ_task_tss 0x00000388
#define AOFF_task_mm 0x00000578
#define ASIZ_task_mm 0x00000004
#define AOFF_task_sigmask_lock 0x0000057c
-#define ASIZ_task_sigmask_lock 0x00000000
-#define AOFF_task_sig 0x0000057c
+#define ASIZ_task_sigmask_lock 0x00000001
+#define AOFF_task_sig 0x00000580
#define ASIZ_task_sig 0x00000004
-#define AOFF_task_signal 0x00000580
+#define AOFF_task_signal 0x00000584
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x00000588
+#define AOFF_task_blocked 0x0000058c
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x00000590
+#define AOFF_task_sigqueue 0x00000594
#define ASIZ_task_sigqueue 0x00000004
-#define AOFF_task_sigqueue_tail 0x00000594
+#define AOFF_task_sigqueue_tail 0x00000598
#define ASIZ_task_sigqueue_tail 0x00000004
-#define AOFF_task_sas_ss_sp 0x00000598
+#define AOFF_task_sas_ss_sp 0x0000059c
#define ASIZ_task_sas_ss_sp 0x00000004
-#define AOFF_task_sas_ss_size 0x0000059c
+#define AOFF_task_sas_ss_size 0x000005a0
#define ASIZ_task_sas_ss_size 0x00000004
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000004
#define ASIZ_task_cap_inheritable 0x00000004
#define AOFF_task_cap_permitted 0x00000264
#define ASIZ_task_cap_permitted 0x00000004
-#define AOFF_task_rlim 0x00000268
+#define AOFF_task_user 0x00000268
+#define ASIZ_task_user 0x00000004
+#define AOFF_task_rlim 0x0000026c
#define ASIZ_task_rlim 0x00000050
-#define AOFF_task_used_math 0x000002b8
+#define AOFF_task_used_math 0x000002bc
#define ASIZ_task_used_math 0x00000002
-#define AOFF_task_comm 0x000002ba
+#define AOFF_task_comm 0x000002be
#define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count 0x000002cc
+#define AOFF_task_link_count 0x000002d0
#define ASIZ_task_link_count 0x00000004
-#define AOFF_task_tty 0x000002d0
+#define AOFF_task_tty 0x000002d4
#define ASIZ_task_tty 0x00000004
-#define AOFF_task_semundo 0x000002d4
+#define AOFF_task_semundo 0x000002d8
#define ASIZ_task_semundo 0x00000004
-#define AOFF_task_semsleeping 0x000002d8
+#define AOFF_task_semsleeping 0x000002dc
#define ASIZ_task_semsleeping 0x00000004
#define AOFF_task_tss 0x000002e0
#define ASIZ_task_tss 0x00000388
#define AOFF_task_mm 0x00000670
#define ASIZ_task_mm 0x00000004
#define AOFF_task_sigmask_lock 0x00000674
-#define ASIZ_task_sigmask_lock 0x00000001
-#define AOFF_task_sig 0x00000678
+#define ASIZ_task_sigmask_lock 0x00000008
+#define AOFF_task_sig 0x0000067c
#define ASIZ_task_sig 0x00000004
-#define AOFF_task_signal 0x0000067c
+#define AOFF_task_signal 0x00000680
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x00000684
+#define AOFF_task_blocked 0x00000688
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x0000068c
+#define AOFF_task_sigqueue 0x00000690
#define ASIZ_task_sigqueue 0x00000004
-#define AOFF_task_sigqueue_tail 0x00000690
+#define AOFF_task_sigqueue_tail 0x00000694
#define ASIZ_task_sigqueue_tail 0x00000004
-#define AOFF_task_sas_ss_sp 0x00000694
+#define AOFF_task_sas_ss_sp 0x00000698
#define ASIZ_task_sas_ss_sp 0x00000004
-#define AOFF_task_sas_ss_size 0x00000698
+#define AOFF_task_sas_ss_size 0x0000069c
#define ASIZ_task_sas_ss_size 0x00000004
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000004
-/* $Id: dma.h,v 1.26 1998/04/13 07:27:05 davem Exp $
+/* $Id: dma.h,v 1.28 1998/10/26 20:03:09 davem Exp $
* include/asm-sparc/dma.h
*
* Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
#include <asm/sbus.h>
#include <asm/delay.h>
#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
/* These are irrelevant for Sparc DMA, but we leave it in so that
* things can compile.
-/* $Id: fcntl.h,v 1.10 1998/08/26 10:33:29 davem Exp $ */
+/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */
#ifndef _SPARC_FCNTL_H
#define _SPARC_FCNTL_H
/* hardirq.h: 32-bit Sparc hard IRQ support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#ifndef __SPARC_HARDIRQ_H
#include <linux/tasks.h>
extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+ (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
#ifndef __SMP__
#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
-#define hardirq_endlock(cpu) do { } while(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() barrier()
-#else /* __SMP__ */
+#else
#include <asm/atomic.h>
#include <asm/spinlock.h>
@@ -32,37+39,33 @@ 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 || \
- *(((unsigned char *)(&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)
+static inline void release_irqlock(int cpu)
+{
+ /* if we didn't own the irq lock, just ignore.. */
+ if (global_irq_holder == (unsigned char) cpu) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+}
+
+static inline void hardirq_enter(int cpu)
+{
+ ++local_irq_count[cpu];
+ atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+ atomic_dec(&global_irq_count);
+ --local_irq_count[cpu];
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+ return !atomic_read(&global_irq_count) && !*(((volatile unsigned char *)(&global_irq_lock)));
+}
+
+#define hardirq_endlock(cpu) do { } while (0)
extern void synchronize_irq(void);
--- /dev/null
+/*----------------------------------------
+ PERFORMANCE INSTRUMENTATION
+ Guillaume Thouvenin 08/10/98
+ David S. Miller 10/06/98
+ ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface. First arg is operation code
+ * from enumeration below. The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ * unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec. That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+ /* Enable UltraSparc performance counters, ARG0 is pointer
+ * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+ * to 64-bit accumulator for D1 counter. ARG2 is a pointer to
+ * the initial PCR register value to use.
+ */
+ PERFCTR_ON,
+
+ /* Disable UltraSparc performance counters. The PCR is written
+ * with zero and the user counter accumulator pointers and
+ * working PCR register value are forgotten.
+ */
+ PERFCTR_OFF,
+
+ /* Add current D0 and D1 PIC values into user pointers given
+ * in PERFCTR_ON operation. The PIC is cleared before returning.
+ */
+ PERFCTR_READ,
+
+ /* Clear the PIC register. */
+ PERFCTR_CLRPIC,
+
+ /* Begin using a new PCR value, the pointer to which is passed
+ * in ARG0. The PIC is also cleared after the new PCR value is
+ * written.
+ */
+ PERFCTR_SETPCR,
+
+ /* Store in pointer given in ARG0 the current PCR register value
+ * being used.
+ */
+ PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included. --DaveM
+ */
+#ifndef __KERNEL__
+
+#define PRIV 0x00000001
+#define USR 0x00000002
+#define SYS 0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding */
+#define CYCLE_CNT 0x00000000
+#define INSTR_CNT 0x00000010
+#define DISPATCH0_IC_MISS 0x00000020
+#define DISPATCH0_STOREBUF 0x00000030
+#define IC_REF 0x00000080
+#define DC_RD 0x00000090
+#define DC_WR 0x000000A0
+#define LOAD_USE 0x000000B0
+#define EC_REF 0x000000C0
+#define EC_WRITE_HIT_RDO 0x000000D0
+#define EC_SNOOP_INV 0x000000E0
+#define EC_RD_HIT 0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding */
+#define CYCLE_CNT_D1 0x00000000
+#define INSTR_CNT_D1 0x00000800
+#define DISPATCH0_IC_MISPRED 0x00001000
+#define DISPATCH0_FP_USE 0x00001800
+#define IC_HIT 0x00004000
+#define DC_RD_HIT 0x00004800
+#define DC_WR_HIT 0x00005000
+#define LOAD_USE_RAW 0x00005800
+#define EC_HIT 0x00006000
+#define EC_WB 0x00006800
+#define EC_SNOOP_CB 0x00007000
+#define EC_IT_HIT 0x00007800
+
+struct vcounter_struct {
+ unsigned long long vcnt0;
+ unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
-/* $Id: sigcontext.h,v 1.12 1997/03/03 16:51:52 jj Exp $ */
+/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */
#ifndef __SPARC_SIGCONTEXT_H
#define __SPARC_SIGCONTEXT_H
@@ -52,6+52,16 @@ typedef struct { } si_fpqueue [16];
} __siginfo_fpu_t;
+/* This magic should be in g_upper[0] for all upper parts
+ to be valid.
+ This is generated by sparc64 only, but for 32bit processes,
+ so we define it here as well. */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
+typedef struct {
+ unsigned int g_upper[8];
+ unsigned int o_upper[8];
+} siginfo_extra_v8plus_t;
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC_SIGCONTEXT_H) */
-/* 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 <asm/atomic.h>
-#include <asm/hardirq.h>
-
-/* 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.
- */
-#define get_active_bhs() (bh_mask & bh_active)
-
-#ifdef __SMP__
-
-extern atomic_t __sparc_bh_counter;
-
-#define start_bh_atomic() \
- do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0)
-
-#define end_bh_atomic() atomic_dec(&__sparc_bh_counter)
-
-#include <asm/spinlock.h>
-
-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 remove_bh(nr) \
-do { unsigned long flags; \
- int ent = nr; \
- spin_lock_irqsave(&global_bh_lock, flags); \
- bh_base[ent] = NULL; \
- 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(cpu) \
-({ \
- int ret = 1; \
- if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \
- atomic_dec(&__sparc_bh_counter); \
- ret = 0; \
- } \
- ret; \
-})
-#define softirq_endlock(cpu) 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__) */
-
-extern int __sparc_bh_counter;
-
-#define start_bh_atomic() do { __sparc_bh_counter++; barrier(); } while(0)
-#define end_bh_atomic() do { barrier(); __sparc_bh_counter--; } while(0)
-
-#define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
-#define softirq_endlock(cpu) (__sparc_bh_counter = 0)
-#define clear_active_bhs(x) (bh_active &= ~(x))
-#define synchronize_bh() barrier() /* XXX implement SMP version -DaveM */
-
-#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 remove_bh(nr) \
-do { int ent = nr; \
- bh_base[ent] = NULL; \
- 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 */
+/* softirq.h: 32-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ */
+
+#ifndef __SPARC_SOFTIRQ_H
+#define __SPARC_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/hardirq.h>
+
+extern unsigned int local_bh_count[NR_CPUS];
+
+#define get_active_bhs() (bh_mask & bh_active)
+
+#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 global_bh_lock;
+extern atomic_t global_bh_count;
+extern spinlock_t sparc_bh_lock;
+
+extern void synchronize_bh(void);
+
+static inline void clear_active_bhs(unsigned int mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ bh_active &= ~(mask);
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ bh_base[nr] = routine;
+ bh_mask_count[nr] = 0;
+ bh_mask |= 1 << nr;
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void remove_bh(int nr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+extern inline void mark_bh(int nr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ bh_active |= (1 << nr);
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ bh_mask &= ~(1 << nr);
+ bh_mask_count[nr]++;
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+ synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&sparc_bh_lock, flags);
+ if (!--bh_mask_count[nr])
+ bh_mask |= 1 << nr;
+ spin_unlock_irqrestore(&sparc_bh_lock, flags);
+}
+
+static inline void start_bh_atomic(void)
+{
+ atomic_inc(&global_bh_lock);
+ synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+ atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+ if (atomic_add_return(1, &global_bh_count) == 1) {
+ if (atomic_read(&global_bh_lock) == 0) {
+ ++local_bh_count[cpu];
+ return 1;
+ }
+ }
+ atomic_dec(&global_bh_count);
+ return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+ local_bh_count[cpu]--;
+ atomic_dec(&global_bh_count);
+}
+
+#else
+
+#define clear_active_bhs(x) (bh_active &= ~(x))
+#define mark_bh(nr) (bh_active |= (1 << (nr)))
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu) (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
+#define softirq_endlock(cpu) (local_bh_count[cpu] = 0)
+#define synchronize_bh() barrier()
+
+/*
+ * 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]++;
+ synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+ if (!--bh_mask_count[nr])
+ bh_mask |= 1 << nr;
+}
+
+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 remove_bh(int nr)
+{
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+}
+
+extern inline void start_bh_atomic(void)
+{
+ local_bh_count[0]++;
+ barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+ barrier();
+ local_bh_count[0]--;
+}
+
+#endif /* SMP */
+
+#endif /* __SPARC_SOFTIRQ_H */
#ifndef __SMP__
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
- typedef struct { } spinlock_t;
- #define SPIN_LOCK_UNLOCKED { }
-#else
- typedef unsigned char spinlock_t;
- #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
#define spin_lock_init(lock) do { } while(0)
#define spin_lock(lock) do { } while(0)
@@ -270,18+265,16 @@ typedef struct { volatile unsigned int lock; } rwlock_t; /* Sort of like atomic_t's on Sparc, but even more clever.
*
* ------------------------------------
- * | 16-bit counter | clock | wlock | rwlock_t
+ * | 24-bit counter | wlock | rwlock_t
* ------------------------------------
- * 31 16 15 8 7 0
+ * 31 8 7 0
*
- * wlock signifies the one writer is in, the clock protects
- * counter bumping, however a reader must acquire wlock
- * before he can bump the counter on a read_lock().
- * Similarly a writer, once he has the wlock, must await
- * for the top 24 bits to all clear before he can finish
- * going in (this includes the clock of course).
+ * wlock signifies the one writer is in or somebody is updating
+ * counter. For a writer, if he successfully acquires the wlock,
+ * but counter is non-zero, he has to release the lock and wait,
+ * till both counter and wlock are zero.
*
- * Unfortunately this scheme limits us to ~65,000 cpus.
+ * Unfortunately this scheme limits us to ~16,000,000 cpus.
*/
extern __inline__ void _read_lock(rwlock_t *rw)
{
@@ -310,7+303,7 @@ extern __inline__ void _read_unlock(rwlock_t *rw) __asm__ __volatile__("
mov %%o7, %%g4
call ___rw_read_exit
- ldstub [%%g1 + 2], %%g2
+ ldstub [%%g1 + 3], %%g2
" : /* no outputs */
: "r" (lp)
: "g2", "g4", "g7", "memory", "cc");
-/* $Id: system.h,v 1.70 1998/09/29 09:46:32 davem Exp $ */
+/* $Id: system.h,v 1.71 1998/10/13 03:51:06 jj Exp $ */
#include <linux/config.h>
#ifndef __SPARC_SYSTEM_H
@@ -235,18+235,16 @@ extern __inline__ unsigned long read_psr_and_cli(void)
extern unsigned char global_irq_holder;
-#define save_flags(x) \
-do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
- ((getipl() & PSR_PIL) ? 2 : 0))); } while(0)
-
#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
#ifdef DEBUG_IRQLOCK
extern void __global_cli(void);
extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
extern void __global_restore_flags(unsigned long flags);
#define cli() __global_cli()
#define sti() __global_sti()
+#define save_flags(flags) ((flags)=__global_save_flags())
#define restore_flags(flags) __global_restore_flags(flags)
#else
-/* $Id: unistd.h,v 1.47 1998/09/21 05:07:22 jj Exp $ */
+/* $Id: unistd.h,v 1.48 1998/10/07 01:27:50 davem Exp $ */
#ifndef _SPARC_UNISTD_H
#define _SPARC_UNISTD_H
#define __NR_chmod 15 /* Common */
#define __NR_lchown 16 /* Common */
#define __NR_brk 17 /* Common */
-/* #define __NR_ni_syscall 18 ENOSYS under SunOS */
+/* #define __NR_ni_syscall 18 RESERVED for sparc64 perf-counter syscall */
#define __NR_lseek 19 /* Common */
#define __NR_getpid 20 /* Common */
#define __NR_capget 21 /* Linux Specific */
#define AOFF_task_semsleeping 0x00000370
#define ASIZ_task_semsleeping 0x00000008
#define AOFF_task_tss 0x00000380
-#define ASIZ_task_tss 0x00000440
-#define AOFF_task_fs 0x000007c0
+#define ASIZ_task_tss 0x00000470
+#define AOFF_task_fs 0x000007f0
#define ASIZ_task_fs 0x00000008
-#define AOFF_task_files 0x000007c8
+#define AOFF_task_files 0x000007f8
#define ASIZ_task_files 0x00000008
-#define AOFF_task_mm 0x000007d0
+#define AOFF_task_mm 0x00000800
#define ASIZ_task_mm 0x00000008
-#define AOFF_task_sigmask_lock 0x000007d8
-#define ASIZ_task_sigmask_lock 0x00000000
-#define AOFF_task_sig 0x000007d8
+#define AOFF_task_sigmask_lock 0x00000808
+#define ASIZ_task_sigmask_lock 0x00000001
+#define AOFF_task_sig 0x00000810
#define ASIZ_task_sig 0x00000008
-#define AOFF_task_signal 0x000007e0
+#define AOFF_task_signal 0x00000818
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x000007e8
+#define AOFF_task_blocked 0x00000820
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x000007f0
+#define AOFF_task_sigqueue 0x00000828
#define ASIZ_task_sigqueue 0x00000008
-#define AOFF_task_sigqueue_tail 0x000007f8
+#define AOFF_task_sigqueue_tail 0x00000830
#define ASIZ_task_sigqueue_tail 0x00000008
-#define AOFF_task_sas_ss_sp 0x00000800
+#define AOFF_task_sas_ss_sp 0x00000838
#define ASIZ_task_sas_ss_sp 0x00000008
-#define AOFF_task_sas_ss_size 0x00000808
+#define AOFF_task_sas_ss_size 0x00000840
#define ASIZ_task_sas_ss_size 0x00000008
-#define ASIZ_task 0x00000810
+#define ASIZ_task 0x00000850
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000008
#define AOFF_mm_mmap_cache 0x00000008
#define ASIZ_thread_sig_address 0x00000008
#define AOFF_thread_sig_desc 0x000003f0
#define ASIZ_thread_sig_desc 0x00000008
-#define AOFF_thread_fpdepth 0x000003f8
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0 0x00000408
+#define ASIZ_thread_kernel_cntd0 0x00000008
+#define AOFF_thread_kernel_cntd1 0x00000410
+#define ASIZ_thread_kernel_cntd1 0x00000008
+#define AOFF_thread_pcr_reg 0x00000418
+#define ASIZ_thread_pcr_reg 0x00000008
+#define AOFF_thread_fpdepth 0x00000420
#define ASIZ_thread_fpdepth 0x00000001
-#define AOFF_thread_fpsaved 0x000003f9
+#define AOFF_thread_fpsaved 0x00000421
#define ASIZ_thread_fpsaved 0x00000007
-#define AOFF_thread_gsr 0x00000400
+#define AOFF_thread_gsr 0x00000428
#define ASIZ_thread_gsr 0x00000007
-#define AOFF_thread_xfsr 0x00000408
+#define AOFF_thread_xfsr 0x00000430
#define ASIZ_thread_xfsr 0x00000038
-#define ASIZ_thread 0x00000440
+#define ASIZ_thread 0x00000470
#else /* __SMP__ */
+#ifndef SPIN_LOCK_DEBUG
+
#define AOFF_task_state 0x00000000
#define ASIZ_task_state 0x00000008
#define AOFF_task_flags 0x00000008
#define AOFF_task_semsleeping 0x00000560
#define ASIZ_task_semsleeping 0x00000008
#define AOFF_task_tss 0x00000570
-#define ASIZ_task_tss 0x00000440
-#define AOFF_task_fs 0x000009b0
+#define ASIZ_task_tss 0x00000470
+#define AOFF_task_fs 0x000009e0
#define ASIZ_task_fs 0x00000008
-#define AOFF_task_files 0x000009b8
+#define AOFF_task_files 0x000009e8
#define ASIZ_task_files 0x00000008
-#define AOFF_task_mm 0x000009c0
+#define AOFF_task_mm 0x000009f0
#define ASIZ_task_mm 0x00000008
-#define AOFF_task_sigmask_lock 0x000009c8
+#define AOFF_task_sigmask_lock 0x000009f8
#define ASIZ_task_sigmask_lock 0x00000001
-#define AOFF_task_sig 0x000009d0
+#define AOFF_task_sig 0x00000a00
+#define ASIZ_task_sig 0x00000008
+#define AOFF_task_signal 0x00000a08
+#define ASIZ_task_signal 0x00000008
+#define AOFF_task_blocked 0x00000a10
+#define ASIZ_task_blocked 0x00000008
+#define AOFF_task_sigqueue 0x00000a18
+#define ASIZ_task_sigqueue 0x00000008
+#define AOFF_task_sigqueue_tail 0x00000a20
+#define ASIZ_task_sigqueue_tail 0x00000008
+#define AOFF_task_sas_ss_sp 0x00000a28
+#define ASIZ_task_sas_ss_sp 0x00000008
+#define AOFF_task_sas_ss_size 0x00000a30
+#define ASIZ_task_sas_ss_size 0x00000008
+#define ASIZ_task 0x00000a40
+#define AOFF_mm_mmap 0x00000000
+#define ASIZ_mm_mmap 0x00000008
+#define AOFF_mm_mmap_cache 0x00000008
+#define ASIZ_mm_mmap_cache 0x00000008
+#define AOFF_mm_pgd 0x00000010
+#define ASIZ_mm_pgd 0x00000008
+#define AOFF_mm_count 0x00000018
+#define ASIZ_mm_count 0x00000004
+#define AOFF_mm_map_count 0x0000001c
+#define ASIZ_mm_map_count 0x00000004
+#define AOFF_mm_mmap_sem 0x00000020
+#define ASIZ_mm_mmap_sem 0x00000010
+#define AOFF_mm_context 0x00000030
+#define ASIZ_mm_context 0x00000008
+#define AOFF_mm_start_code 0x00000038
+#define ASIZ_mm_start_code 0x00000008
+#define AOFF_mm_end_code 0x00000040
+#define ASIZ_mm_end_code 0x00000008
+#define AOFF_mm_start_data 0x00000048
+#define ASIZ_mm_start_data 0x00000008
+#define AOFF_mm_end_data 0x00000050
+#define ASIZ_mm_end_data 0x00000008
+#define AOFF_mm_start_brk 0x00000058
+#define ASIZ_mm_start_brk 0x00000008
+#define AOFF_mm_brk 0x00000060
+#define ASIZ_mm_brk 0x00000008
+#define AOFF_mm_start_stack 0x00000068
+#define ASIZ_mm_start_stack 0x00000008
+#define AOFF_mm_arg_start 0x00000070
+#define ASIZ_mm_arg_start 0x00000008
+#define AOFF_mm_arg_end 0x00000078
+#define ASIZ_mm_arg_end 0x00000008
+#define AOFF_mm_env_start 0x00000080
+#define ASIZ_mm_env_start 0x00000008
+#define AOFF_mm_env_end 0x00000088
+#define ASIZ_mm_env_end 0x00000008
+#define AOFF_mm_rss 0x00000090
+#define ASIZ_mm_rss 0x00000008
+#define AOFF_mm_total_vm 0x00000098
+#define ASIZ_mm_total_vm 0x00000008
+#define AOFF_mm_locked_vm 0x000000a0
+#define ASIZ_mm_locked_vm 0x00000008
+#define AOFF_mm_def_flags 0x000000a8
+#define ASIZ_mm_def_flags 0x00000008
+#define AOFF_mm_cpu_vm_mask 0x000000b0
+#define ASIZ_mm_cpu_vm_mask 0x00000008
+#define AOFF_mm_segments 0x000000b8
+#define ASIZ_mm_segments 0x00000008
+#define ASIZ_mm 0x000000c0
+#define AOFF_thread_ksp 0x00000000
+#define ASIZ_thread_ksp 0x00000008
+#define AOFF_thread_wstate 0x00000008
+#define ASIZ_thread_wstate 0x00000002
+#define AOFF_thread_cwp 0x0000000a
+#define ASIZ_thread_cwp 0x00000002
+#define AOFF_thread_flags 0x0000000c
+#define ASIZ_thread_flags 0x00000002
+#define AOFF_thread_ctx 0x0000000e
+#define ASIZ_thread_ctx 0x00000002
+#define AOFF_thread_w_saved 0x00000010
+#define ASIZ_thread_w_saved 0x00000002
+#define AOFF_thread_new_signal 0x00000012
+#define ASIZ_thread_new_signal 0x00000002
+#define AOFF_thread____pad 0x00000014
+#define ASIZ_thread____pad 0x00000004
+#define AOFF_thread_current_ds 0x00000018
+#define ASIZ_thread_current_ds 0x00000008
+#define AOFF_thread_kregs 0x00000020
+#define ASIZ_thread_kregs 0x00000008
+#define AOFF_thread_utraps 0x00000028
+#define ASIZ_thread_utraps 0x00000008
+#define AOFF_thread_reg_window 0x00000030
+#define ASIZ_thread_reg_window 0x00000380
+#define AOFF_thread_rwbuf_stkptrs 0x000003b0
+#define ASIZ_thread_rwbuf_stkptrs 0x00000038
+#define AOFF_thread_sig_address 0x000003e8
+#define ASIZ_thread_sig_address 0x00000008
+#define AOFF_thread_sig_desc 0x000003f0
+#define ASIZ_thread_sig_desc 0x00000008
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0 0x00000408
+#define ASIZ_thread_kernel_cntd0 0x00000008
+#define AOFF_thread_kernel_cntd1 0x00000410
+#define ASIZ_thread_kernel_cntd1 0x00000008
+#define AOFF_thread_pcr_reg 0x00000418
+#define ASIZ_thread_pcr_reg 0x00000008
+#define AOFF_thread_fpdepth 0x00000420
+#define ASIZ_thread_fpdepth 0x00000001
+#define AOFF_thread_fpsaved 0x00000421
+#define ASIZ_thread_fpsaved 0x00000007
+#define AOFF_thread_gsr 0x00000428
+#define ASIZ_thread_gsr 0x00000007
+#define AOFF_thread_xfsr 0x00000430
+#define ASIZ_thread_xfsr 0x00000038
+#define ASIZ_thread 0x00000470
+
+#else /* SPIN_LOCK_DEBUG */
+
+#define AOFF_task_state 0x00000000
+#define ASIZ_task_state 0x00000008
+#define AOFF_task_flags 0x00000008
+#define ASIZ_task_flags 0x00000008
+#define AOFF_task_sigpending 0x00000010
+#define ASIZ_task_sigpending 0x00000004
+#define AOFF_task_addr_limit 0x00000018
+#define ASIZ_task_addr_limit 0x00000008
+#define AOFF_task_exec_domain 0x00000020
+#define ASIZ_task_exec_domain 0x00000008
+#define AOFF_task_need_resched 0x00000028
+#define ASIZ_task_need_resched 0x00000008
+#define AOFF_task_counter 0x00000030
+#define ASIZ_task_counter 0x00000008
+#define AOFF_task_priority 0x00000038
+#define ASIZ_task_priority 0x00000008
+#define AOFF_task_has_cpu 0x00000040
+#define ASIZ_task_has_cpu 0x00000004
+#define AOFF_task_processor 0x00000044
+#define ASIZ_task_processor 0x00000004
+#define AOFF_task_last_processor 0x00000048
+#define ASIZ_task_last_processor 0x00000004
+#define AOFF_task_lock_depth 0x0000004c
+#define ASIZ_task_lock_depth 0x00000004
+#define AOFF_task_next_task 0x00000050
+#define ASIZ_task_next_task 0x00000008
+#define AOFF_task_prev_task 0x00000058
+#define ASIZ_task_prev_task 0x00000008
+#define AOFF_task_next_run 0x00000060
+#define ASIZ_task_next_run 0x00000008
+#define AOFF_task_prev_run 0x00000068
+#define ASIZ_task_prev_run 0x00000008
+#define AOFF_task_binfmt 0x00000070
+#define ASIZ_task_binfmt 0x00000008
+#define AOFF_task_exit_code 0x00000078
+#define ASIZ_task_exit_code 0x00000004
+#define AOFF_task_exit_signal 0x0000007c
+#define ASIZ_task_exit_signal 0x00000004
+#define AOFF_task_pdeath_signal 0x00000080
+#define ASIZ_task_pdeath_signal 0x00000004
+#define AOFF_task_personality 0x00000088
+#define ASIZ_task_personality 0x00000008
+#define AOFF_task_pid 0x00000094
+#define ASIZ_task_pid 0x00000004
+#define AOFF_task_pgrp 0x00000098
+#define ASIZ_task_pgrp 0x00000004
+#define AOFF_task_tty_old_pgrp 0x0000009c
+#define ASIZ_task_tty_old_pgrp 0x00000004
+#define AOFF_task_session 0x000000a0
+#define ASIZ_task_session 0x00000004
+#define AOFF_task_leader 0x000000a4
+#define ASIZ_task_leader 0x00000004
+#define AOFF_task_p_opptr 0x000000a8
+#define ASIZ_task_p_opptr 0x00000008
+#define AOFF_task_p_pptr 0x000000b0
+#define ASIZ_task_p_pptr 0x00000008
+#define AOFF_task_p_cptr 0x000000b8
+#define ASIZ_task_p_cptr 0x00000008
+#define AOFF_task_p_ysptr 0x000000c0
+#define ASIZ_task_p_ysptr 0x00000008
+#define AOFF_task_p_osptr 0x000000c8
+#define ASIZ_task_p_osptr 0x00000008
+#define AOFF_task_pidhash_next 0x000000d0
+#define ASIZ_task_pidhash_next 0x00000008
+#define AOFF_task_pidhash_pprev 0x000000d8
+#define ASIZ_task_pidhash_pprev 0x00000008
+#define AOFF_task_tarray_ptr 0x000000e0
+#define ASIZ_task_tarray_ptr 0x00000008
+#define AOFF_task_wait_chldexit 0x000000e8
+#define ASIZ_task_wait_chldexit 0x00000008
+#define AOFF_task_timeout 0x000000f0
+#define ASIZ_task_timeout 0x00000008
+#define AOFF_task_policy 0x000000f8
+#define ASIZ_task_policy 0x00000008
+#define AOFF_task_rt_priority 0x00000100
+#define ASIZ_task_rt_priority 0x00000008
+#define AOFF_task_it_real_value 0x00000108
+#define ASIZ_task_it_real_value 0x00000008
+#define AOFF_task_it_prof_value 0x00000110
+#define ASIZ_task_it_prof_value 0x00000008
+#define AOFF_task_it_virt_value 0x00000118
+#define ASIZ_task_it_virt_value 0x00000008
+#define AOFF_task_it_real_incr 0x00000120
+#define ASIZ_task_it_real_incr 0x00000008
+#define AOFF_task_it_prof_incr 0x00000128
+#define ASIZ_task_it_prof_incr 0x00000008
+#define AOFF_task_it_virt_incr 0x00000130
+#define ASIZ_task_it_virt_incr 0x00000008
+#define AOFF_task_real_timer 0x00000138
+#define ASIZ_task_real_timer 0x00000028
+#define AOFF_task_times 0x00000160
+#define ASIZ_task_times 0x00000020
+#define AOFF_task_start_time 0x00000180
+#define ASIZ_task_start_time 0x00000008
+#define AOFF_task_per_cpu_utime 0x00000188
+#define ASIZ_task_per_cpu_utime 0x00000100
+#define AOFF_task_min_flt 0x00000388
+#define ASIZ_task_min_flt 0x00000008
+#define AOFF_task_maj_flt 0x00000390
+#define ASIZ_task_maj_flt 0x00000008
+#define AOFF_task_nswap 0x00000398
+#define ASIZ_task_nswap 0x00000008
+#define AOFF_task_cmin_flt 0x000003a0
+#define ASIZ_task_cmin_flt 0x00000008
+#define AOFF_task_cmaj_flt 0x000003a8
+#define ASIZ_task_cmaj_flt 0x00000008
+#define AOFF_task_cnswap 0x000003b0
+#define ASIZ_task_cnswap 0x00000008
+#define AOFF_task_swap_address 0x000003c0
+#define ASIZ_task_swap_address 0x00000008
+#define AOFF_task_old_maj_flt 0x000003c8
+#define ASIZ_task_old_maj_flt 0x00000008
+#define AOFF_task_dec_flt 0x000003d0
+#define ASIZ_task_dec_flt 0x00000008
+#define AOFF_task_swap_cnt 0x000003d8
+#define ASIZ_task_swap_cnt 0x00000008
+#define AOFF_task_uid 0x000003e0
+#define ASIZ_task_uid 0x00000004
+#define AOFF_task_euid 0x000003e4
+#define ASIZ_task_euid 0x00000004
+#define AOFF_task_suid 0x000003e8
+#define ASIZ_task_suid 0x00000004
+#define AOFF_task_fsuid 0x000003ec
+#define ASIZ_task_fsuid 0x00000004
+#define AOFF_task_gid 0x000003f0
+#define ASIZ_task_gid 0x00000004
+#define AOFF_task_egid 0x000003f4
+#define ASIZ_task_egid 0x00000004
+#define AOFF_task_sgid 0x000003f8
+#define ASIZ_task_sgid 0x00000004
+#define AOFF_task_fsgid 0x000003fc
+#define ASIZ_task_fsgid 0x00000004
+#define AOFF_task_ngroups 0x00000400
+#define ASIZ_task_ngroups 0x00000004
+#define AOFF_task_groups 0x00000404
+#define ASIZ_task_groups 0x00000080
+#define AOFF_task_cap_effective 0x00000484
+#define ASIZ_task_cap_effective 0x00000004
+#define AOFF_task_cap_inheritable 0x00000488
+#define ASIZ_task_cap_inheritable 0x00000004
+#define AOFF_task_cap_permitted 0x0000048c
+#define ASIZ_task_cap_permitted 0x00000004
+#define AOFF_task_user 0x00000490
+#define ASIZ_task_user 0x00000008
+#define AOFF_task_rlim 0x00000498
+#define ASIZ_task_rlim 0x000000a0
+#define AOFF_task_used_math 0x00000538
+#define ASIZ_task_used_math 0x00000002
+#define AOFF_task_comm 0x0000053a
+#define ASIZ_task_comm 0x00000010
+#define AOFF_task_link_count 0x0000054c
+#define ASIZ_task_link_count 0x00000004
+#define AOFF_task_tty 0x00000550
+#define ASIZ_task_tty 0x00000008
+#define AOFF_task_semundo 0x00000558
+#define ASIZ_task_semundo 0x00000008
+#define AOFF_task_semsleeping 0x00000560
+#define ASIZ_task_semsleeping 0x00000008
+#define AOFF_task_tss 0x00000570
+#define ASIZ_task_tss 0x00000470
+#define AOFF_task_fs 0x000009e0
+#define ASIZ_task_fs 0x00000008
+#define AOFF_task_files 0x000009e8
+#define ASIZ_task_files 0x00000008
+#define AOFF_task_mm 0x000009f0
+#define ASIZ_task_mm 0x00000008
+#define AOFF_task_sigmask_lock 0x000009f8
+#define ASIZ_task_sigmask_lock 0x0000000c
+#define AOFF_task_sig 0x00000a08
#define ASIZ_task_sig 0x00000008
-#define AOFF_task_signal 0x000009d8
+#define AOFF_task_signal 0x00000a10
#define ASIZ_task_signal 0x00000008
-#define AOFF_task_blocked 0x000009e0
+#define AOFF_task_blocked 0x00000a18
#define ASIZ_task_blocked 0x00000008
-#define AOFF_task_sigqueue 0x000009e8
+#define AOFF_task_sigqueue 0x00000a20
#define ASIZ_task_sigqueue 0x00000008
-#define AOFF_task_sigqueue_tail 0x000009f0
+#define AOFF_task_sigqueue_tail 0x00000a28
#define ASIZ_task_sigqueue_tail 0x00000008
-#define AOFF_task_sas_ss_sp 0x000009f8
+#define AOFF_task_sas_ss_sp 0x00000a30
#define ASIZ_task_sas_ss_sp 0x00000008
-#define AOFF_task_sas_ss_size 0x00000a00
+#define AOFF_task_sas_ss_size 0x00000a38
#define ASIZ_task_sas_ss_size 0x00000008
-#define ASIZ_task 0x00000a10
+#define ASIZ_task 0x00000a40
#define AOFF_mm_mmap 0x00000000
#define ASIZ_mm_mmap 0x00000008
#define AOFF_mm_mmap_cache 0x00000008
#define ASIZ_thread_sig_address 0x00000008
#define AOFF_thread_sig_desc 0x000003f0
#define ASIZ_thread_sig_desc 0x00000008
-#define AOFF_thread_fpdepth 0x000003f8
+#define AOFF_thread_user_cntd0 0x000003f8
+#define ASIZ_thread_user_cntd0 0x00000008
+#define AOFF_thread_user_cntd1 0x00000400
+#define ASIZ_thread_user_cntd1 0x00000008
+#define AOFF_thread_kernel_cntd0 0x00000408
+#define ASIZ_thread_kernel_cntd0 0x00000008
+#define AOFF_thread_kernel_cntd1 0x00000410
+#define ASIZ_thread_kernel_cntd1 0x00000008
+#define AOFF_thread_pcr_reg 0x00000418
+#define ASIZ_thread_pcr_reg 0x00000008
+#define AOFF_thread_fpdepth 0x00000420
#define ASIZ_thread_fpdepth 0x00000001
-#define AOFF_thread_fpsaved 0x000003f9
+#define AOFF_thread_fpsaved 0x00000421
#define ASIZ_thread_fpsaved 0x00000007
-#define AOFF_thread_gsr 0x00000400
+#define AOFF_thread_gsr 0x00000428
#define ASIZ_thread_gsr 0x00000007
-#define AOFF_thread_xfsr 0x00000408
+#define AOFF_thread_xfsr 0x00000430
#define ASIZ_thread_xfsr 0x00000038
-#define ASIZ_thread 0x00000440
+#define ASIZ_thread 0x00000470
+#endif /* SPIN_LOCK_DEBUG */
#endif /* __SMP__ */
-/* $Id: dma.h,v 1.8 1998/04/13 07:27:06 davem Exp $
+/* $Id: dma.h,v 1.9 1998/10/26 20:03:15 davem Exp $
* include/asm-sparc64/dma.h
*
* Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
#include <asm/sbus.h>
#include <asm/delay.h>
#include <asm/oplib.h>
+#include <asm/spinlock.h>
+
+extern spinlock_t dma_spin_lock;
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dma_spin_lock, flags);
+ return flags;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
/* These are irrelevant for Sparc DMA, but we leave it in so that
* things can compile.
-/* $Id: fcntl.h,v 1.4 1998/08/26 10:33:36 davem Exp $ */
+/* $Id: fcntl.h,v 1.5 1998/10/26 20:03:15 davem Exp $ */
#ifndef _SPARC64_FCNTL_H
#define _SPARC64_FCNTL_H
-/* $Id: floppy.h,v 1.15 1998/09/14 18:28:37 ecd Exp $
+/* $Id: floppy.h,v 1.16 1998/10/06 20:32:15 ecd Exp $
* asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -661,8+661,9 @@ __initfunc(static unsigned long sun_floppy_init(void)) tmp |= FCR_LDE;
ns87303_writeb(config, FCR, tmp);
+ tmp = sun_floppy_types[0];
sun_floppy_types[0] = sun_floppy_types[1];
- sun_floppy_types[1] = 0;
+ sun_floppy_types[1] = tmp;
if (sun_pci_broken_drive != -1) {
sun_pci_broken_drive = 1 - sun_pci_broken_drive;
/* hardirq.h: 64-bit Sparc hard IRQ support.
*
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
*/
#ifndef __SPARC64_HARDIRQ_H
@@ -13,7+13,12 @@ extern unsigned int local_irq_count; #else
#define local_irq_count (cpu_data[smp_processor_id()].irq_count)
#endif
-#define in_interrupt() (local_irq_count != 0)
+
+/*
+ * Are we in an interrupt context? Either doing bottom half
+ * or hardware interrupt processing?
+ */
+#define in_interrupt() ((local_irq_count + local_bh_count) != 0)
#ifndef __SMP__
@@ -47,7+52,7 @@ static inline void release_irqlock(int cpu)
static inline void hardirq_enter(int cpu)
{
- ++cpu_data[cpu].irq_count;
+ ++(cpu_data[cpu].irq_count);
atomic_inc(&global_irq_count);
membar("#StoreLoad | #StoreStore");
}
@@ -56,31+61,16 @@ static inline void hardirq_exit(int cpu) {
membar("#StoreStore | #LoadStore");
atomic_dec(&global_irq_count);
- --cpu_data[cpu].irq_count;
+ --(cpu_data[cpu].irq_count);
}
static inline int hardirq_trylock(int cpu)
{
- unsigned long flags;
-
- __save_and_cli(flags);
- atomic_inc(&global_irq_count);
- if(atomic_read(&global_irq_count) != 1 ||
- (*(((unsigned char *)(&global_irq_lock)))) != 0) {
- atomic_dec(&global_irq_count);
- __restore_flags(flags);
- return 0;
- }
- ++cpu_data[cpu].irq_count;
- return 1;
+ return (! atomic_read(&global_irq_count) &&
+ ! spin_is_locked (&global_irq_lock));
}
-static inline void hardirq_endlock(int cpu)
-{
- __cli();
- hardirq_exit(cpu);
- __sti();
-}
+#define hardirq_endlock(cpu) do { } while (0)
extern void synchronize_irq(void);
-/* $Id: ioctl.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+/* $Id: ioctl.h,v 1.2 1998/10/15 05:40:38 jj Exp $ */
#ifndef _SPARC64_IOCTL_H
#define _SPARC64_IOCTL_H
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+/* ...and for the PCMCIA... */
+
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+
#endif /* !(_SPARC64_IOCTL_H) */
-/* $Id: mmu_context.h,v 1.31 1998/09/24 03:22:01 davem Exp $ */
+/* $Id: mmu_context.h,v 1.32 1998/10/13 14:03:52 davem Exp $ */
#ifndef __SPARC64_MMU_CONTEXT_H
#define __SPARC64_MMU_CONTEXT_H
@@ -118,11+118,10 @@ extern __inline__ void __get_mmu_context(struct task_struct *tsk) * the context for the new mm so we see the new mappings.
*/
#define activate_context(__tsk) \
-do { unsigned long __flags; \
- __save_and_cli(__flags); \
- flushw_user(); \
+do { flushw_user(); \
+ spin_lock(&scheduler_lock); \
__get_mmu_context(__tsk); \
- __restore_flags(__flags); \
+ spin_unlock(&scheduler_lock); \
} while(0)
#endif /* !(__ASSEMBLY__) */
#define SPARC_SOL_EMUL "usr/gnemul/solaris/"
static inline struct dentry *
-__sparc64_lookup_dentry(const char *name, int follow_link)
+__sparc64_lookup_dentry(const char *name, int lookup_flags)
{
struct dentry *base;
char *emul;
@@ -29,18+29,18 @@ __sparc64_lookup_dentry(const char *name, int follow_link) return NULL;
}
- base = lookup_dentry (emul, dget (current->fs->root), 1);
+ base = lookup_dentry (emul, dget (current->fs->root), (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK));
if (IS_ERR (base)) return NULL;
- base = lookup_dentry (name, base, follow_link);
+ base = lookup_dentry (name, base, lookup_flags);
if (IS_ERR (base)) return NULL;
if (!base->d_inode) {
struct dentry *fromroot;
- fromroot = lookup_dentry (name, dget (current->fs->root), follow_link);
+ fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags);
if (IS_ERR (fromroot)) return base;
@@ -55,9+55,9 @@ __sparc64_lookup_dentry(const char *name, int follow_link) return base;
}
-#define __prefix_lookup_dentry(name, follow_link) \
+#define __prefix_lookup_dentry(name, lookup_flags) \
if (current->personality) { \
- dentry = __sparc64_lookup_dentry (name, follow_link); \
+ dentry = __sparc64_lookup_dentry (name, lookup_flags); \
if (dentry) return dentry; \
}
-/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
+/* $Id: oplib.h,v 1.9 1998/10/06 20:56:05 ecd Exp $
* oplib.h: Describes the interface and available routines in the
* Linux Prom library.
*
@@ -117,8+117,8 @@ extern void prom_halt(void) __attribute__ ((noreturn)); * kernel is still active, the prom will call this routine.
*
*/
-typedef void (*sync_func_t)(long *cmd);
-extern void prom_setsync(sync_func_t func_ptr);
+typedef int (*callback_func_t)(long *cmd);
+extern void prom_setcallback(callback_func_t func_ptr);
/* Acquire the IDPROM of the root node in the prom device tree. This
* gets passed a buffer where you would like it stuffed. The return value
-/* $Id: page.h,v 1.23 1998/06/12 14:54:33 jj Exp $ */
+/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
#ifndef _SPARC64_PAGE_H
#define _SPARC64_PAGE_H
#ifndef __ASSEMBLY__
-#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
+extern void clear_page(unsigned long page);
extern void copy_page(unsigned long to, unsigned long from);
/* GROSS, defining this makes gcc pass these types as aggregates,
--- /dev/null
+/*----------------------------------------
+ PERFORMANCE INSTRUMENTATION
+ Guillaume Thouvenin 08/10/98
+ David S. Miller 10/06/98
+ ---------------------------------------*/
+#ifndef PERF_COUNTER_API
+#define PERF_COUNTER_API
+
+/* sys_perfctr() interface. First arg is operation code
+ * from enumeration below. The meaning of further arguments
+ * are determined by the operation code.
+ *
+ * int sys_perfctr(int opcode, unsigned long arg0,
+ * unsigned long arg1, unsigned long arg2)
+ *
+ * Pointers which are passed by the user are pointers to 64-bit
+ * integers.
+ *
+ * Once enabled, performance counter state is retained until the
+ * process either exits or performs an exec. That is, performance
+ * counters remain enabled for fork/clone children.
+ */
+enum perfctr_opcode {
+ /* Enable UltraSparc performance counters, ARG0 is pointer
+ * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer
+ * to 64-bit accumulator for D1 counter. ARG2 is a pointer to
+ * the initial PCR register value to use.
+ */
+ PERFCTR_ON,
+
+ /* Disable UltraSparc performance counters. The PCR is written
+ * with zero and the user counter accumulator pointers and
+ * working PCR register value are forgotten.
+ */
+ PERFCTR_OFF,
+
+ /* Add current D0 and D1 PIC values into user pointers given
+ * in PERFCTR_ON operation. The PIC is cleared before returning.
+ */
+ PERFCTR_READ,
+
+ /* Clear the PIC register. */
+ PERFCTR_CLRPIC,
+
+ /* Begin using a new PCR value, the pointer to which is passed
+ * in ARG0. The PIC is also cleared after the new PCR value is
+ * written.
+ */
+ PERFCTR_SETPCR,
+
+ /* Store in pointer given in ARG0 the current PCR register value
+ * being used.
+ */
+ PERFCTR_GETPCR
+};
+
+/* I don't want the kernel's namespace to be polluted with this
+ * stuff when this file is included. --DaveM
+ */
+#ifndef __KERNEL__
+
+#define PRIV 0x00000001
+#define USR 0x00000002
+#define SYS 0x00000004
+
+/* Pic.S0 Selection Bit Field Encoding */
+#define CYCLE_CNT 0x00000000
+#define INSTR_CNT 0x00000010
+#define DISPATCH0_IC_MISS 0x00000020
+#define DISPATCH0_STOREBUF 0x00000030
+#define IC_REF 0x00000080
+#define DC_RD 0x00000090
+#define DC_WR 0x000000A0
+#define LOAD_USE 0x000000B0
+#define EC_REF 0x000000C0
+#define EC_WRITE_HIT_RDO 0x000000D0
+#define EC_SNOOP_INV 0x000000E0
+#define EC_RD_HIT 0x000000F0
+
+/* Pic.S1 Selection Bit Field Encoding */
+#define CYCLE_CNT_D1 0x00000000
+#define INSTR_CNT_D1 0x00000800
+#define DISPATCH0_IC_MISPRED 0x00001000
+#define DISPATCH0_FP_USE 0x00001800
+#define IC_HIT 0x00004000
+#define DC_RD_HIT 0x00004800
+#define DC_WR_HIT 0x00005000
+#define LOAD_USE_RAW 0x00005800
+#define EC_HIT 0x00006000
+#define EC_WB 0x00006800
+#define EC_SNOOP_CB 0x00007000
+#define EC_IT_HIT 0x00007800
+
+struct vcounter_struct {
+ unsigned long long vcnt0;
+ unsigned long long vcnt1;
+};
+
+#endif /* !(__KERNEL__) */
+
+#endif /* !(PERF_COUNTER_API) */
-/* $Id: pgtable.h,v 1.90 1998/09/24 03:21:56 davem Exp $
+/* $Id: pgtable.h,v 1.95 1998/10/22 03:05:57 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -169,10+169,9 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size); #define flush_cache_range(mm, start, end) flushw_user()
#define flush_cache_page(vma, page) flushw_user()
-extern void flush_page_to_ram(unsigned long page);
-
-/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
+/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
#define flush_icache_range(start, end) do { } while (0)
+#define flush_page_to_ram(page) do { } while (0)
extern void __flush_dcache_range(unsigned long start, unsigned long end);
@@ -379,7+378,7 @@ extern __inline__ pgd_t *get_pgd_fast(void) if(ret) {
struct page *page = mem_map + MAP_NR(ret);
- clear_page(ret);
+ memset(ret, 0, PAGE_SIZE);
(unsigned long)page->pprev_hash = 2;
(unsigned long *)page->next_hash = pgd_quicklist;
pgd_quicklist = (unsigned long *)page;
@@ -409,7+408,7 @@ extern __inline__ pgd_t *get_pgd_fast(void) } else {
ret = (unsigned long *) __get_free_page(GFP_KERNEL);
if(ret)
- clear_page(ret);
+ memset(ret, 0, PAGE_SIZE);
}
return (pgd_t *)ret;
}
@@ -562,26+561,41 @@ extern void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbu #define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
+/* There used to be some funny code here which tried to guess which
+ * TLB wanted the mapping, that wasn't accurate enough to justify it's
+ * existance. The real way to do that is to have each TLB miss handler
+ * pass in a distinct code to do_sparc64_fault() and do it more accurately
+ * there.
+ *
+ * What we do need to handle here is prevent I-cache corruption. The
+ * deal is that the I-cache snoops stores from other CPUs and all DMA
+ * activity, however stores from the local processor are not snooped.
+ * The dynamic linker and our signal handler mechanism take care of
+ * the cases where they write into instruction space, but when a page
+ * is copied in the kernel and then executed in user-space is not handled
+ * right. This leads to corruptions if things are "just right", consider
+ * the following scenerio:
+ * 1) Process 1 frees up a page that was used for the PLT of libc in
+ * it's address space.
+ * 2) Process 2 writes into a page in the PLT of libc for the first
+ * time. do_wp_page() copies the page locally, the local I-cache of
+ * the processor does not notice the writes during the page copy.
+ * The new page used just so happens to be the one just freed in #1.
+ * 3) After the PLT write, later the cpu calls into an unresolved PLT
+ * entry, the CPU executes old instructions from process 1's PLT
+ * table.
+ * 4) Splat.
+ */
+extern void flush_icache_page(unsigned long phys_page);
#define update_mmu_cache(__vma, __address, _pte) \
-__asm__ __volatile__( \
- "rdpr %%pstate, %%g1\n\t" \
- "wrpr %%g1, %0, %%pstate\n\t" \
- "brz,pt %1, 1f\n\t" \
- " mov %2, %%g2\n\t" \
- "stxa %3, [%%g2] %5\n\t" \
- "ba,pt %%xcc, 2f\n\t" \
- " stxa %4, [%%g0] %6\n\t" \
-"1: stxa %3, [%%g2] %7\n\t" \
-" stxa %4, [%%g0] %8\n\t" \
-"2: wrpr %%g1, 0x0, %%pstate\n" \
- : /* no outputs */ \
- : "i" (PSTATE_IE), \
- "r" (((__vma)->vm_flags&(VM_READ|VM_WRITE|VM_EXEC))==(VM_READ|VM_EXEC)), \
- "i" (TLB_TAG_ACCESS), \
- "r" ((__address) | ((__vma)->vm_mm->context & 0x3ff)), \
- "r" (pte_val(_pte)), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_IN), \
- "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_IN) \
- : "g1", "g2")
+do { \
+ unsigned short __flags = ((__vma)->vm_flags); \
+ if ((__flags & VM_EXEC) != 0 && \
+ ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \
+ (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \
+ flush_icache_page(pte_page(_pte) - page_offset); \
+ } \
+} while(0)
/* Make a non-present pseudo-TTE. */
extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
-/* $Id: processor.h,v 1.49 1998/07/31 10:42:40 jj Exp $
+/* $Id: processor.h,v 1.51 1998/10/21 03:21:19 davem Exp $
* include/asm-sparc64/processor.h
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -61,6+61,11 @@ struct thread_struct { unsigned long sig_address __attribute__ ((aligned (8)));
unsigned long sig_desc;
+ /* Performance counter state */
+ u64 *user_cntd0, *user_cntd1;
+ u64 kernel_cntd0, kernel_cntd1;
+ u64 pcr_reg;
+
unsigned char fpdepth;
unsigned char fpsaved[7];
unsigned char gsr[7];
@@ -74,6+79,7 @@ struct thread_struct { #define SPARC_FLAG_NEWSIGNALS 0x040 /* task wants new-style signals */
#define SPARC_FLAG_32BIT 0x080 /* task is older 32-bit binary */
#define SPARC_FLAG_NEWCHILD 0x100 /* task is just-spawned child process */
+#define SPARC_FLAG_PERFCTR 0x200 /* task has performance counters active */
#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
@@ -91,6+97,8 @@ struct thread_struct { { 0, 0, 0, 0, 0, 0, 0, }, \
/* sig_address, sig_desc */ \
0, 0, \
+/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \
+ 0, 0, 0, 0, 0, \
/* fpdepth, fpsaved, gsr, xfsr */ \
0, { 0 }, { 0 }, { 0 }, \
}
-/* $Id: psrcompat.h,v 1.4 1997/06/20 11:54:39 davem Exp $ */
+/* $Id: psrcompat.h,v 1.5 1998/10/06 09:28:39 jj Exp $ */
#ifndef _SPARC64_PSRCOMPAT_H
#define _SPARC64_PSRCOMPAT_H
#define PSR_VERS 0x0f000000 /* cpu-version field */
#define PSR_IMPL 0xf0000000 /* cpu-implementation field */
+#define PSR_V8PLUS 0xff000000 /* fake impl/ver, meaning a 64bit CPU is present */
+#define PSR_XCC 0x000f0000 /* if PSR_V8PLUS, this is %xcc */
+
extern inline unsigned int tstate_to_psr(unsigned long tstate)
{
- unsigned long vers;
-
- __asm__ __volatile__("rdpr %%ver, %0" : "=r" (vers));
return ((tstate & TSTATE_CWP) |
PSR_S |
((tstate & TSTATE_ICC) >> 12) |
- (((vers << 8) >> 32) & PSR_IMPL) |
- (((vers << 24) >> 36) & PSR_VERS));
+ ((tstate & TSTATE_XCC) >> 20) |
+ PSR_V8PLUS);
}
extern inline unsigned long psr_to_tstate_icc(unsigned int psr)
{
- return ((unsigned long)(psr & PSR_ICC)) << 12;
+ unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
+ if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS)
+ tstate |= ((unsigned long)(psr & PSR_XCC)) << 20;
+ return tstate;
}
#endif /* !(_SPARC64_PSRCOMPAT_H) */
-/* $Id: sab82532.h,v 1.3 1997/09/03 11:55:04 ecd Exp $
+/* $Id: sab82532.h,v 1.4 1998/10/25 23:04:29 ecd Exp $
* sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -143,7+143,7 @@ struct sab82532 { int xmit_fifo_size;
int recv_fifo_size;
int custom_divisor;
- int quot;
+ int baud;
int x_char;
int close_delay;
unsigned short closing_wait;
@@ -24,17+24,24 @@ extern void __up(struct semaphore * sem);
#define wake_one_more(sem) atomic_inc(&sem->waking);
-#define waking_non_zero(sem) \
-({ unsigned long flags; \
- int ret = 0; \
- save_and_cli(flags); \
- if (atomic_read(&sem->waking) > 0) { \
- atomic_dec(&sem->waking); \
- ret = 1; \
- } \
- restore_flags(flags); \
- ret; \
-})
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+ int ret;
+
+ __asm__ __volatile__("
+1: ldsw [%1], %%g5
+ brlez,pt %%g5, 2f
+ mov 0, %0
+ sub %%g5, 1, %%g7
+ cas [%1], %%g5, %%g7
+ cmp %%g5, %%g7
+ bne,pn %%icc, 1b
+ mov 1, %0
+2:" : "=r" (ret)
+ : "r" (&((sem)->waking))
+ : "g5", "g7", "cc", "memory");
+ return ret;
+}
extern __inline__ void down(struct semaphore * sem)
{
-/* $Id: sigcontext.h,v 1.10 1997/12/11 15:16:11 jj Exp $ */
+/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */
#ifndef __SPARC64_SIGCONTEXT_H
#define __SPARC64_SIGCONTEXT_H
@@ -77,6+77,14 @@ typedef struct { unsigned long si_fprs;
} __siginfo_fpu_t;
+/* This magic should be in g_upper[0] for all upper parts
+ to be valid. */
+#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
+typedef struct {
+ unsigned int g_upper[8];
+ unsigned int o_upper[8];
+} siginfo_extra_v8plus_t;
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC64_SIGCONTEXT_H) */
@@ -34,16+34,16 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS]; struct cpuinfo_sparc {
/* Dcache line 1 */
unsigned long irq_count;
+ unsigned long bh_count;
unsigned int multiplier;
unsigned int counter;
- unsigned long pgcache_size;
- unsigned long pgdcache_size;
+ unsigned long udelay_val;
/* Dcache line 2 */
- unsigned long *pgd_cache;
+ unsigned long pgcache_size;
unsigned long *pte_cache;
- unsigned long udelay_val;
- unsigned long dummy;
+ unsigned long pgdcache_size;
+ unsigned long *pgd_cache;
};
extern struct cpuinfo_sparc cpu_data[NR_CPUS];
*
* Default SMP lock implementation
*/
+#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/spinlock.h>
@@ -36,14+37,14 @@ do { \ * so we only need to worry about other
* CPU's.
*/
-extern __inline__ void lock_kernel(void)
-{
- if (!++current->lock_depth)
- spin_lock(&kernel_flag);
-}
+#define lock_kernel() \
+do { \
+ if (!++current->lock_depth) \
+ spin_lock(&kernel_flag); \
+} while(0)
-extern __inline__ void unlock_kernel(void)
-{
- if (--current->lock_depth < 0)
- spin_unlock(&kernel_flag);
-}
+#define unlock_kernel() \
+do { \
+ if (--current->lock_depth < 0) \
+ spin_unlock(&kernel_flag); \
+} while(0)
-/* 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 <asm/atomic.h>
-#include <asm/hardirq.h>
-
-/* 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.
- */
-
-#define get_active_bhs() (bh_mask & bh_active)
-
-#ifndef __SMP__
-
-extern int __sparc64_bh_counter;
-
-#define softirq_trylock(cpu) (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
-#define softirq_endlock(cpu) (__sparc64_bh_counter = 0)
-#define clear_active_bhs(x) (bh_active &= ~(x))
-#define synchronize_bh() barrier() /* XXX implement SMP version -DaveM */
-
-#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 remove_bh(nr) \
-do { int ent = nr; \
- bh_base[ent] = NULL; \
- 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]++; \
- barrier(); \
-} while(0)
-
-#define enable_bh(nr) \
-do { int ent = nr; \
- barrier(); \
- if (!--bh_mask_count[ent]) \
- bh_mask |= 1 << ent; \
-} while(0)
-
-#define start_bh_atomic() do { __sparc64_bh_counter++; barrier(); } while(0)
-
-#define end_bh_atomic() do { barrier(); __sparc64_bh_counter--; } while(0)
-
-#else /* (__SMP__) */
-
-extern atomic_t __sparc64_bh_counter;
-
-#define start_bh_atomic() \
- do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0)
-
-#define end_bh_atomic() atomic_dec(&__sparc64_bh_counter)
-
-#include <asm/spinlock.h>
-
-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 remove_bh(nr) \
-do { unsigned long flags; \
- int ent = nr; \
- spin_lock_irqsave(&global_bh_lock, flags); \
- bh_base[ent] = NULL; \
- 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(cpu) \
-({ \
- int ret = 1; \
- if(atomic_add_return(1, &__sparc64_bh_counter) != 1) { \
- atomic_dec(&__sparc64_bh_counter); \
- ret = 0; \
- } \
- ret; \
-})
-#define softirq_endlock(cpu) atomic_dec(&__sparc64_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)
-
-#endif /* (__SMP__) */
-
-#endif /* !(__SPARC64_SOFTIRQ_H) */
+/* softirq.h: 64-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_SOFTIRQ_H
+#define __SPARC64_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#ifndef __SMP__
+extern unsigned int local_bh_count;
+#else
+#define local_bh_count (cpu_data[smp_processor_id()].bh_count)
+#endif
+
+/* 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.
+ */
+
+#define get_active_bhs() (bh_mask & bh_active)
+#define clear_active_bhs(mask) \
+ __asm__ __volatile__( \
+"1: ldx [%1], %%g7\n" \
+" andn %%g7, %0, %%g5\n" \
+" casx [%1], %%g7, %%g5\n" \
+" cmp %%g7, %%g5\n" \
+" bne,pn %%xcc, 1b\n" \
+" nop" \
+ : /* no outputs */ \
+ : "HIr" (mask), "r" (&bh_active) \
+ : "g5", "g7", "cc", "memory")
+
+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 remove_bh(int nr)
+{
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+}
+
+extern inline void mark_bh(int nr)
+{
+ set_bit(nr, &bh_active);
+}
+
+#ifndef __SMP__
+
+extern inline void start_bh_atomic(void)
+{
+ local_bh_count++;
+ barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+ barrier();
+ local_bh_count--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock(cpu) (local_bh_count ? 0 : (local_bh_count=1))
+#define softirq_endlock(cpu) (local_bh_count = 0)
+#define synchronize_bh() barrier()
+
+#else /* (__SMP__) */
+
+extern atomic_t global_bh_lock;
+extern spinlock_t global_bh_count;
+
+extern void synchronize_bh(void);
+
+static inline void start_bh_atomic(void)
+{
+ atomic_inc(&global_bh_lock);
+ synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+ atomic_dec(&global_bh_lock);
+}
+
+/* These are for the IRQs testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+ if (spin_trylock(&global_bh_count)) {
+ if (atomic_read(&global_bh_lock) == 0) {
+ ++(cpu_data[cpu].bh_count);
+ return 1;
+ }
+ spin_unlock(&global_bh_count);
+ }
+ return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+ (cpu_data[cpu].bh_count)--;
+ spin_unlock(&global_bh_count);
+}
+
+#endif /* (__SMP__) */
+
+/*
+ * 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]++;
+ synchronize_bh();
+}
+
+extern inline void enable_bh(int nr)
+{
+ if (!--bh_mask_count[nr])
+ bh_mask |= 1 << nr;
+}
+
+#endif /* !(__SPARC64_SOFTIRQ_H) */
#ifndef __SMP__
-#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
- typedef struct { } spinlock_t;
- #define SPIN_LOCK_UNLOCKED { }
-#else
- typedef unsigned char spinlock_t;
- #define SPIN_LOCK_UNLOCKED 0
-#endif
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED 0
#define spin_lock_init(lock) do { } while(0)
#define spin_lock(lock) do { } while(0)
@@ -58,6+53,11 @@ typedef struct { } rwlock_t;
#else /* !(__SMP__) */
+/* To get debugging spinlocks which detect and catch
+ * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
+ * specific makefile and rebuild your kernel.
+ */
+
/* All of these locking primitives are expected to work properly
* even in an RMO memory model, which currently is what the kernel
* runs in.
@@ -71,10+71,13 @@ typedef struct { } rwlock_t; * must be pre-V9 branches.
*/
+#ifndef SPIN_LOCK_DEBUG
+
typedef unsigned char spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0)
+#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
#define spin_unlock_wait(lock) \
do { membar("#LoadLoad"); \
@@ -177,8+180,42 @@ extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long fl : "memory");
}
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+ unsigned char lock;
+ unsigned int owner_pc, owner_cpu;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED { 0, 0, NO_PROC_ID }
+#define spin_lock_init(__lock) \
+do { (__lock)->lock = 0; \
+ (__lock)->owner_pc = 0; \
+ (__lock)->owner_cpu = NO_PROC_ID; \
+} while(0)
+#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+#define spin_unlock_wait(__lock) \
+do { \
+ membar("#LoadLoad"); \
+} while(*((volatile unsigned char *)(&((__lock)->lock))))
+
+extern void _do_spin_lock (spinlock_t *lock, char *str);
+extern void _do_spin_unlock (spinlock_t *lock);
+extern int _spin_trylock (spinlock_t *lock);
+
+#define spin_trylock(lp) _spin_trylock(lp)
+#define spin_lock(lock) _do_spin_lock(lock, "spin_lock")
+#define spin_lock_irq(lock) do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
+#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
+#define spin_unlock(lock) _do_spin_unlock(lock)
+#define spin_unlock_irq(lock) do { _do_spin_unlock(lock); __sti(); } while(0)
+#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
+
/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
+#ifndef SPIN_LOCK_DEBUG
+
typedef unsigned long rwlock_t;
#define RW_LOCK_UNLOCKED 0
@@ -278,6+315,58 @@ extern __inline__ void write_unlock(rwlock_t *rw) #define write_unlock_irqrestore(lock, flags) \
do { write_unlock(lock); __restore_flags(flags); } while (0)
+#else /* !(SPIN_LOCK_DEBUG) */
+
+typedef struct {
+ unsigned long lock;
+ unsigned int writer_pc, writer_cpu;
+ unsigned int reader_pc[4];
+} rwlock_t;
+#define RW_LOCK_UNLOCKED { 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } }
+
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+
+#define read_lock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _do_read_lock(lock, "read_lock"); \
+ __restore_flags(flags); \
+} while(0)
+#define read_lock_irq(lock) do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
+#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
+
+#define read_unlock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _do_read_unlock(lock, "read_unlock"); \
+ __restore_flags(flags); \
+} while(0)
+#define read_unlock_irq(lock) do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
+#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
+
+#define write_lock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _do_write_lock(lock, "write_lock"); \
+ __restore_flags(flags); \
+} while(0)
+#define write_lock_irq(lock) do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
+#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
+
+#define write_unlock(lock) \
+do { unsigned long flags; \
+ __save_and_cli(flags); \
+ _do_write_unlock(lock); \
+ __restore_flags(flags); \
+} while(0)
+#define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0)
+#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
+
+#endif /* SPIN_LOCK_DEBUG */
+
#endif /* __SMP__ */
#endif /* !(__ASSEMBLY__) */
-/* $Id: string.h,v 1.12 1998/10/04 08:44:27 davem Exp $
+/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $
* string.h: External definitions for optimized assembly string
* routines for the Linux Kernel.
*
@@ -65,23+65,7 @@ extern inline void *__nonconstant_memcpy(void *to, const void *from, __kernel_si
#define __HAVE_ARCH_MEMSET
-extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count)
-{
- extern __kernel_size_t __bzero(void *, __kernel_size_t);
- extern void *__bzero_1page(void *);
-
- if(!c) {
- if (count == 8192)
- __bzero_1page(s);
- else
- __bzero(s, count);
- } else {
- __memset(s, c, count);
- }
- return s;
-}
-
-extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count)
+extern inline void *__constant_memset(void *s, char c, __kernel_size_t count)
{
extern __kernel_size_t __bzero(void *, __kernel_size_t);
@@ -100,10+84,9 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
#undef memset
#define memset(s, c, count) \
-(__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \
- __constant_c_and_count_memset((s), (c), (count)) : \
- __constant_c_memset((s), (c), (count))) \
- : __nonconstant_memset((s), (c), (count)))
+(__builtin_constant_p(c) ? \
+ __constant_memset((s), (c), (count)) : \
+ __nonconstant_memset((s), (c), (count)))
#define __HAVE_ARCH_MEMSCAN
@@ -128,14+111,19 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count) /* Now the str*() stuff... */
#define __HAVE_ARCH_STRLEN
-/* Ugly but it works around a bug in our original sparc64-linux-gcc. */
extern __kernel_size_t __strlen(const char *);
+
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+extern __kernel_size_t strlen(const char *);
+#else /* !EGCS */
+/* Ugly but it works around a bug in our original sparc64-linux-gcc. */
#undef strlen
#define strlen(__arg0) \
({ int __strlen_res = __strlen(__arg0) + 1; \
__strlen_res -= 1; \
__strlen_res; \
})
+#endif /* !EGCS */
#define __HAVE_ARCH_STRNCMP
-/* $Id: system.h,v 1.44 1998/09/21 03:57:22 davem Exp $ */
+/* $Id: system.h,v 1.47 1998/10/21 03:21:20 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
@@ -76,24+76,17 @@ extern unsigned long empty_zero_page; #else
#ifndef __ASSEMBLY__
-extern unsigned char global_irq_holder;
-#endif
-
-#define save_flags(x) \
-do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
- ((getipl() != 0) ? 2 : 0))); } while(0)
-
-#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
-
-#ifndef __ASSEMBLY__
extern void __global_cli(void);
extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
extern void __global_restore_flags(unsigned long flags);
#endif
#define cli() __global_cli()
#define sti() __global_sti()
+#define save_flags(x) ((x) = __global_save_flags())
#define restore_flags(flags) __global_restore_flags(flags)
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
#endif
@@ -107,6+100,12 @@ extern void __global_restore_flags(unsigned long flags);
#define flushw_all() __asm__ __volatile__("flushw")
+/* Performance counter register access. */
+#define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p))
+#define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p));
+#define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
+#define reset_pic() __asm__ __volatile__("wr %g0, 0x0, %pic");
+
#ifndef __ASSEMBLY__
extern void synchronize_user_stack(void);
@@ -124,21+123,6 @@ extern __inline__ void flushw_user(void)
#define flush_user_windows flushw_user
-#define DEBUG_SWITCH
-
-#ifdef DEBUG_SWITCH
-#define SWITCH_CTX_CHECK(__tsk) \
-do { unsigned short ctx_now; \
- ctx_now = spitfire_get_secondary_context(); \
- if(ctx_now != (__tsk)->tss.ctx) \
- printk("[%s:%d] Bogus ctx after switch [%x:%x]\n", \
- (__tsk)->comm, (__tsk)->pid, \
- (__tsk)->tss.ctx, ctx_now); \
-} while(0)
-#else
-#define SWITCH_CTX_CHECK(__tsk) do { } while(0)
-#endif
-
/* See what happens when you design the chip correctly?
*
* XXX What we are doing here assumes a lot about gcc reload
@@ -156,7+140,15 @@ do { unsigned short ctx_now; \ * not reference %g6.
*/
#define switch_to(prev, next) \
-do { save_and_clear_fpu(); \
+do { if (current->tss.flags & SPARC_FLAG_PERFCTR) { \
+ unsigned long __tmp; \
+ read_pcr(__tmp); \
+ current->tss.pcr_reg = __tmp; \
+ read_pic(__tmp); \
+ current->tss.kernel_cntd0 += (unsigned int)(__tmp); \
+ current->tss.kernel_cntd1 += ((__tmp) >> 32); \
+ } \
+ save_and_clear_fpu(); \
__asm__ __volatile__( \
"flushw\n\t" \
"wrpr %g0, 0x94, %pstate\n\t"); \
@@ -201,7+193,11 @@ do { save_and_clear_fpu(); \ "l2", "l3", "l4", "l5", "l6", "l7", \
"i0", "i1", "i2", "i3", "i4", "i5", \
"o0", "o1", "o2", "o3", "o4", "o5", "o7"); \
- SWITCH_CTX_CHECK(current); \
+ /* If you fuck with this, update ret_from_syscall code too. */ \
+ if (current->tss.flags & SPARC_FLAG_PERFCTR) { \
+ write_pcr(current->tss.pcr_reg); \
+ reset_pic(); \
+ } \
} while(0)
extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
-/* $Id: uaccess.h,v 1.27 1998/09/23 02:04:57 davem Exp $ */
+/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */
#ifndef _ASM_UACCESS_H
#define _ASM_UACCESS_H
@@ -45,10+45,8 @@ extern spinlock_t scheduler_lock;
#define set_fs(val) \
do { \
- unsigned long flags; \
if (current->tss.current_ds.seg != val.seg) { \
spin_lock(&scheduler_lock); \
- __save_and_cli(flags); \
current->tss.current_ds = (val); \
if (segment_eq((val), KERNEL_DS)) { \
flushw_user (); \
} \
spitfire_set_secondary_context(current->tss.ctx); \
__asm__ __volatile__("flush %g6"); \
- __restore_flags(flags); \
spin_unlock(&scheduler_lock); \
} \
} while(0)
-/* $Id: unistd.h,v 1.22 1998/09/13 04:33:14 davem Exp $ */
+/* $Id: unistd.h,v 1.23 1998/10/07 01:28:02 davem Exp $ */
#ifndef _SPARC64_UNISTD_H
#define _SPARC64_UNISTD_H
#define __NR_chmod 15 /* Common */
#define __NR_lchown 16 /* Common */
#define __NR_brk 17 /* Common */
-/* #define __NR_ni_syscall 18 ENOSYS under SunOS */
+#define __NR_perfctr 18 /* Performance counter operations */
#define __NR_lseek 19 /* Common */
#define __NR_getpid 20 /* Common */
#define __NR_capget 21 /* Linux Specific */
#define IFF_PORTSEL 0x2000 /* can set media type */
#define IFF_AUTOMEDIA 0x4000 /* auto media select active */
#define IFF_NODYNARP 0x8000 /* use static ARP only (HIPPI) */
+
+#ifdef __KERNEL__
/*
* The ifaddr structure contains information about one address
* of an interface. They are maintained by the different address
@@ -66,6+68,8 @@ struct ifaddr #define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */
#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */
+#endif /* __KERNEL__ */
+
/*
* Device mapping structure. I'd just gone off and designed a
* beautiful scheme using only loadable modules with arguments
@@ -115,7+119,7 @@ struct ifreq struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
- __kernel_caddr_t ifru_data;
+ char * ifru_data;
} ifr_ifru;
};
@@ -148,7+152,7 @@ struct ifconf int ifc_len; /* size of buffer */
union
{
- __kernel_caddr_t ifcu_buf;
+ char * ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
};
#include <linux/linkage.h>
/* Optimization barrier */
-#define barrier() __asm__("": : :"memory")
+/* The "volatile" is due to gcc bugs */
+#define barrier() __asm__ __volatile__("": : :"memory")
#define INT_MAX ((int)(~0U>>1))
#define UINT_MAX (~0U)
#define LP_NOPA 0x0010
#define LP_ERR 0x0020
#define LP_ABORT 0x0040
-#ifdef LP_NEED_CAREFUL
+#if 0
#define LP_CAREFUL 0x0080
#endif
#define LP_ABORTOPEN 0x0100
@@ -131,6+131,7 @@ struct lp_struct { unsigned int last_error;
volatile unsigned int irq_detected:1;
volatile unsigned int irq_missed:1;
+ unsigned int polled:1;
};
/*
@@ -176,7+177,7 @@ struct lp_struct { */
#define LP_DELAY 50
-#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE)
+#define LP_POLLED(minor) (lp_table[(minor)].polled)
#define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL)
/*
NET_IPV4_ROUTE = 18,
NET_IPV4_FIB_HASH = 19,
-/*32*/ NET_IPV4_TCP_HOE_RETRANSMITS=32,
- NET_IPV4_TCP_TIMESTAMPS,
+/*33*/ NET_IPV4_TCP_TIMESTAMPS=33,
NET_IPV4_TCP_WINDOW_SCALING,
NET_IPV4_TCP_SACK,
NET_IPV4_TCP_RETRANS_COLLAPSE,
@@ -17,8+17,6 @@ struct scm_cookie struct ucred creds; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
unsigned long seq; /* Connection seqno */
- struct file *file; /* file for socket */
- struct socket *sock; /* Passed socket */
};
extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -39,7+37,6 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, scm->creds.uid = current->uid;
scm->creds.gid = current->gid;
scm->creds.pid = current->pid;
- scm->sock = sock;
if (msg->msg_controllen <= 0)
return 0;
return __scm_send(sock, msg, scm);
@@ -194,6+194,7 @@ extern void ibmmca_scsi_setup(char *str, int *ints); extern void in2000_setup(char *str, int *ints);
extern void NCR53c406a_setup(char *str, int *ints);
extern void wd7000_setup(char *str, int *ints);
+extern void dc390_setup(char* str, int *ints);
extern void scsi_luns_setup(char *str, int *ints);
extern void scsi_logging_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
@@ -704,6+705,9 @@ static struct kernel_param cooked_params[] __initdata = { #ifdef CONFIG_SCSI_IBMMCA
{ "ibmmcascsi=", ibmmca_scsi_setup },
#endif
+#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
+ { "tmscsim=", dc390_setup },
+#endif
#ifdef CONFIG_BLK_DEV_XD
{ "xd=", xd_setup },
{ "xd_geo=", xd_manual_geo_init },
@@ -550,7+550,7 @@ int kswapd(void *unused) do_try_to_free_page(0);
if (free_memory_available() > 1)
break;
- } while (jiffies != start_time);
+ } while (jiffies == start_time);
}
/* As if we could ever get here - maybe we want to make this killable */
kswapd_task = NULL;
@@ -103,7+103,6 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) void __scm_destroy(struct scm_cookie *scm)
{
struct scm_fp_list *fpl = scm->fp;
- struct file *file;
int i;
if (fpl) {
@@ -112,34+111,18 @@ void __scm_destroy(struct scm_cookie *scm) fput(fpl->fp[i]);
kfree(fpl);
}
-
- file = scm->file;
- if (file) {
- scm->sock = NULL;
- scm->file = NULL;
- fput(file);
- }
}
-
-
-extern __inline__ int not_one_bit(unsigned val)
-{
- return (val-1) & val;
-}
-
-
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
{
struct cmsghdr *cmsg;
- struct file *file;
- int acc_fd, err;
- unsigned int scm_flags=0;
+ int err;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
{
err = -EINVAL;
+ /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */
if ((unsigned long)(((char*)cmsg - (char*)msg->msg_control)
+ cmsg->cmsg_len) > msg->msg_controllen)
goto error;
@@ -162,30+145,6 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) if (err)
goto error;
break;
- case SCM_CONNECT:
- if (scm_flags)
- goto error;
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
- goto error;
- memcpy(&acc_fd, CMSG_DATA(cmsg), sizeof(int));
- p->sock = NULL;
- if (acc_fd != -1) {
- err = -EBADF;
- file = fget(acc_fd);
- if (!file)
- goto error;
- p->file = file;
- err = -ENOTSOCK;
- if (!file->f_dentry->d_inode ||
- !file->f_dentry->d_inode->i_sock)
- goto error;
- p->sock = &file->f_dentry->d_inode->u.socket_i;
- err = -EINVAL;
- if (p->sock->state != SS_UNCONNECTED)
- goto error;
- }
- scm_flags |= MSG_SYN;
- break;
default:
goto error;
}
@@ -196,16+155,13 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) kfree(p->fp);
p->fp = NULL;
}
-
- err = -EINVAL;
- msg->msg_flags |= scm_flags;
- scm_flags = msg->msg_flags&MSG_CTLFLAGS;
- if (not_one_bit(scm_flags))
- goto error;
- if (!(scm_flags && p->fp))
- return 0;
+ err = -EINVAL;
+ if (msg->msg_flags & MSG_CTLFLAGS)
+ goto error;
+ return 0;
+
error:
scm_destroy(p);
return err;
* handler for protocols to use and generic option handler.
*
*
- * Version: $Id: sock.c,v 1.73 1998/10/03 16:08:10 freitag Exp $
+ * Version: $Id: sock.c,v 1.74 1998/10/21 05:40:38 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -294,6+294,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname, {
char devname[IFNAMSIZ];
+ /* Sorry... */
+ if (!capable(CAP_NET_RAW))
+ return -EPERM;
+
/* Bind this socket to a particular device like "eth0",
* as specified in the passed interface name. If the
* name is "" or the option length is zero the socket
/* linux/net/inet/arp.c
*
- * Version: $Id: arp.c,v 1.70 1998/08/26 12:03:18 davem Exp $
+ * Version: $Id: arp.c,v 1.73 1998/10/21 05:36:02 davem Exp $
*
* Copyright (C) 1994 by Florian La Roche
*
@@ -1027,7+1027,7 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy "%-17s0x%-10x0x%-10x%s",
in_ntoa(*(u32*)n->key),
hatype,
- ATF_PUBL|ATF_PERM,
+ ATF_PUBL|ATF_PERM,
"00:00:00:00:00:00");
size += sprintf(buffer+len+size,
" %-17s %s\n",
*
* Alan Cox, <alan@cymru.net>
*
- * Version: $Id: icmp.c,v 1.46 1998/10/03 09:37:15 davem Exp $
+ * Version: $Id: icmp.c,v 1.47 1998/10/21 05:32:24 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -359,6+359,11 @@ struct socket *icmp_socket=&icmp_inode.u.socket_i; * This function is generic and could be used for other purposes
* too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
*
+ * Note that the same dst_entry fields are modified by functions in
+ * route.c too, but these work for packet destinations while xrlim_allow
+ * works for icmp destinations. This means the rate limiting information
+ * for one "ip object" is shared.
+ *
* RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
* SHOULD allow setting of rate limits
*
@@ -374,6+379,7 @@ int xrlim_allow(struct dst_entry *dst, int timeout) if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
if (dst->rate_tokens >= timeout) {
+ dst->rate_last = now;
dst->rate_tokens -= timeout;
return 1;
}
* IP_MASQ_FTP CUSeeMe masquerading module
*
*
- * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $
*
* Author: Richard Lynch
*
* IP_MASQ_RAUDIO - Real Audio masquerading module
*
*
- * Version: @(#)$Id: ip_masq_raudio.c,v 1.10 1998/08/29 23:51:17 davem Exp $
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
*
* Author: Nigel Metheringham
* Real Time Streaming code by Progressive Networks
* IP_MASQ_VDOLIVE - VDO Live masquerading module
*
*
- * Version: @(#)$Id: ip_masq_vdolive.c,v 1.3 1998/08/29 23:51:18 davem Exp $
+ * Version: @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
*
* Author: Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
* PLAnet Online Ltd
*
* Dumb Network Address Translation.
*
- * Version: $Id: ip_nat_dumb.c,v 1.6 1998/10/03 09:37:25 davem Exp $
+ * Version: $Id: ip_nat_dumb.c,v 1.7 1998/10/06 04:49:09 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
/*
- * $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $
+ * $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $
*
* Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
* information to configure own IP address and routes.
@@ -260,12+260,12 @@ __initfunc(int ic_defaults(void)) root_server_addr = ic_servaddr;
if (ic_netmask == INADDR_NONE) {
- if (IN_CLASSA(ic_myaddr))
- ic_netmask = IN_CLASSA_NET;
- else if (IN_CLASSB(ic_myaddr))
- ic_netmask = IN_CLASSB_NET;
- else if (IN_CLASSC(ic_myaddr))
- ic_netmask = IN_CLASSC_NET;
+ if (IN_CLASSA(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSB_NET);
+ else if (IN_CLASSC(ntohl(ic_myaddr)))
+ ic_netmask = htonl(IN_CLASSC_NET);
else {
printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
return -1;
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: $Id: proc.c,v 1.32 1998/10/03 09:37:42 davem Exp $
+ * Version: $Id: proc.c,v 1.33 1998/10/21 05:44:35 davem Exp $
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -55,21+55,22 @@ static inline void get__openreq(struct sock *sk, struct open_request *req, char *tmpbuf,
int i)
{
- /* FIXME: I'm not sure if the timer fields are correct. */
sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u",
i,
(long unsigned int)req->af.v4_req.loc_addr,
ntohs(sk->sport),
(long unsigned int)req->af.v4_req.rmt_addr,
- req->rmt_port,
+ ntohs(req->rmt_port),
TCP_SYN_RECV,
- 0,0, /* use sizeof(struct open_request) here? */
- 0, (unsigned long)(req->expires - jiffies), /* ??? */
+ 0,0, /* could print option size, but that is af dependent. */
+ 1, /* timers active (only the expire timer) */
+ (unsigned long)(req->expires - jiffies),
req->retrans,
sk->socket ? sk->socket->inode->i_uid : 0,
- 0, /* ??? */
- sk->socket ? sk->socket->inode->i_ino:0);
+ 0, /* non standard timer */
+ 0 /* open_requests have no inode */
+ );
}
/* Format a single socket into tmpbuf. */
@@ -157,6+158,9 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format) * KNOWN BUGS
* As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos.
+ *
+ * Assumes that buffer length is a multiply of 128 - if not it will
+ * write past the end.
*/
static int
get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length)
@@ -172,17+176,6 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of " sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout inode");
pos = 128;
-/*
- * This was very pretty but didn't work when a socket is destroyed
- * at the wrong moment (eg a syn recv socket getting a reset), or
- * a memory timer destroy. Instead of playing with timers we just
- * concede defeat and do a start_bh_atomic().
- * Why not just use lock_sock()? As far as I can see all timer routines
- * check for sock_readers before doing anything. -AK
- * [Disabled for now again, because it hard-locked my machine, and there
- * is an theoretical situation then, where an user could prevent
- * sockets from being destroyed by constantly reading /proc/net/tcp.]
- */
SOCKHASH_LOCK();
sp = pro->sklist_next;
while(sp != (struct sock *)pro) {
@@ -196,8+189,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of continue;
get__openreq(sp, req, tmpbuf, i);
len += sprintf(buffer+len, "%-127s\n", tmpbuf);
- if(len >= length)
- break;
+ if(len >= length)
+ goto out;
}
}
@@ -215,6+208,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of sp = next;
i++;
}
+out:
SOCKHASH_UNLOCK();
begin = len - (pos - offset);
@@ -222,6+216,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of len -= begin;
if(len>length)
len = length;
+ if (len<0)
+ len = 0;
return len;
}
@@ -265,6+261,8 @@ int afinet_get_info(char *buffer, char **start, off_t offset, int length, int du len -= offset;
if (len > length)
len = length;
+ if (len < 0)
+ len = 0;
return len;
}
@@ -343,6+341,8 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length, int dumm len -= offset;
if (len > length)
len = length;
+ if (len < 0)
+ len = 0;
return len;
}
@@ -379,5+379,7 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length, int d len -= offset;
if (len > length)
len = length;
+ if (len < 0)
+ len = 0;
return len;
}
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.35 1998/10/03 09:37:54 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.36 1998/10/21 05:26:59 davem Exp $
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -43,7+43,6 @@ extern int sysctl_ip_dynaddr; /* From ip_masq.c */
extern int sysctl_ip_masq_debug;
-extern int sysctl_tcp_hoe_retransmits;
extern int sysctl_tcp_timestamps;
extern int sysctl_tcp_window_scaling;
extern int sysctl_tcp_sack;
@@ -92,9+91,6 @@ int ipv4_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
ctl_table ipv4_table[] = {
- {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits",
- &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL,
- &proc_dointvec},
{NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps",
&sysctl_tcp_timestamps, sizeof(int), 0644, NULL,
&proc_dointvec},
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.130 1998/10/04 07:06:47 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.133 1998/10/21 05:38:53 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Andi Kleen: Add tcp_measure_rcv_mss to make
* connections with MSS<min(MTU,ann. MSS)
* work without delayed acks.
+ * Andi Kleen: Process packets with PSH set in the
+ * fast path.
*/
#include <linux/config.h>
@@ -75,7+77,6 @@ extern int sysctl_tcp_fin_timeout; int sysctl_tcp_timestamps = 1;
int sysctl_tcp_window_scaling = 1;
int sysctl_tcp_sack = 1;
-int sysctl_tcp_hoe_retransmits = 1;
int sysctl_tcp_syncookies = SYNC_INIT;
int sysctl_tcp_stdurg;
@@ -1139,7+1140,7 @@ coalesce: /* Zap SWALK, by moving every further SACK up by one slot.
* Decrease num_sacks.
*/
- for(this_sack += 1; this_sack < num_sacks; this_sack++, swalk++) {
+ for(this_sack += 1; this_sack < num_sacks-1; this_sack++, swalk++) {
struct tcp_sack_block *next = (swalk + 1);
swalk->start_seq = next->start_seq;
swalk->end_seq = next->end_seq;
@@ -1745,14+1746,15 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, }
}
- flg = *(((u32 *)th) + 3);
-
+ flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16);
+
/* pred_flags is 0xS?10 << 16 + snd_wnd
* if header_predition is to be made
* 'S' will always be tp->tcp_header_len >> 2
* '?' will be 0 else it will be !0
* (when there are holes in the receive
* space for instance)
+ * PSH flag is ignored.
*/
if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
@@ -22,6+22,10 @@ extern void inet6_proto_init(struct net_proto *pro); #endif
#endif /* INET */
+#ifdef CONFIG_ECONET
+extern void econet_proto_init(struct net_proto *pro);
+#endif
+
#ifdef CONFIG_NETLINK
extern void netlink_proto_init(struct net_proto *pro);
#endif
@@ -153,5+157,9 @@ struct net_proto protocols[] = { { "X.25", x25_proto_init }, /* CCITT X.25 Packet Layer */
#endif
+#ifdef CONFIG_ECONET
+ { "Econet", econet_proto_init }, /* Acorn Econet */
+#endif
+
{ NULL, NULL } /* End marker */
};