diff options
author | davem <davem> | 2001-12-08 04:06:24 +0000 |
---|---|---|
committer | davem <davem> | 2001-12-08 04:06:24 +0000 |
commit | 3e659fe9785aeefab6e52ddf25792edb922825b3 (patch) | |
tree | 643681a9741f7d2564e08ab3ab9b386491704b62 | |
parent | e05f273d8e7f775168f501289c5139ae42fc87de (diff) | |
download | netdev-vger-cvs-3e659fe9785aeefab6e52ddf25792edb922825b3.tar.gz |
Merge mainline to 2.4.17-pre6
154 files changed, 2601 insertions, 1743 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index 6dc50f50b..d4c8e8c31 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -53,7 +53,7 @@ o Gnu make 3.77 # make --version o binutils 2.9.1.0.25 # ld -v o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V -o e2fsprogs 1.19 # tune2fs +o e2fsprogs 1.25 # tune2fs o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version @@ -317,8 +317,7 @@ o <ftp://rawhide.redhat.com/pub/rawhide/SRPMS/SRPMS/> E2fsprogs --------- -o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19.tar.gz> -o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.19-0.src.rpm> +o <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.25.tar.gz> Reiserfsprogs ------------- diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 6ab6683c1..b5d4a2df7 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -2,7 +2,7 @@ # Eric S. Raymond <mailto:esr@thyrsus.com> # Steven Cole <mailto:elenstev@mesatop.com> # -# Merged version 2.66: current with 2.4.17-pre2/2.5.1-pre5. +# Merged version 2.67: current with 2.4.17-pre5/2.5.1-pre6. # # This version of the Linux kernel configuration help texts # corresponds to kernel versions 2.4.x and 2.5.x. @@ -341,7 +341,7 @@ CONFIG_NOHIGHMEM "high memory". If you are compiling a kernel which will never run on a machine with - more than 1 Gigabyte total physical RAM, answer "off" here (default + more than 960 megabytes of total physical RAM, answer "off" here (default choice and suitable for most users). This will result in a "3GB/1GB" split: 3GB are mapped so that each process sees a 3GB virtual memory space and the remaining part of the 4GB virtual memory space is used @@ -358,10 +358,10 @@ CONFIG_NOHIGHMEM processors (Pentium Pro and better). NOTE: If you say "64GB" here, then the kernel will not boot on CPUs that don't support PAE! - The actual amount of total physical memory will either be - auto detected or can be forced by using a kernel command line option - such as "mem=256M". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the + The actual amount of total physical memory will either be auto + detected or can be forced by using a kernel command line option such + as "mem=256M". (Try "man bootparam" or see the documentation of your + boot loader (grub, lilo or loadlin) about how to pass options to the kernel at boot time.) If unsure, say "off". @@ -5206,6 +5206,14 @@ CONFIG_IPV6 It is safe to say N here for now. +# 2.5 tree only +IPv6: routing messages via old netlink +CONFIG_IPV6_NETLINK + You can say Y here to receive routing messages from the IPv6 code + through the old netlink interface. However, a better option is to + say Y to "Kernel/User network link driver" and to "Routing + messages" instead. + Kernel httpd acceleration CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web @@ -5959,6 +5967,34 @@ CONFIG_PACKET_MMAP If unsure, say N. +# 2.5 tree only +Kernel/User network link driver +CONFIG_NETLINK + This driver allows for two-way communication between the kernel and + user processes. It does so by creating a new socket family, + PF_NETLINK. Over this socket, the kernel can send and receive + datagrams carrying information. It is documented on many systems in + netlink(7). + + So far, the kernel uses this feature to publish some network related + information if you say Y to "Routing messages", below. You also need + to say Y here if you want to use arpd, a daemon that helps keep the + internal ARP cache (a mapping between IP addresses and hardware + addresses on the local network) small. The ethertap device, which + lets user space programs read and write raw Ethernet frames, also + needs the network link driver. + + If unsure, say Y. + +# 2.5 tree only +Routing messages +CONFIG_RTNETLINK + If you say Y here, user space programs can receive some network + related routing information over the netlink. 'rtmon', supplied + with the iproute2 package (<ftp://ftp.inr.ac.ru/>), can read and + interpret this data. Information sent to the kernel over this link + is ignored. + Netlink device emulation CONFIG_NETLINK_DEV This option will be removed soon. Any programs that want to use @@ -8712,19 +8748,6 @@ CONFIG_PCMCIA_AXNET a module, say M here and read <file:Documentation/modules.txt>. If unsure, say N. -Asix AX88190 PCMCIA support -CONFIG_PCMCIA_AXNET - Say Y here if you intend to attach an Asix AX88190-based PCMCIA - (PC-card) Fast Ethernet card to your computer. These cards are - nearly NE2000 compatible but need a separate driver due to a few - misfeatures. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called axnet_cs.o. If you want to compile it as - a module, say M here and read <file:Documentation/modules.txt>. If - unsure, say N. - New Media PCMCIA support CONFIG_PCMCIA_NMCLAN Say Y here if you intend to attach a New Media Ethernet or LiveWire @@ -13844,7 +13867,7 @@ CONFIG_EXT2_FS Ext3 journalling file system support (EXPERIMENTAL) CONFIG_EXT3_FS This is the journalling version of the Second extended file system - (often called ext3), the de facto standard Linux file system + (often called ext2), the de facto standard Linux file system (method to organize files on a storage device) for hard disks. The journalling code included in this driver means you do not have @@ -13961,15 +13984,41 @@ CONFIG_CMS_FS mainframe systems. Only the basic format is supported so far. If you don't know what CMS is you probably don't want to know any more. +# When the 2.5 version of configure.help goes away, the part of this that +# duplicates Documentation/filesystems/tmpfs.txt can drop out. Virtual memory file system support CONFIG_TMPFS Tmpfs is a file system which keeps all files in virtual memory. - Everything in tmpfs is temporary in the sense that no files will be created on your hard drive. If you reboot, everything in tmpfs will be lost. - See <file:Documentation/filesystems/tmpfs.txt> for details + In contrast to RAM disks, which get allocated a fixed amount of + physical RAM, tmpfs grows and shrinks to accommodate the files it + contains and is able to swap unneeded pages out to swap space. + + Everything is "virtual" in the sense that no files will be created + on your hard drive; if you reboot, everything in tmpfs will be + lost. + + You should mount the file system somewhere to be able to use + POSIX shared memory. Adding the following line to /etc/fstab should + take care of things: + + tmpfs /dev/shm tmpfs defaults 0 0 + + Remember to create the directory that you intend to mount tmpfs on + if necessary (/dev/shm is automagically created if you use devfs). + + You can set limits for the number of blocks and inodes used by the + file system with the mount options "size", "nr_blocks" and + "nr_inodes". These parameters accept a suffix k, m or g for kilo, + mega and giga and can be changed on remount. + + The initial permissions of the root directory can be set with the + mount option "mode". + + See <file:Documentation/filesystems/tmpfs.txt> for details. Simple RAM-based file system support CONFIG_RAMFS @@ -18846,6 +18895,26 @@ CONFIG_MIPS_UNCACHED hardware debugging with a logic analyzer and need to see all traffic on the bus. +AU1000 serial console +CONFIG_AU1000_SERIAL_CONSOLE + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use a console on a serial port, say Y. Otherwise, say N. + +AU1000 serial support +CONFIG_AU1000_UART + If you have an Alchemy AU1000 processor (MIPS based) and you want + to use serial ports, say Y. Otherwise, say N. + +AU1000 ethernet controller on SGI MIPS system +CONFIG_MIPS_AU1000_ENET + If you have an Alchemy Semi AU1000 ethernet controller + on an SGI MIPS system, say Y. Otherwise, say N. + +WD93 SCSI Controller on SGI MIPS system +CONFIG_SGIWD93_SCSI + If you have a Western Digital WD93 SCSI controller on + an SGI MIPS system, say Y. Otherwise, say N. + Magic System Request Key support CONFIG_MAGIC_SYSRQ If you say Y here, you will have some control over the system even @@ -21467,7 +21536,7 @@ CONFIG_VIDEO_W9966 otherwise say N. This driver is also available as a module (w9966.o). - Check out <file:Documentation/video4linux/w9966.txt> and + Check out <file:drivers/media/video4linux/w9966.txt> and <file:drivers/media/video/w9966.c> for more information. CPiA Video For Linux @@ -23586,6 +23655,42 @@ CONFIG_EFI_VARS To use this option, you have to check that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +Physical memory granularity (16 MB) +CONFIG_IA64_GRANULE_16MB + IA64 identity-mapped regions use a large page size. We'll call such + large pages "granules". If you can think of a better name that's + unambiguous, let us know... Unless your identity-mapped regions are + very large, select a granule size of 16MB. + +Physical memory granularity (64 MB) +CONFIG_IA64_GRANULE_64MB + IA64 identity-mapped regions use a large page size. We'll call such + large pages "granules". If you can think of a better name that's + unambiguous, let us know... Unless your identity-mapped regions are + very large, select a granule size of 16MB. (This is the "large" choice.) + +Enable SGI SN extra debugging code +CONFIG_IA64_SGI_SN_DEBUG + Turns on extra debugging code in the SGI SN (Scalable NUMA) platform + for IA64. Unless you are debugging problems on an SGI SN IA64 box, + say N. + +Enable SGI Medusa Simulator Support +CONFIG_IA64_SGI_SN_SIM + If you are compiling a kernel that will run under SGI's IA64 + simulator (Medusa) then say Y, otherwise say N. + +PCIBA Support +CONFIG_PCIBA + IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable + NUMA) platform for IA64. Unless you are compiling a kernel for an SGI SN IA64 box, say N. + +Enable protocol mode for the L1 console +SERIAL_SGI_L1_PROTOCOL + Uses protocol mode instead of raw mode for the level 1 console on the + SGI SN (Scalable NUMA) platform for IA64. If you are compiling for + an SGI SN box then Y is the recommended value, otherwise say N. + Directly Connected Compact Flash support CONFIG_CF_ENABLER Compact Flash is a small, removable mass storage device introduced @@ -23627,6 +23732,19 @@ CONFIG_DEBUG_SPINLOCK best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +Read-write spinlock debugging +CONFIG_DEBUG_RWLOCK + If you say Y here then read-write lock processing will count how many + times it has tried to get the lock and issue an error message after + too many attempts. If you suspect a rwlock problem or a kernel + hacker asks for this option then say Y. Otherwise say N. + +Semaphore debugging +CONFIG_DEBUG_SEMAPHORE + If you say Y here then semaphore processing will issue lots of + verbose debugging messages. If you suspect a semaphore problem or a + kernel hacker asks for this option then say Y. Otherwise say N. + Verbose BUG() reporting (adds 70K) CONFIG_DEBUG_BUGVERBOSE Say Y here to make BUG() panics output the file name and line number @@ -24042,10 +24160,10 @@ CONFIG_GDB_CONSOLE # LocalWords: filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI # LocalWords: chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport # LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard -# LocalWords: Brumby pci TNC cis ohio faq usenet dev hydra ca Tyne mem +# LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem # LocalWords: carleton DECstation SUNFD JENSEN Noname XXXM SLiRP LILO's amifb # LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd -# LocalWords: mknod xos MTU lwared Macs netatalk macs cs Wolff +# LocalWords: RTNETLINK mknod xos MTU lwared Macs netatalk macs cs Wolff # LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress # LocalWords: ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp # LocalWords: thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 8e7276b35..c1d3e522b 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -123,6 +123,10 @@ prototypes: int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); int (*bmap)(struct address_space *, long); + int (*flushpage) (struct page *, unsigned long); + int (*releasepage) (struct page *, int); + int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); + locking rules: All may block BKL PageLocked(page) @@ -132,6 +136,8 @@ sync_page: no maybe prepare_write: no yes commit_write: no yes bmap: yes +flushpage: no yes +releasepage: no yes ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop). @@ -144,6 +150,15 @@ well-defined... filesystems and by the swapper. The latter will eventually go away. All instances do not actually need the BKL. Please, keep it that way and don't breed new callers. + ->flushpage() is called when the filesystem must attempt to drop +some or all of the buffers from the page when it is being truncated. It +returns zero on success. If ->flushpage is zero, the kernel uses +block_flushpage() instead. + ->releasepage() is called when the kernel is about to try to drop the +buffers from the page in preparation for freeing it. It returns zero to +indicate that the buffers are (or may be) freeable. If ->flushpage is zero, +the kernel assumes that the fs has no private interest in the buffers. + Note: currently almost all instances of address_space methods are using BKL for internal serialization and that's one of the worst sources of contention. Normally they are calling library functions (in fs/buffer.c) diff --git a/Documentation/pci.txt b/Documentation/pci.txt index dadb9a9dc..5ac05854a 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -104,6 +104,10 @@ Tips: If you are sure the driver is not a hotplug driver then use only __init/exit __initdata/exitdata. + Pointers to functions marked as __devexit must be created using + __devexit_p(function_name). That will generate the function + name or NULL if the __devexit function will be discarded. + 2. How to find PCI devices manually (the old style) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/sonypi.txt b/Documentation/sonypi.txt index 0d7314ce1..24d391c6b 100644 --- a/Documentation/sonypi.txt +++ b/Documentation/sonypi.txt @@ -58,6 +58,10 @@ where: get enabled unless you set this parameter to 1. Do not use this option unless it's actually necessary, some Vaio models don't deal well with this option. + This option is available only if the kernel is + compiled without ACPI support (since it conflicts + with it and it shouldn't be required anyway if + ACPI is already enabled). verbose: print unknown events from the sonypi device @@ -93,7 +97,10 @@ Bugs: - some users reported that the laptop speed is lower (dhrystone tested) when using the driver with the fnkeyinit parameter. I cannot reproduce it on my laptop and not all users have this problem. - Still under investigation. + This happens because the fnkeyinit parameter enables the ACPI + mode (but without additionnal ACPI control, like processor + speed handling etc). Use ACPI instead of APM if it works on your + laptop. - since all development was done by reverse engineering, there is _absolutely no guarantee_ that this driver will not crash your @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 17 -EXTRAVERSION = -pre5 +EXTRAVERSION = -pre6 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 33ca873c4..803397aaa 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/irq.h> +#include <linux/cache.h> #include <asm/hwrpb.h> #include <asm/ptrace.h> @@ -65,7 +66,7 @@ enum ipi_message_type { IPI_CPU_STOP, }; -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* Set to a secondary's cpuid when it comes online. */ static unsigned long smp_secondary_alive; diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S index 0907ea962..dc6841590 100644 --- a/arch/i386/boot/setup.S +++ b/arch/i386/boot/setup.S @@ -539,7 +539,7 @@ done_apm_bios: cmpw $0, %cs:realmode_swtch jz rmodeswtch_normal - lcall %cs:realmode_swtch + lcall *%cs:realmode_swtch jmp rmodeswtch_end diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 5021c216d..d04a4306c 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -17,6 +17,7 @@ #include <linux/smp_lock.h> #include <linux/kernel_stat.h> #include <linux/mc146818rtc.h> +#include <linux/cache.h> #include <asm/mtrr.h> #include <asm/pgalloc.h> @@ -102,7 +103,7 @@ */ /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; struct tlb_state cpu_tlbstate[NR_CPUS] = {[0 ... NR_CPUS-1] = { &init_mm, 0 }}; diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 8f6f1ffd0..9f7966c3b 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -30,6 +30,7 @@ #include <linux/kernel_stat.h> #include <linux/mm.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/bitops.h> @@ -51,7 +52,7 @@ #include <asm/mca.h> /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* * Structure and data for smp_call_function(). This is designed to minimise static memory diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index bcfdad667..48085d315 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -31,6 +31,7 @@ #include <linux/timex.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/processor.h> @@ -52,7 +53,7 @@ /* Ze Big Kernel Lock! */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; int smp_threads_ready; /* Not used */ int smp_num_cpus; int global_irq_holder = NO_PROC_ID; diff --git a/arch/mips64/kernel/smp.c b/arch/mips64/kernel/smp.c index 86b338c05..e18cf01e7 100644 --- a/arch/mips64/kernel/smp.c +++ b/arch/mips64/kernel/smp.c @@ -5,6 +5,7 @@ #include <linux/time.h> #include <linux/timex.h> #include <linux/sched.h> +#include <linux/cache.h> #include <asm/atomic.h> #include <asm/processor.h> @@ -52,7 +53,7 @@ static void sendintr(int destid, unsigned char status) #endif /* CONFIG_SGI_IP27 */ /* The 'big kernel lock' */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; int smp_threads_ready; /* Not used */ atomic_t smp_commenced = ATOMIC_INIT(0); struct cpuinfo_mips cpu_data[NR_CPUS]; diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index b814ee640..a76cf7661 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -23,6 +23,7 @@ #include <linux/unistd.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/cache.h> #include <asm/ptrace.h> #include <asm/atomic.h> @@ -45,7 +46,7 @@ struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; atomic_t ipi_recv; atomic_t ipi_sent; -spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; cycles_t cacheflush_time; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 0171e0d4c..6a836af79 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -29,6 +29,7 @@ #include <linux/smp_lock.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/sigp.h> #include <asm/pgalloc.h> @@ -55,7 +56,7 @@ cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ static atomic_t smp_commenced = ATOMIC_INIT(0); -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; diff --git a/arch/s390x/kernel/smp.c b/arch/s390x/kernel/smp.c index 21912c773..fe9593dbf 100644 --- a/arch/s390x/kernel/smp.c +++ b/arch/s390x/kernel/smp.c @@ -29,6 +29,7 @@ #include <linux/smp_lock.h> #include <linux/delay.h> +#include <linux/cache.h> #include <asm/sigp.h> #include <asm/pgalloc.h> @@ -55,7 +56,7 @@ cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ static atomic_t smp_commenced = ATOMIC_INIT(0); -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 7d272865b..bbe832d86 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/cache.h> #include <asm/ptrace.h> #include <asm/atomic.h> @@ -66,7 +67,7 @@ cycles_t cacheflush_time = 0; /* XXX */ */ /* Kernel spinlock */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* Used to make bitops atomic */ unsigned char bitops_spinlock = 0; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 971bc1b8e..90cbdf108 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -17,6 +17,7 @@ #include <linux/spinlock.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/cache.h> #include <asm/head.h> #include <asm/ptrace.h> @@ -49,7 +50,7 @@ static unsigned char boot_cpu_id = 0; static int smp_activated = 0; /* Kernel spinlock */ -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; volatile int smp_processors_ready = 0; unsigned long cpu_present_map = 0; diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 9ca723bb6..638e8d0ef 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2310,7 +2310,7 @@ static struct pci_driver eni_driver = { name: DEV_LABEL, id_table: eni_pci_tbl, probe: eni_init_one, - remove: eni_remove_one, + remove: __devexit_p(eni_remove_one), }; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index a6a9046de..4db7ab6a3 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -2102,7 +2102,7 @@ static struct pci_driver firestream_driver = { name: "firestream", id_table: firestream_pci_tbl, probe: firestream_init_one, - remove: firestream_remove_one, + remove: __devexit_p(firestream_remove_one), }; static int __init firestream_init_module (void) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9f9f2aee3..14fbe6ffb 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2019,7 +2019,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) static struct pci_driver cciss_pci_driver = { name: "cciss", probe: cciss_init_one, - remove: cciss_remove_one, + remove: __devexit_p(cciss_remove_one), id_table: cciss_pci_device_id, /* id_table */ }; diff --git a/drivers/block/paride/Config.in b/drivers/block/paride/Config.in index e0aec10d9..eccb773ca 100644 --- a/drivers/block/paride/Config.in +++ b/drivers/block/paride/Config.in @@ -29,7 +29,7 @@ dep_tristate ' FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE dep_tristate ' Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE if [ "$CONFIG_PARIDE_EPAT" != "n" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 $CONFIG_PARIDE + bool ' Support c7/c8 chips (EXPERIMENTAL)' CONFIG_PARIDE_EPATC8 fi fi diff --git a/drivers/char/drm/Config.in b/drivers/char/drm/Config.in index 4936c6b3f..0cc3713d2 100644 --- a/drivers/char/drm/Config.in +++ b/drivers/char/drm/Config.in @@ -13,4 +13,5 @@ if [ "$CONFIG_DRM" != "n" ]; then dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP + dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP fi diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index 819418eb5..f0656be88 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. O_TARGET := drm.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o radeon.o ffb.o sis.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o @@ -12,6 +12,7 @@ mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o i810-objs := i810_drv.o i810_dma.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o ffb-objs := ffb_drv.o ffb_context.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o @@ -20,6 +21,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_SIS) += sis.o include $(TOPDIR)/Rules.make @@ -43,3 +45,6 @@ radeon.o: $(radeon-objs) $(lib) ffb.o: $(ffb-objs) $(lib) $(LD) -r -o $@ $(ffb-objs) $(lib) + +sis.o: $(sis-objs) $(lib) + $(LD) -r -o $@ $(sis-objs) $(lib) diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h index ac9f407a7..362de2ccf 100644 --- a/drivers/char/drm/drm.h +++ b/drivers/char/drm/drm.h @@ -104,7 +104,7 @@ typedef struct drm_tex_region { #include "i810_drm.h" #include "r128_drm.h" #include "radeon_drm.h" -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) #include "sis_drm.h" #endif @@ -483,7 +483,7 @@ typedef struct drm_scatter_gather { #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#ifdef CONFIG_DRM_SIS +#if defined(CONFIG_DRM_SIS) || defined(CONFIG_DRM_SIS_MODULE) /* SiS specific ioctls */ #define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) #define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) diff --git a/drivers/char/drm/drm_context.h b/drivers/char/drm/drm_context.h index 33d6112e3..e155946dc 100644 --- a/drivers/char/drm/drm_context.h +++ b/drivers/char/drm/drm_context.h @@ -27,6 +27,10 @@ * Authors: * Rickard E. (Rik) Faith <faith@valinux.com> * Gareth Hughes <gareth@valinux.com> + * ChangeLog: + * 2001-11-16 Torsten Duwe <duwe@caldera.de> + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. */ #define __NO_VERSION__ @@ -316,6 +320,10 @@ int DRM(addctx)( struct inode *inode, struct file *filp, /* Should this return -EBUSY instead? */ return -ENOMEM; } +#ifdef DRIVER_CTX_CTOR + if ( ctx.handle != DRM_KERNEL_CONTEXT ) + DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) ) return -EFAULT; @@ -390,6 +398,9 @@ int DRM(rmctx)( struct inode *inode, struct file *filp, priv->remove_auth_on_close = 1; } if ( ctx.handle != DRM_KERNEL_CONTEXT ) { +#ifdef DRIVER_CTX_DTOR + DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */ +#endif DRM(ctxbitmap_free)( dev, ctx.handle ); } diff --git a/drivers/char/drm/sis.h b/drivers/char/drm/sis.h new file mode 100644 index 000000000..9903c0037 --- /dev/null +++ b/drivers/char/drm/sis.h @@ -0,0 +1,56 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.1 2001/05/19 18:29:22 dawes Exp $ */ + +#ifndef __SIS_H__ +#define __SIS_H__ + +/* This remains constant for all DRM template files. + * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel + * that's used for fb devices + */ +#define DRM(x) sisdrv_##x + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +/* Buffer customization: + */ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_sis_private_t *)((dev)->dev_private))->buffers + +extern int sis_init_context(int context); +extern int sis_final_context(int context); + +#define DRIVER_CTX_CTOR sis_init_context +#define DRIVER_CTX_DTOR sis_final_context + +#endif diff --git a/drivers/char/drm/sis_drm.h b/drivers/char/drm/sis_drm.h new file mode 100644 index 000000000..339ed5a00 --- /dev/null +++ b/drivers/char/drm/sis_drm.h @@ -0,0 +1,36 @@ + +#ifndef _sis_drm_public_h_ +#define _sis_drm_public_h_ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned int free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int left, right; +} drm_sis_flip_t; + +#ifdef __KERNEL__ + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); + +#endif + +#endif diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c new file mode 100644 index 000000000..3dd83fd7e --- /dev/null +++ b/drivers/char/drm/sis_drv.c @@ -0,0 +1,74 @@ +/* sis.c -- sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include <linux/config.h> +#include "sis.h" +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" + +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20010503" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 1 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 1 }, \ + /* AGP Memory Management */ \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 1 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 1 }, \ + [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 1 } +#if 0 /* these don't appear to be defined */ + /* SIS Stereo */ + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 }, + [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } +#endif + +#define __HAVE_COUNTERS 5 + +#include "drm_auth.h" +#include "drm_agpsupport.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_drv.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lists.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h new file mode 100644 index 000000000..844e38b07 --- /dev/null +++ b/drivers/char/drm/sis_drv.h @@ -0,0 +1,45 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _SIS_DRV_H_ +#define _SIS_DRV_H_ + +typedef struct drm_sis_private { + drm_map_t *buffers; +} drm_sis_private_t; + +/* Stereo ? - this was never committed */ + +int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +void flip_final(void); + +#endif diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c new file mode 100644 index 000000000..6143ad83a --- /dev/null +++ b/drivers/char/drm/sis_ds.c @@ -0,0 +1,406 @@ +/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <linux/poll.h> +#include <asm/io.h> +#include <linux/pci.h> + +#include "sis_ds.h" + +/* Set Data Structure, not check repeated value + * temporarily used + */ + +set_t *setInit(void) +{ + int i; + set_t *set; + + set = (set_t *)MALLOC(sizeof(set_t)); + for(i = 0; i < SET_SIZE; i++){ + set->list[i].free_next = i+1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + + return set; +} + +int setAdd(set_t *set, ITEM_TYPE item) +{ + int free = set->free; + + if(free != -1){ + set->list[free].val = item; + set->free = set->list[free].free_next; + } + else{ + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + + return 1; +} + +int setDel(set_t *set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while(alloc != -1){ + if(set->list[alloc].val == item){ + if(prev != -1) + set->list[prev].alloc_next = set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if(alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int setFirst(set_t *set, ITEM_TYPE *item) +{ + if(set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int setNext(set_t *set, ITEM_TYPE *item) +{ + if(set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int setDestroy(set_t *set) +{ + FREE(set); + + return 1; +} + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define ISFREE(bptr) ((bptr)->free) + +#define PRINTF(fmt, arg...) do{}while(0) +#define fprintf(fmt, arg...) do{}while(0) + +static void *calloc(size_t nmemb, size_t size) +{ + void *addr; + addr = kmalloc(nmemb*size, GFP_KERNEL); + memset(addr, 0, nmemb*size); + return addr; +} +#define free(n) kfree(n) + +void mmDumpMemInfo( memHeap_t *heap ) +{ + TMemBlock *p; + + PRINTF ("Memory heap %p:\n", heap); + if (heap == 0) { + PRINTF (" heap == 0\n"); + } else { + p = (TMemBlock *)heap; + while (p) { + PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, + p->free ? '.':'U', + p->reserved ? 'R':'.'); + p = p->next; + } + } + PRINTF ("End of memory blocks\n"); +} + +memHeap_t *mmInit(int ofs, + int size) +{ + PMemBlock blocks; + + if (size <= 0) { + return 0; + } + blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock)); + if (blocks) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Kludgey workaround for existing i810 server. Remove soon. + */ +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ) +{ + PMemBlock blocks; + blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock)); + if (blocks) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join non-adjacent + * ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock) heap; + return (memHeap_t *)blocks; + } + else + return heap; +} + +static TMemBlock* SliceBlock(TMemBlock *p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) +{ + int mask,startofs,endofs; + TMemBlock *p; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (!p) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; +} + +static __inline__ int Join2Blocks(TMemBlock *p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + free(q); + return 1; + } + return 0; +} + +int mmFreeMem(PMemBlock b) +{ + TMemBlock *p,*prev; + + if (!b) + return 0; + if (!b->heap) { + fprintf(stderr, "no heap\n"); + return -1; + } + p = b->heap; + prev = NULL; + while (p && p != b) { + prev = p; + p = p->next; + } + if (!p || p->free || p->reserved) { + if (!p) + fprintf(stderr, "block not found in heap\n"); + else if (p->free) + fprintf(stderr, "block already free\n"); + else + fprintf(stderr, "block is reserved\n"); + return -1; + } + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +int mmReserveMem(memHeap_t *heap, int offset,int size) +{ + int endofs; + TMemBlock *p; + + if (!heap || size <= 0) + return -1; + endofs = offset+size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; +} + +int mmFreeReserved(memHeap_t *heap, int offset) +{ + TMemBlock *p,*prev; + + if (!heap) + return -1; + p = (TMemBlock *)heap; + prev = NULL; + while (p && p->ofs != offset) { + prev = p; + p = p->next; + } + if (!p || !p->reserved) + return -1; + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +void mmDestroy(memHeap_t *heap) +{ + TMemBlock *p,*q; + + if (!heap) + return; + p = (TMemBlock *)heap; + while (p) { + q = p->next; + free(p); + p = q; + } +} diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h new file mode 100644 index 000000000..c3367dba7 --- /dev/null +++ b/drivers/char/drm/sis_ds.h @@ -0,0 +1,163 @@ +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#ifndef _sis_ds_h_ +#define _sis_ds_h_ + +/* Set Data Structure */ + +#define SET_SIZE 5000 +#define MALLOC(s) kmalloc(s, GFP_KERNEL) +#define FREE(s) kfree(s) + +typedef unsigned int ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *setInit(void); +int setAdd(set_t *set, ITEM_TYPE item); +int setDel(set_t *set, ITEM_TYPE item); +int setFirst(set_t *set, ITEM_TYPE *item); +int setNext(set_t *set, ITEM_TYPE *item); +int setDestroy(set_t *set); + +#endif + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef MM_INC +#define MM_INC + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ return b->size; } + +static __inline__ int mmOffset(PMemBlock b) +{ return b->ofs; } + +static __inline__ void mmMarkReserved(PMemBlock b) +{ b->reserved = 1; } + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *mmInit( int ofs, int size ); + + + +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ); + + +/* + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int mmFreeMem( PMemBlock b ); + +/* + * Reserve 'size' bytes block start at offset + * This is used to prevent allocation of memory already used + * by the X server for the front buffer, pixmaps, and cursor + * input: size, offset + * output: 0 if OK, -1 if error + */ +int mmReserveMem( memHeap_t *heap, int offset,int size ); +int mmFreeReserved( memHeap_t *heap, int offset ); + +/* + * destroy MM + */ +void mmDestroy( memHeap_t *mmInit ); + +/* For debuging purpose. */ +void mmDumpMemInfo( memHeap_t *mmInit ); + +#endif diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c new file mode 100644 index 000000000..81832769d --- /dev/null +++ b/drivers/char/drm/sis_mm.c @@ -0,0 +1,307 @@ +/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#define __NO_VERSION__ +#include "sis.h" +#include <linux/sisfb.h> +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" +#include "sis_ds.h" + +#define MAX_CONTEXT 100 +#define VIDEO_TYPE 0 +#define AGP_TYPE 1 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ +} sis_context_t; + +static sis_context_t global_ppriv[MAX_CONTEXT]; + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + for(i = 0; i < MAX_CONTEXT; i++) + if(global_ppriv[i].used && global_ppriv[i].context == context){ + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + return retval; +} + +/* fb management via fb device */ +#if 1 +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + req.size = fb.size; + sis_malloc(&req); + if(req.offset){ + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = -1; + } + } + else{ + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT; + + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t fb; + int retval = 0; + + if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) + return -EFAULT; + + if(!fb.free){ + return -1; + } + + sis_free(fb.free); + if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = -1; + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; +} + +#else + +int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return -1; +} + +int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +#endif + +/* agp memory management */ +#if 1 + +static memHeap_t *AgpHeap = NULL; + +int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_agp_t agp; + + if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp))) + return -EFAULT; + + AgpHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + + return 0; +} + +int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + block = mmAllocMem(AgpHeap, agp.size, 0, 0); + if(block){ + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned int)block; + if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } + else{ + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT; + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; +} + +int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_sis_mem_t agp; + int retval = 0; + + if(!AgpHeap) + return -1; + + if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) + return -EFAULT; + + if(!agp.free){ + return -1; + } + + mmFreeMem((PMemBlock)agp.free); + if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + retval = -1; + + DRM_DEBUG("free agp, free = %d\n", agp.free); + + return retval; +} + +#endif + +int sis_init_context(int context) +{ + int i; + + for(i = 0; i < MAX_CONTEXT ; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i >= MAX_CONTEXT){ + for(i = 0; i < MAX_CONTEXT ; i++){ + if(!global_ppriv[i].used){ + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, context = %d\n", + i, context); + break; + } + } + if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)){ + return 0; + } + } + + return 1; +} + +int sis_final_context(int context) +{ + int i; + + for(i=0; i<MAX_CONTEXT; i++) + if(global_ppriv[i].used && (global_ppriv[i].context == context)) + break; + + if(i < MAX_CONTEXT){ + set_t *set; + unsigned int item; + int retval; + + DRM_DEBUG("find socket %d, context = %d\n", i, context); + + /* Video Memory */ + set = global_ppriv[i].sets[0]; + retval = setFirst(set, &item); + while(retval){ + DRM_DEBUG("free video memory 0x%x\n", item); + sis_free(item); + retval = setNext(set, &item); + } + setDestroy(set); + + /* AGP Memory */ + set = global_ppriv[i].sets[1]; + retval = setFirst(set, &item); + while(retval){ + DRM_DEBUG("free agp memory 0x%x\n", item); + mmFreeMem((PMemBlock)item); + retval = setNext(set, &item); + } + setDestroy(set); + + global_ppriv[i].used = 0; + } + + /* turn-off auto-flip */ + /* TODO */ +#if defined(SIS_STEREO) + flip_final(); +#endif + + return 1; +} diff --git a/drivers/char/joystick/cs461x.c b/drivers/char/joystick/cs461x.c index 7116b3453..6b096f0fe 100644 --- a/drivers/char/joystick/cs461x.c +++ b/drivers/char/joystick/cs461x.c @@ -313,7 +313,7 @@ static struct pci_driver cs461x_pci_driver = { name: "PCI Gameport", id_table: cs461x_pci_tbl, probe: cs461x_pci_probe, - remove: cs461x_pci_remove, + remove: __devexit_p(cs461x_pci_remove), }; int __init js_cs461x_init(void) diff --git a/drivers/char/joystick/emu10k1-gp.c b/drivers/char/joystick/emu10k1-gp.c index 2489b11c6..4763a02c7 100644 --- a/drivers/char/joystick/emu10k1-gp.c +++ b/drivers/char/joystick/emu10k1-gp.c @@ -108,7 +108,7 @@ static struct pci_driver emu_driver = { name: "Emu10k1 Gameport", id_table: emu_tbl, probe: emu_probe, - remove: emu_remove, + remove: __devexit_p(emu_remove), }; int __init emu_init(void) diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c index 04e1bee04..194814ca6 100644 --- a/drivers/char/joystick/pcigame.c +++ b/drivers/char/joystick/pcigame.c @@ -180,7 +180,7 @@ static struct pci_driver pcigame_driver = { name: "pcigame", id_table: pcigame_id_table, probe: pcigame_probe, - remove: pcigame_remove, + remove: __devexit_p(pcigame_remove), }; int __init pcigame_init(void) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 14f29671b..4f303001c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -272,6 +272,8 @@ static ssize_t read_kmem(struct file *file, char *buf, return virtr + read; } +extern long vwrite(char *buf, char *addr, unsigned long count); + /* * This function writes to the *virtual* memory as seen by the kernel. */ @@ -279,12 +281,46 @@ static ssize_t write_kmem(struct file * file, const char * buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; + ssize_t wrote = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ - if (p >= (unsigned long) high_memory) - return 0; - if (count > (unsigned long) high_memory - p) - count = (unsigned long) high_memory - p; - return do_write_mem(file, (void*)p, p, buf, count, ppos); + if (p < (unsigned long) high_memory) { + wrote = count; + if (count > (unsigned long) high_memory - p) + wrote = (unsigned long) high_memory - p; + + wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos); + + p += wrote; + buf += wrote; + count -= wrote; + } + + if (count > 0) { + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + if (len && copy_from_user(kbuf, buf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + len = vwrite(kbuf, (char *)p, len); + count -= len; + buf += len; + virtr += len; + p += len; + } + free_page((unsigned long)kbuf); + } + + *ppos = p; + return virtr + wrote; } #if !defined(__mc68000__) diff --git a/drivers/char/serial.c b/drivers/char/serial.c index d680bfd72..adbe3ffa8 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -4892,7 +4892,7 @@ MODULE_DEVICE_TABLE(pci, serial_pci_tbl); static struct pci_driver serial_pci_driver = { name: "serial", probe: serial_init_one, - remove: serial_remove_one, + remove: __devexit_p(serial_remove_one), id_table: serial_pci_tbl, }; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index ae4cd8890..92bc9c5c4 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -617,8 +617,11 @@ static int __devinit sonypi_probe(struct pci_dev *pcidev) { goto out3; } +#if !defined(CONFIG_ACPI) + /* Enable ACPI mode to get Fn key events */ if (fnkeyinit) outb(0xf0, 0xb2); +#endif if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) sonypi_type2_srs(); @@ -666,6 +669,11 @@ static void __devexit sonypi_remove(void) { sonypi_type2_dis(); else sonypi_type1_dis(); +#if !defined(CONFIG_ACPI) + /* disable ACPI mode */ + if (fnkeyinit) + outb(0xf1, 0xb2); +#endif free_irq(sonypi_device.irq, sonypi_irq); release_region(sonypi_device.ioport1, sonypi_device.region_size); misc_deregister(&sonypi_misc_device); diff --git a/drivers/char/sonypi.h b/drivers/char/sonypi.h index 4385b3c5a..9d8360860 100644 --- a/drivers/char/sonypi.h +++ b/drivers/char/sonypi.h @@ -35,7 +35,7 @@ #ifdef __KERNEL__ #define SONYPI_DRIVER_MAJORVERSION 1 -#define SONYPI_DRIVER_MINORVERSION 7 +#define SONYPI_DRIVER_MINORVERSION 8 #include <linux/types.h> #include <linux/pci.h> diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 94200f895..970ec27a7 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -2374,7 +2374,7 @@ static struct pci_driver ohci1394_driver = { name: OHCI1394_DRIVER_NAME, id_table: ohci1394_pci_tbl, probe: ohci1394_add_one, - remove: ohci1394_remove_one, + remove: __devexit_p(ohci1394_remove_one), }; static void __exit ohci1394_cleanup (void) diff --git a/drivers/isdn/eicon/common.c b/drivers/isdn/eicon/common.c index f2b4d0452..77d3a50b9 100644 --- a/drivers/isdn/eicon/common.c +++ b/drivers/isdn/eicon/common.c @@ -808,7 +808,9 @@ void DivasDoDpc(void *pData) while(i--) { - DivaDoCardDpc(card++); + if (card->state == DIA_RUNNING) + DivaDoCardDpc(card); + card++; } } diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 77f90cbb8..cd7466596 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.23.6.5 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h index 2ccfeb0fb..8cac8ffa8 100644 --- a/drivers/isdn/eicon/eicon_dsp.h +++ b/drivers/isdn/eicon/eicon_dsp.h @@ -1,4 +1,4 @@ -/* $Id: eicon_dsp.h,v 1.7.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_dsp.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * DSP definitions diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index b44cc2ba6..5c6f2ac38 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.41.6.4 2001/11/06 20:58:29 kai Exp $ +/* $Id: eicon_idi.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,7 +25,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.41.6.4 $"; +char *eicon_idi_revision = "$Revision: 1.1.4.1 $"; eicon_manifbuf *manbuf; diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index c0cab657b..eefa56eb4 100644 --- a/drivers/isdn/eicon/eicon_idi.h +++ b/drivers/isdn/eicon/eicon_idi.h @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.11.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_idi.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN lowlevel-module for the Eicon active cards. * IDI-Interface diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index ff61c5f10..cfbded538 100644 --- a/drivers/isdn/eicon/eicon_io.c +++ b/drivers/isdn/eicon/eicon_io.c @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.13.6.2 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_io.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index a925d1f3e..e5ae07744 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.16.6.2 2001/11/06 20:58:29 kai Exp $ +/* $Id: eicon_isa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -20,7 +20,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.16.6.2 $"; +char *eicon_isa_revision = "$Revision: 1.1.4.1 $"; #undef EICON_MCA_DEBUG diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h index 7502aabec..9379af626 100644 --- a/drivers/isdn/eicon/eicon_isa.h +++ b/drivers/isdn/eicon/eicon_isa.h @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.h,v 1.10.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_isa.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index b7c0adb47..ea424191e 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.37.6.6 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_mod.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -44,7 +44,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.37.6.6 $"; +static char *eicon_revision = "$Revision: 1.1.4.1 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -1550,7 +1550,7 @@ int eicon_mca_find_card(int type, /* type-idx of eicon-card */ }; }; /* all adapter flavors checked without match, finito with: */ - return ENODEV; + return -ENODEV; }; @@ -1597,14 +1597,14 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ membase = cards_membase; } else { if (membase != cards_membase) - return ENODEV; + return -ENODEV; }; cards_irq=irq_array[((adf_pos0 & 0xC)>>2)]; if (irq == -1) { irq = cards_irq; } else { if (irq != cards_irq) - return ENODEV; + return -ENODEV; }; cards_io= 0xC00 + ((adf_pos0>>4)*0x10); type = EICON_CTYPE_ISAPRI; @@ -1616,14 +1616,14 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ membase = cards_membase; } else { if (membase != cards_membase) - return ENODEV; + return -ENODEV; }; cards_irq=irq_array[((adf_pos0 & 0xC)>>2)]; if (irq == -1) { irq = cards_irq; } else { if (irq != cards_irq) - return ENODEV; + return -ENODEV; }; cards_io= 0xC00 + ((adf_pos0>>4)*0x10); @@ -1637,12 +1637,12 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ irq = cards_irq; } else { if (irq != cards_irq) - return ENODEV; + return -ENODEV; }; type = 0; break; default: - return ENODEV; + return -ENODEV; }; /* matching membase & irq */ if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { @@ -1661,7 +1661,7 @@ int eicon_mca_probe(int slot, /* slot-nr where the card was detected */ cards->mca_slot+1); return 0 ; /* eicon_addcard added a card */ } else { - return ENODEV; + return -ENODEV; }; }; #endif /* CONFIG_MCA */ diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index 69c0a0b79..d1dba2d5c 100644 --- a/drivers/isdn/eicon/eicon_pci.c +++ b/drivers/isdn/eicon/eicon_pci.c @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.15.6.3 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -24,7 +24,7 @@ #include "adapter.h" #include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.15.6.3 $"; +char *eicon_pci_revision = "$Revision: 1.1.4.1 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ #ifdef CONFIG_ISDN_DRV_EICON_PCI diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h index 7e615c6f3..d87c8cacf 100644 --- a/drivers/isdn/eicon/eicon_pci.h +++ b/drivers/isdn/eicon/eicon_pci.h @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.h,v 1.6.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_pci.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards (PCI part). * diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index c056dc334..bc098205d 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -485,7 +485,7 @@ static int __init HiSax_setup(char *line) if (strlen(str) < HISAX_IDSIZE) strcpy(HiSaxID, str); else - printk(KERN_WARNING "HiSax: ID too long!") + printk(KERN_WARNING "HiSax: ID too long!"); } else strcpy(HiSaxID, "HiSax"); diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c index 479e18fa8..a8359bb81 100644 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ b/drivers/isdn/hisax/hisax_fcpcipnp.c @@ -533,7 +533,7 @@ static inline void hdlc_xpr_irq(struct fritz_bcs *bcs) dev_kfree_skb_irq(skb); } -static void hdlc_irq(struct fritz_bcs *bcs, u32 stat) +static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat) { DBG(0x10, "ch%d stat %#x", bcs->channel, stat); if (stat & HDLC_INT_RPR) { @@ -550,7 +550,7 @@ static void hdlc_irq(struct fritz_bcs *bcs, u32 stat) } } -static inline void hdlc_interrupt(struct fritz_adapter *adapter) +static inline void hdlc_irq(struct fritz_adapter *adapter) { int nr; u32 stat; @@ -559,7 +559,7 @@ static inline void hdlc_interrupt(struct fritz_adapter *adapter) stat = adapter->read_hdlc_status(adapter, nr); DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat); if (stat & HDLC_INT_MASK) - hdlc_irq(&adapter->bcs[nr], stat); + hdlc_irq_one(&adapter->bcs[nr], stat); } } @@ -642,10 +642,10 @@ static void fcpci2_irq(int intno, void *dev, struct pt_regs *regs) return; DBG(2, "STATUS0 %#x", val); if (val & AVM_STATUS0_IRQ_ISAC) - isacsx_interrupt(&adapter->isac); + isacsx_irq(&adapter->isac); if (val & AVM_STATUS0_IRQ_HDLC) - hdlc_interrupt(adapter); + hdlc_irq(adapter); } static void fcpci_irq(int intno, void *dev, struct pt_regs *regs) @@ -659,10 +659,10 @@ static void fcpci_irq(int intno, void *dev, struct pt_regs *regs) return; DBG(2, "sval %#x", sval); if (!(sval & AVM_STATUS0_IRQ_ISAC)) - isac_interrupt(&adapter->isac); + isac_irq(&adapter->isac); if (!(sval & AVM_STATUS0_IRQ_HDLC)) - hdlc_interrupt(adapter); + hdlc_irq(adapter); } // ---------------------------------------------------------------------- diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c index 9a6a5065b..29a96edf3 100644 --- a/drivers/isdn/hisax/hisax_isac.c +++ b/drivers/isdn/hisax/hisax_isac.c @@ -601,7 +601,7 @@ static inline void isac_exi_interrupt(struct isac *isac) } } -void isac_interrupt(struct isac *isac) +void isac_irq(struct isac *isac) { unsigned char val; @@ -741,7 +741,7 @@ static inline void isacsx_icd_interrupt(struct isac *isac) } } -void isacsx_interrupt(struct isac *isac) +void isacsx_irq(struct isac *isac) { unsigned char val; @@ -887,10 +887,10 @@ EXPORT_SYMBOL(isac_init); EXPORT_SYMBOL(isac_d_l2l1); EXPORT_SYMBOL(isacsx_setup); -EXPORT_SYMBOL(isacsx_interrupt); +EXPORT_SYMBOL(isacsx_irq); EXPORT_SYMBOL(isac_setup); -EXPORT_SYMBOL(isac_interrupt); +EXPORT_SYMBOL(isac_irq); module_init(hisax_isac_init); module_exit(hisax_isac_exit); diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h index 6b8d2dfa0..08890cf4d 100644 --- a/drivers/isdn/hisax/hisax_isac.h +++ b/drivers/isdn/hisax/hisax_isac.h @@ -37,9 +37,9 @@ void isac_init(struct isac *isac); void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); void isac_setup(struct isac *isac); -void isac_interrupt(struct isac *isac); +void isac_irq(struct isac *isac); void isacsx_setup(struct isac *isac); -void isacsx_interrupt(struct isac *isac); +void isacsx_irq(struct isac *isac); #endif diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 17b2a4325..0aa033579 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -275,7 +275,7 @@ static int __devinit st5481_setup_b_out(struct st5481_bcs *bcs) usb_b_out_complete, bcs); } -static void __devexit st5481_release_b_out(struct st5481_bcs *bcs) +static void st5481_release_b_out(struct st5481_bcs *bcs) { struct st5481_b_out *b_out = &bcs->b_out; @@ -316,7 +316,7 @@ int __devinit st5481_setup_b(struct st5481_bcs *bcs) /* * Release buffers and URBs for the B channels */ -void __devexit st5481_release_b(struct st5481_bcs *bcs) +void st5481_release_b(struct st5481_bcs *bcs) { DBG(4,""); diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index ce751cc46..1079bae6e 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -673,7 +673,7 @@ static int __devinit st5481_setup_d_out(struct st5481_adapter *adapter) usb_d_out_complete, adapter); } -static void __devexit st5481_release_d_out(struct st5481_adapter *adapter) +static void st5481_release_d_out(struct st5481_adapter *adapter) { struct st5481_d_out *d_out = &adapter->d_out; @@ -723,7 +723,7 @@ int __devinit st5481_setup_d(struct st5481_adapter *adapter) return retval; } -void __devexit st5481_release_d(struct st5481_adapter *adapter) +void st5481_release_d(struct st5481_adapter *adapter) { DBG(2,""); diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 28ea25bf5..8aad86d9d 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -178,7 +178,7 @@ MODULE_DEVICE_TABLE (usb, st5481_ids); static struct usb_driver st5481_usb_driver = { name: "st5481_usb", probe: probe_st5481, - disconnect: disconnect_st5481, + disconnect: __devexit_p(disconnect_st5481), id_table: st5481_ids, }; diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 859c164f5..a3098071f 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -307,7 +307,7 @@ int __devinit st5481_setup_usb(struct st5481_adapter *adapter) * Release buffers and URBs for the interrupt and control * endpoint. */ -void __devexit st5481_release_usb(struct st5481_adapter *adapter) +void st5481_release_usb(struct st5481_adapter *adapter) { struct st5481_intr *intr = &adapter->intr; struct st5481_ctrl *ctrl = &adapter->ctrl; @@ -443,7 +443,7 @@ st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, return retval; } -void __devexit st5481_release_isocpipes(struct urb* urb[2]) +void st5481_release_isocpipes(struct urb* urb[2]) { int j; @@ -547,7 +547,7 @@ int __devinit st5481_setup_in(struct st5481_in *in) return retval; } -void __devexit st5481_release_in(struct st5481_in *in) +void st5481_release_in(struct st5481_in *in) { DBG(2,""); diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c deleted file mode 100644 index 39c7bd8a8..000000000 --- a/drivers/isdn/hysdn/hysdn_procfs.c +++ /dev/null @@ -1,471 +0,0 @@ -/* $Id: hysdn_procfs.c,v 1.1 2000/02/10 19:45:18 werner Exp $ - - * Linux driver for HYSDN cards, /proc/net filesystem log functions. - * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH - * - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Log: hysdn_procfs.c,v $ - * Revision 1.1 2000/02/10 19:45:18 werner - * - * Initial release - * - * - */ - -#define __NO_VERSION__ -#include <linux/module.h> -#include <linux/version.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/pci.h> -#include <linux/smp_lock.h> - -#include "hysdn_defs.h" - -static char *hysdn_procfs_revision = "$Revision: 1.1 $"; - -#define INFO_OUT_LEN 80 /* length of info line including lf */ - -/*************************************************/ -/* structure keeping ascii log for device output */ -/*************************************************/ -struct log_data { - struct log_data *next; - ulong usage_cnt; /* number of files still to work */ - void *proc_ctrl; /* pointer to own control procdata structure */ - char log_start[2]; /* log string start (final len aligned by size) */ -}; - -/**********************************************/ -/* structure holding proc entrys for one card */ -/**********************************************/ -struct procdata { - struct proc_dir_entry *log; /* log entry */ - char log_name[15]; /* log filename */ - struct log_data *log_head, *log_tail; /* head and tail for queue */ - int if_used; /* open count for interface */ - wait_queue_head_t rd_queue; -}; - -/********************************************/ -/* put an log buffer into the log queue. */ -/* This buffer will be kept until all files */ -/* opened for read got the contents. */ -/* Flushes buffers not longer in use. */ -/********************************************/ -void -put_log_buffer(hysdn_card * card, char *cp) -{ - struct log_data *ib; - struct procdata *pd = card->procfs; - int flags; - - if (!pd) - return; - if (!cp) - return; - if (!*cp) - return; - if (pd->if_used <= 0) - return; /* no open file for read */ - - if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) - return; /* no memory */ - strcpy(ib->log_start, cp); /* set output string */ - ib->next = NULL; - ib->proc_ctrl = pd; /* point to own control structure */ - save_flags(flags); - cli(); - ib->usage_cnt = pd->if_used; - if (!pd->log_head) - pd->log_head = ib; /* new head */ - else - pd->log_tail->next = ib; /* follows existing messages */ - pd->log_tail = ib; /* new tail */ - restore_flags(flags); - - /* delete old entrys */ - while (pd->log_head->next) { - if ((pd->log_head->usage_cnt <= 0) && - (pd->log_head->next->usage_cnt <= 0)) { - ib = pd->log_head; - pd->log_head = pd->log_head->next; - kfree(ib); - } else - break; - } /* pd->log_head->next */ - wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ -} /* put_log_buffer */ - - -/**********************************/ -/* log file operations and tables */ -/**********************************/ - -/****************************************/ -/* write log file -> set log level bits */ -/****************************************/ -static ssize_t -hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off) -{ - int retval; - hysdn_card *card = (hysdn_card *) file->private_data; - - if (&file->f_pos != off) /* fs error check */ - return (-ESPIPE); - - if ((retval = pof_boot_write(card, buf, count)) < 0) - retval = -EFAULT; /* an error occurred */ - - return (retval); -} /* hysdn_log_write */ - -/******************/ -/* read log file */ -/******************/ -static ssize_t -hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off) -{ - struct log_data *inf; - int len; - word ino; - struct procdata *pd; - hysdn_card *card; - - if (!*((struct log_data **) file->private_data)) { - if (file->f_flags & O_NONBLOCK) - return (-EAGAIN); - - /* sorry, but we need to search the card */ - ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ - card = card_root; - while (card) { - pd = card->procfs; - if (pd->log->low_ino == ino) - break; - card = card->next; /* search next entry */ - } - if (card) - interruptible_sleep_on(&(pd->rd_queue)); - else - return (-EAGAIN); - - } - if (!(inf = *((struct log_data **) file->private_data))) - return (0); - - inf->usage_cnt--; /* new usage count */ - (struct log_data **) file->private_data = &inf->next; /* next structure */ - if ((len = strlen(inf->log_start)) <= count) { - if (copy_to_user(buf, inf->log_start, len)) - return -EFAULT; - file->f_pos += len; - return (len); - } - return (0); -} /* hysdn_log_read */ - -/******************/ -/* open log file */ -/******************/ -static int -hysdn_log_open(struct inode *ino, struct file *filep) -{ - hysdn_card *card; - struct procdata *pd; - ulong flags; - - lock_kernel(); - card = card_root; - while (card) { - pd = card->procfs; - if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) - break; - card = card->next; /* search next entry */ - } - if (!card) { - unlock_kernel(); - return (-ENODEV); /* device is unknown/invalid */ - } - filep->private_data = card; /* remember our own card */ - - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> boot pof data */ - if (pof_boot_open(card)) { - unlock_kernel(); - return (-EPERM); /* no permission this time */ - } - } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - - /* read access -> log/debug read */ - save_flags(flags); - cli(); - pd->if_used++; - if (pd->log_head) - (struct log_data **) filep->private_data = &(pd->log_tail->next); - else - (struct log_data **) filep->private_data = &(pd->log_head); - restore_flags(flags); - - } else { /* simultaneous read/write access forbidden ! */ - unlock_kernel(); - return (-EPERM); /* no permission this time */ - } - unlock_kernel(); - return (0); -} /* hysdn_log_open */ - -/*******************************************************************************/ -/* close a cardlog file. If the file has been opened for exclusive write it is */ -/* assumed as pof data input and the pof loader is noticed about. */ -/* Otherwise file is handled as log output. In this case the interface usage */ -/* count is decremented and all buffers are noticed of closing. If this file */ -/* was the last one to be closed, all buffers are freed. */ -/*******************************************************************************/ -static int -hysdn_log_close(struct inode *ino, struct file *filep) -{ - struct log_data *inf; - struct procdata *pd; - hysdn_card *card; - int flags, retval = 0; - - lock_kernel(); - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> write debug completely written */ - retval = 0; /* success */ - } else { - /* read access -> log/debug read, mark one further file as closed */ - - pd = NULL; - save_flags(flags); - cli(); - inf = *((struct log_data **) filep->private_data); /* get first log entry */ - if (inf) - pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ - else { - /* no info available -> search card */ - card = card_root; - while (card) { - pd = card->procfs; - if (pd->log->low_ino == (ino->i_ino & 0xFFFF)) - break; - card = card->next; /* search next entry */ - } - if (card) - pd = card->procfs; /* pointer to procfs ctrl */ - } - if (pd) - pd->if_used--; /* decrement interface usage count by one */ - - while (inf) { - inf->usage_cnt--; /* decrement usage count for buffers */ - inf = inf->next; - } - restore_flags(flags); - - if (pd) - if (pd->if_used <= 0) /* delete buffers if last file closed */ - while (pd->log_head) { - inf = pd->log_head; - pd->log_head = pd->log_head->next; - kfree(inf); - } - } /* read access */ - - unlock_kernel(); - return (retval); -} /* hysdn_log_close */ - -/*************************************************/ -/* select/poll routine to be able using select() */ -/*************************************************/ -static unsigned int -hysdn_log_poll(struct file *file, poll_table * wait) -{ - unsigned int mask = 0; - word ino; - hysdn_card *card; - struct procdata *pd; - - if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) - return (mask); /* no polling for write supported */ - - /* we need to search the card */ - ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */ - card = card_root; - while (card) { - pd = card->procfs; - if (pd->log->low_ino == ino) - break; - card = card->next; /* search next entry */ - } - if (!card) - return (mask); /* card not found */ - - poll_wait(file, &(pd->rd_queue), wait); - - if (*((struct log_data **) file->private_data)) - mask |= POLLIN | POLLRDNORM; - - return mask; -} /* hysdn_log_poll */ - -/**************************************************/ -/* table for log filesystem functions defined above. */ -/**************************************************/ -static struct file_operations log_fops = -{ - llseek: no_llseek, - read: hysdn_log_read, - write: hysdn_log_write, - poll: hysdn_log_poll, - open: hysdn_log_open, - release: hysdn_log_close, -}; - -/*****************************************/ -/* Output info data to the cardinfo file */ -/*****************************************/ -static int -info_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) -{ - char tmp[INFO_OUT_LEN * 11 + 2]; - int i; - char *cp; - hysdn_card *card; - - sprintf(tmp, "id bus slot type irq iobase plx-mem dp-mem boot device"); - cp = tmp; /* start of string */ - while (*cp) - cp++; - while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) - *cp++ = ' '; - *cp++ = '\n'; - - card = card_root; /* start of list */ - while (card) { - sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x 0x%08x", - card->myid, - card->bus, - PCI_SLOT(card->devfn), - card->brdtype, - card->irq, - card->iobase, - card->plxbase, - card->membase); - card = card->next; - while (*cp) - cp++; - while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) - *cp++ = ' '; - *cp++ = '\n'; - } - - i = cp - tmp; - *start = buffer; - if (offset + length > i) { - length = i - offset; - *eof = 1; - } else if (offset > i) { - length = 0; - *eof = 1; - } - cp = tmp + offset; - - if (length > 0) { - /* start_bh_atomic(); */ - memcpy(buffer, cp, length); - /* end_bh_atomic(); */ - return length; - } - return 0; -} /* info_read */ - -/*****************************/ -/* hysdn subdir in /proc/net */ -/*****************************/ -static struct proc_dir_entry *hysdn_proc_entry = NULL; -static struct proc_dir_entry *hysdn_info_entry = NULL; - -/***************************************************************************************/ -/* hysdn_procfs_init is called when the module is loaded and after the cards have been */ -/* detected. The needed proc dir and card entries are created. */ -/***************************************************************************************/ -int -hysdn_procfs_init(void) -{ - struct procdata *pd; - hysdn_card *card; - - hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net); - if (!hysdn_proc_entry) { - printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); - return (-1); - } - hysdn_info_entry = create_proc_entry("cardinfo", 0, hysdn_proc_entry); - if (hysdn_info_entry) - hysdn_info_entry->read_proc = info_read; /* read info function */ - - /* create all cardlog proc entries */ - - card = card_root; /* start with first card */ - while (card) { - if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { - memset(pd, 0, sizeof(struct procdata)); - - sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - pd->log->proc_fops = &log_fops; /* set new operations table */ - pd->log->owner = THIS_MODULE; - } - - init_waitqueue_head(&(pd->rd_queue)); - - card->procfs = (void *) pd; /* remember procfs structure */ - } - card = card->next; /* point to next card */ - } - - printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procfs_revision)); - return (0); -} /* hysdn_procfs_init */ - -/***************************************************************************************/ -/* hysdn_procfs_release is called when the module is unloaded and before the cards */ -/* resources are released. The module counter is assumed to be 0 ! */ -/***************************************************************************************/ -void -hysdn_procfs_release(void) -{ - struct procdata *pd; - hysdn_card *card; - - card = card_root; /* start with first card */ - while (card) { - if ((pd = (struct procdata *) card->procfs) != NULL) { - if (pd->log) - remove_proc_entry(pd->log_name, hysdn_proc_entry); - kfree(pd); /* release memory */ - } - card = card->next; /* point to next card */ - } - - remove_proc_entry("cardinfo", hysdn_proc_entry); - remove_proc_entry(PROC_SUBDIR_NAME, proc_net); -} /* hysdn_procfs_release */ diff --git a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c index 9a000b3d1..4573cad5a 100644 --- a/drivers/isdn/tpam/tpam_main.c +++ b/drivers/isdn/tpam/tpam_main.c @@ -254,7 +254,7 @@ static struct pci_driver tpam_driver = { name: "tpam", id_table: tpam_pci_tbl, probe: tpam_probe, - remove: tpam_remove, + remove: __devexit_p(tpam_remove), }; static int __init tpam_init(void) { diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 68f612caa..9da6a3619 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -424,7 +424,7 @@ static struct pci_driver gemtek_pci_driver = name: "gemtek_pci", id_table: gemtek_pci_id, probe: gemtek_pci_probe, - remove: gemtek_pci_remove + remove: __devexit_p(gemtek_pci_remove), }; static int __init gemtek_pci_init_module( void ) diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 1368ff2ed..dec250a7d 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -376,7 +376,7 @@ static struct pci_driver maxiradio_driver = { name: "radio-maxiradio", id_table: maxiradio_pci_tbl, probe: maxiradio_init_one, - remove: maxiradio_remove_one, + remove: __devexit_p(maxiradio_remove_one), }; int __init maxiradio_radio_init(void) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 86b14cd87..b04a03a87 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3025,7 +3025,7 @@ static struct pci_driver bttv_pci_driver = { name: "bttv", id_table: bttv_pci_tbl, probe: bttv_probe, - remove: bttv_remove, + remove: __devexit_p(bttv_remove), }; int bttv_init_module(void) diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 79c22b488..7ad5618f0 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1460,7 +1460,7 @@ static struct pci_driver meye_driver = { name: "meye", id_table: meye_pci_tbl, probe: meye_probe, - remove: meye_remove, + remove: __devexit_p(meye_remove), }; static int __init meye_init_module(void) { diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 62b7cf473..55e03ff65 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2919,7 +2919,7 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) static struct pci_driver vortex_driver = { name: "3c59x", probe: vortex_init_one, - remove: vortex_remove_one, + remove: __devexit_p(vortex_remove_one), id_table: vortex_pci_tbl, #ifdef CONFIG_PM suspend: vortex_suspend, diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ff5f5792f..f91b450e1 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1313,7 +1313,7 @@ static struct pci_driver cp_driver = { name: DRV_NAME, id_table: cp_pci_tbl, probe: cp_init_one, - remove: cp_remove_one, + remove: __devexit_p(cp_remove_one), }; static int __init cp_init (void) diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 45d102065..352d60eaf 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2494,7 +2494,7 @@ static struct pci_driver rtl8139_pci_driver = { name: DRV_NAME, id_table: rtl8139_pci_tbl, probe: rtl8139_init_one, - remove: rtl8139_remove_one, + remove: __devexit_p(rtl8139_remove_one), #ifdef CONFIG_PM suspend: rtl8139_suspend, resume: rtl8139_resume, diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index a6b5bc7ef..ff13552a6 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -160,7 +160,7 @@ static struct pci_driver com20020pci_driver = { name: "com20020", id_table: com20020pci_id_table, probe: com20020pci_probe, - remove: com20020pci_remove + remove: __devexit_p(com20020pci_remove), }; static int __init com20020pci_init(void) diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index 177dbed4e..d079bd417 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -3360,7 +3360,7 @@ MODULE_DEVICE_TABLE(pci, dfx_pci_tbl); static struct pci_driver dfx_driver = { name: "defxx", probe: dfx_init_one, - remove: dfx_remove_one, + remove: __devexit_p(dfx_remove_one), id_table: dfx_pci_tbl, }; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 161075784..657565a71 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1671,7 +1671,7 @@ static struct pci_driver rio_driver = { name:"dl2k", id_table:rio_pci_tbl, probe:rio_probe1, - remove:rio_remove1, + remove:__devexit_p(rio_remove1), }; static int __init diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index c33d5eccf..98d939356 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -2297,7 +2297,7 @@ static struct pci_driver eepro100_driver = { name: "eepro100", id_table: eepro100_pci_tbl, probe: eepro100_init_one, - remove: eepro100_remove_one, + remove: __devexit_p(eepro100_remove_one), #ifdef CONFIG_PM suspend: eepro100_suspend, resume: eepro100_resume, diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 468c675b4..f39c07ae4 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1507,7 +1507,7 @@ static struct pci_driver epic_driver = { name: DRV_NAME, id_table: epic_pci_tbl, probe: epic_init_one, - remove: epic_remove_one, + remove: __devexit_p(epic_remove_one), #ifdef CONFIG_PM suspend: epic_suspend, resume: epic_resume, diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e63a3c542..b782518e0 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1858,7 +1858,7 @@ static struct pci_driver fealnx_driver = { name: "fealnx", id_table: fealnx_pci_tbl, probe: fealnx_init_one, - remove: fealnx_remove_one, + remove: __devexit_p(fealnx_remove_one), }; static int __init fealnx_init(void) diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index dc1667b24..68a88a901 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -1515,7 +1515,7 @@ static struct pci_driver ioc3_driver = { name: "ioc3-eth", id_table: ioc3_pci_tbl, probe: ioc3_probe, - remove: ioc3_remove_one, + remove: __devexit_p(ioc3_remove_one), }; static int __init ioc3_init_module(void) diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index e46fe5293..000f83892 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1291,7 +1291,7 @@ static struct pci_driver vlsi_irda_driver = { name: drivername, id_table: vlsi_irda_table, probe: vlsi_irda_probe, - remove: vlsi_irda_remove, + remove: __devexit_p(vlsi_irda_remove), suspend: vlsi_irda_suspend, resume: vlsi_irda_resume, }; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 7d01a2c6e..1bd57184c 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -2518,7 +2518,7 @@ static struct pci_driver natsemi_driver = { name: DRV_NAME, id_table: natsemi_pci_tbl, probe: natsemi_probe1, - remove: natsemi_remove1, + remove: __devexit_p(natsemi_remove1), #ifdef CONFIG_PM suspend: natsemi_suspend, resume: natsemi_resume, diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 0189756a6..d1addf61c 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -642,7 +642,7 @@ static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) static struct pci_driver ne2k_driver = { name: DRV_NAME, probe: ne2k_pci_init_one, - remove: ne2k_pci_remove_one, + remove: __devexit_p(ne2k_pci_remove_one), id_table: ne2k_pci_tbl, }; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 8a1187855..55ff98ee4 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1455,7 +1455,7 @@ static struct pci_driver driver = { name: "ns83820", id_table: ns83820_pci_tbl, probe: ns83820_init_one, - remove: ns83820_remove_one, + remove: __devexit_p(ns83820_remove_one), #if 0 /* FIXME: implement */ suspend: , resume: , diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index e94d6c3cb..ee1d184c4 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1980,7 +1980,7 @@ static struct pci_driver netdrv_pci_driver = { name: MODNAME, id_table: netdrv_pci_tbl, probe: netdrv_init_one, - remove: netdrv_remove_one, + remove: __devexit_p(netdrv_remove_one), #ifdef CONFIG_PM suspend: netdrv_suspend, resume: netdrv_resume, diff --git a/drivers/net/pcmcia/xircom_cb.c b/drivers/net/pcmcia/xircom_cb.c index 9fb35d9d0..cc15b93a4 100644 --- a/drivers/net/pcmcia/xircom_cb.c +++ b/drivers/net/pcmcia/xircom_cb.c @@ -170,7 +170,7 @@ static struct pci_driver xircom_ops = { name: "xircom_cb", id_table: xircom_pci_table, probe: xircom_probe, - remove: xircom_remove, + remove: __devexit_p(xircom_remove), }; diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index e7fe6ae79..92acf253e 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -1748,7 +1748,7 @@ static struct pci_driver xircom_driver = { name: DRV_NAME, id_table: xircom_pci_table, probe: xircom_init_one, - remove: xircom_remove_one, + remove: __devexit_p(xircom_remove_one), #ifdef CONFIG_PM suspend: xircom_suspend, resume: xircom_resume diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index e6140c6cf..f67dd3050 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2098,7 +2098,7 @@ static struct pci_driver sis900_pci_driver = { name: SIS900_MODULE_NAME, id_table: sis900_pci_tbl, probe: sis900_probe, - remove: sis900_remove, + remove: __devexit_p(sis900_remove), }; static int __init sis900_init_module(void) diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 0fec2bcce..ff1332e88 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1963,7 +1963,7 @@ static void __devexit starfire_remove_one (struct pci_dev *pdev) static struct pci_driver starfire_driver = { name: DRV_NAME, probe: starfire_init_one, - remove: starfire_remove_one, + remove: __devexit_p(starfire_remove_one), id_table: starfire_pci_tbl, }; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index ab376ffed..7c55c0921 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1474,7 +1474,7 @@ static struct pci_driver sundance_driver = { name: DRV_NAME, id_table: sundance_pci_tbl, probe: sundance_probe1, - remove: sundance_remove1, + remove: __devexit_p(sundance_remove1), }; static int __init sundance_init(void) diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index f7858a63c..f712f7ae1 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1,4 +1,4 @@ -/* $Id: sungem.c,v 1.43 2001-12-05 08:40:54 davem Exp $ +/* $Id: sungem.c,v 1.44 2001-12-08 04:06:27 davem Exp $ * sungem.c: Sun GEM ethernet driver. * * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) @@ -2859,7 +2859,7 @@ static struct pci_driver gem_driver = { name: GEM_MODULE_NAME, id_table: gem_pci_tbl, probe: gem_init_one, - remove: gem_remove_one, + remove: __devexit_p(gem_remove_one), #ifdef CONFIG_PM suspend: gem_suspend, resume: gem_resume, diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 57632c10e..6290b6b5e 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -430,7 +430,7 @@ static struct pci_driver tlan_driver = { name: "tlan", id_table: tlan_pci_tbl, probe: tlan_init_one, - remove: tlan_remove_one, + remove: __devexit_p(tlan_remove_one), }; static int __init tlan_probe(void) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index bbae0d622..32a11e49b 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1812,7 +1812,7 @@ static struct pci_driver streamer_pci_driver = { name: "lanstreamer", id_table: streamer_pci_tbl, probe: streamer_init_one, - remove: streamer_remove_one, + remove: __devexit_p(streamer_remove_one), }; static int __init streamer_init_module(void) { diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index ec2cc2346..e1863ed9b 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1705,7 +1705,7 @@ static struct pci_driver olympic_driver = { name: "olympic", id_table: olympic_pci_tbl, probe: olympic_probe, - remove: olympic_remove_one + remove: __devexit_p(olympic_remove_one), }; static int __init olympic_pci_init(void) diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index f67ff1373..601046c8e 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1889,7 +1889,7 @@ static struct pci_driver tulip_driver = { name: DRV_NAME, id_table: tulip_pci_tbl, probe: tulip_init_one, - remove: tulip_remove_one, + remove: __devexit_p(tulip_remove_one), #ifdef CONFIG_PM suspend: tulip_suspend, resume: tulip_resume, diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 2e753ad17..e956ead13 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1667,7 +1667,7 @@ static struct pci_driver via_rhine_driver = { name: "via-rhine", id_table: via_rhine_pci_tbl, probe: via_rhine_init_one, - remove: via_rhine_remove_one, + remove: __devexit_p(via_rhine_remove_one), }; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 031506a5c..64258f647 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -1810,7 +1810,7 @@ static struct pci_driver fst_driver = { name: FST_NAME, id_table: fst_pci_dev_id, probe: fst_add_one, - remove: fst_remove_one, + remove: __devexit_p(fst_remove_one), suspend: NULL, resume: NULL, }; diff --git a/drivers/net/winbond-840.c b/drivers/net/winbond-840.c index f81fc206f..a28cbf9c8 100644 --- a/drivers/net/winbond-840.c +++ b/drivers/net/winbond-840.c @@ -1697,7 +1697,7 @@ static struct pci_driver w840_driver = { name: DRV_NAME, id_table: w840_pci_tbl, probe: w840_probe1, - remove: w840_remove1, + remove: __devexit_p(w840_remove1), #ifdef CONFIG_PM suspend: w840_suspend, resume: w840_resume, diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 458cb73a1..2c4e856e7 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -64,7 +64,7 @@ static struct pci_driver airo_driver = { name: "airo", id_table: card_ids, probe: airo_pci_probe, - remove: airo_pci_remove, + remove: __devexit_p(airo_pci_remove), }; #endif /* CONFIG_PCI */ diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 751a1e733..9c84936c4 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c @@ -279,7 +279,7 @@ static struct pci_driver orinoco_plx_driver = { name:"orinoco_plx", id_table:orinoco_plx_pci_id_table, probe:orinoco_plx_init_one, - remove:orinoco_plx_remove_one, + remove:__devexit_p(orinoco_plx_remove_one), suspend:0, resume:0 }; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index e169ad56f..6cd976b85 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1506,7 +1506,7 @@ static struct pci_driver yellowfin_driver = { name: DRV_NAME, id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, - remove: yellowfin_remove_one, + remove: __devexit_p(yellowfin_remove_one), }; diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index 129450bf6..4411d2a1d 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,3 +1,27 @@ +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * ieee1284_ops.c (parport_ieee1284_epp_write_addr, + parport_ieee1284_epp_read_addr): Actually do something useful. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * parport_pc.c (dmaval): Don't use DMA by default. It seems to be + too buggy at the moment. Use 'dma=auto' to restore the previous + behaviour. + +2001-12-03 Rich Liu <Rich.Liu@ite.com.tw> + + * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port + serial board, not a serial+parallel. + +2001-11-30 Neils Kristian Bech Jensen <nkbj@image.dk> + + * parport_pc.c: Fix compiler warning. + +2001-12-07 Tim Waugh <twaugh@redhat.com> + + * daisy.c (DEBUG): Undefine. + 2001-12-06 Tim Waugh <twaugh@redhat.com> * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 573c5ef20..b9ba843b9 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -23,7 +23,7 @@ #include <linux/delay.h> #include <asm/uaccess.h> -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef DEBUG #define DPRINTK(stuff...) printk (stuff) diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 8fcd6f2f1..aee6e0065 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -824,35 +824,40 @@ size_t parport_ieee1284_epp_write_addr (struct parport *port, const void *buffer, size_t len, int flags) { - /* This is untested */ unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; + /* set EPP idle state (just to make sure) with strobe low */ parport_frob_control (port, PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT | - PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_INIT, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_INIT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { - /* Write data and assert nAStrb. */ + /* Event 56: Write data and set nAStrb low. */ parport_write_data (port, *bp); parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for busy (nWait) to go high */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; + /* Event 59: set nAStrb high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for busy (nWait) to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; } + /* Event 61: set strobe (nWrite) high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); return ret; @@ -863,28 +868,36 @@ size_t parport_ieee1284_epp_read_addr (struct parport *port, void *buffer, size_t len, int flags) { - /* This is untested. */ unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; + /* Set EPP idle state (just to make sure) with strobe high */ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD, 0); + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + /* Event 64: set nSelectIn (nAStrb) low */ + parport_frob_control (port, PARPORT_CONTROL_SELECT, + PARPORT_CONTROL_SELECT); - /* Event 58 */ - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* Event 58: wait for Busy to go high */ + if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { break; + } *bp = parport_read_data (port); + /* Event 59: set nSelectIn (nAStrb) high */ parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for Busy to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) break; ret++; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 0c5c82a3b..6973a2f64 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -91,7 +91,9 @@ static struct superio_struct { /* For Super-IO chips autodetection */ } superios[NR_SUPERIOS] __devinitdata = { {0,},}; static int user_specified __devinitdata = 0; +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) static int verbose_probing; +#endif static int registered_parport; /* frob_control, but for ECR */ @@ -1780,6 +1782,7 @@ static int __devinit parport_PS2_supported(struct parport *pb) return ok; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { int i; @@ -1905,6 +1908,7 @@ static int __devinit parport_ECP_supported(struct parport *pb) return 1; } +#endif static int __devinit parport_ECPPS2_supported(struct parport *pb) { @@ -2004,7 +2008,9 @@ static int __devinit parport_ECPEPP_supported(struct parport *pb) /* Don't bother probing for modes we know we won't use. */ static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +#ifdef CONFIG_PARPORT_PC_FIFO static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +#endif static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} @@ -2453,9 +2459,8 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, ite8872set = 0x64e00000; break; case 0x6: - printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n"); - ite8872set = 0x64a00000; - break; + printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n"); + return 0; case 0x8: DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n"); return 0; @@ -3007,7 +3012,7 @@ EXPORT_SYMBOL (parport_pc_unregister_port); static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO }; -static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; +static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE }; static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY }; static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, }; static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, }; @@ -3024,8 +3029,10 @@ MODULE_PARM_DESC(irq, "IRQ line"); MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); MODULE_PARM_DESC(dma, "DMA channel"); MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s"); -MODULE_PARM(verbose_probing, "i"); +#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO) MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); +MODULE_PARM(verbose_probing, "i"); +#endif int init_module(void) { diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 6eb80f07f..52649275c 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -331,7 +331,7 @@ static struct pci_driver parport_serial_pci_driver = { name: "parport_serial", id_table: parport_serial_pci_tbl, probe: parport_serial_pci_probe, - remove: parport_serial_pci_remove, + remove: __devexit_p(parport_serial_pci_remove), }; diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c index 7c6615a64..d30df9b42 100644 --- a/drivers/pcmcia/pci_socket.c +++ b/drivers/pcmcia/pci_socket.c @@ -249,7 +249,7 @@ static struct pci_driver pci_cardbus_driver = { name: "cardbus", id_table: cardbus_table, probe: cardbus_probe, - remove: cardbus_remove, + remove: __devexit_p(cardbus_remove), suspend: cardbus_suspend, resume: cardbus_resume, }; diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index d22ba8bae..9519d2c6d 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -107,17 +107,21 @@ static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ }; static struct resource *resource_parent(unsigned long b, unsigned long n, int flags, struct pci_dev *dev) { - struct resource res; - - if (dev == NULL) { - if (flags & IORESOURCE_MEM) - return &iomem_resource; - return &ioport_resource; +#ifdef CONFIG_PCI + struct resource res, *pr; + + if (dev != NULL) { + res.start = b; + res.end = b + n - 1; + res.flags = flags; + pr = pci_find_parent_resource(dev, &res); + if (pr) + return pr; } - res.start = b; - res.end = b + n - 1; - res.flags = flags; - return pci_find_parent_resource(dev, &res); +#endif /* CONFIG_PCI */ + if (flags & IORESOURCE_MEM) + return &iomem_resource; + return &ioport_resource; } static inline int check_io_resource(unsigned long b, unsigned long n, diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 2f7a1d721..eab889e86 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -83,8 +83,6 @@ * basically, transfer size needs to be reduced by one * and the last byte read as is done with PSEUDO_DMA. * - * 3. Test USLEEP code - * * 4. Test SCSI-II tagged queueing (I have no devices which support * tagged queueing) * @@ -110,6 +108,12 @@ #define READ_OVERRUNS #endif +#ifdef BOARD_REQUIRES_NO_DELAY +#define io_recovery_delay(x) +#else +#define io_recovery_delay(x) udelay(x) +#endif + /* * Design * Issues : @@ -192,9 +196,8 @@ * phase goes through the various phases as instructed by the target. * if the target goes into MSG IN and sends a DISCONNECT message, * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. + * queue, and NCR5380_main tries to find more work. If the target is + * idle for too long, the system will try to sleep. * * If a command has disconnected, eventually an interrupt will trigger, * calling NCR5380_intr() which will in turn call NCR5380_reselect @@ -244,21 +247,14 @@ * rely on phase mismatch and EOP interrupts to determine end * of phase. * - * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible - * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You * only really want to use this if you're having a problem with * dropped characters during high speed communications, and even * then, you're going to be better off twiddling with transfersize * in the high level code. * - * USLEEP - if defined, on devices that aren't disconnecting from the - * bus, we will go to sleep so that the CPU can get real work done - * when we run a command that won't complete immediately. - * - * Defaults for these will be provided if USLEEP is defined, although - * the user may want to adjust these to allocate CPU resources to - * the SCSI driver or "real" code. + * Defaults for these will be provided although the user may want to adjust + * these to allocate CPU resources to the SCSI driver or "real" code. * * USLEEP_SLEEP - amount of time, in jiffies, to sleep * @@ -322,18 +318,13 @@ static int do_abort(struct Scsi_Host *host); static void do_reset(struct Scsi_Host *host); static struct Scsi_Host *first_instance = NULL; static Scsi_Host_Template *the_template = NULL; - -#ifdef USLEEP -struct timer_list usleep_timer; -#endif +static struct timer_list usleep_timer; /* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) - * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. + * initialize_SCp - init the scsi pointer field + * @cmd: command block to set up * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + * Set up the internal fields in the SCSI command. */ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) @@ -362,46 +353,49 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) static struct { unsigned char mask; const char *name; -} signals[] = { { - -SR_DBP, "PARITY"}, { -SR_RST, "RST"}, { -SR_BSY, "BSY"}, { -SR_REQ, "REQ"}, { -SR_MSG, "MSG"}, { -SR_CD, "CD"}, { -SR_IO, "IO"}, { -SR_SEL, "SEL"}, { -0, NULL} -}, basrs[] = { { -BASR_ATN, "ATN"}, { -BASR_ACK, "ACK"}, { -0, NULL} -}, icrs[] = { { -ICR_ASSERT_RST, "ASSERT RST"}, { -ICR_ASSERT_ACK, "ASSERT ACK"}, { -ICR_ASSERT_BSY, "ASSERT BSY"}, { -ICR_ASSERT_SEL, "ASSERT SEL"}, { -ICR_ASSERT_ATN, "ASSERT ATN"}, { -ICR_ASSERT_DATA, "ASSERT DATA"}, { -0, NULL} -}, mrs[] = { { -MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, { -MR_TARGET, "MODE TARGET"}, { -MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, { -MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, { -MR_MONITOR_BSY, "MODE MONITOR BSY"}, { -MR_DMA_MODE, "MODE DMA"}, { -MR_ARBITRATE, "MODE ARBITRATION"}, { -0, NULL} +} signals[] = { + {SR_DBP, "PARITY"}, + {SR_RST, "RST"}, + {SR_BSY, "BSY"}, + {SR_REQ, "REQ"}, + {SR_MSG, "MSG"}, + {SR_CD, "CD"}, + {SR_IO, "IO"}, + {SR_SEL, "SEL"}, + {0, NULL} +}, +basrs[] = { + {BASR_ATN, "ATN"}, + {BASR_ACK, "ACK"}, + {0, NULL} +}, +icrs[] = { + {ICR_ASSERT_RST, "ASSERT RST"}, + {ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, + {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, + {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL} +}, +mrs[] = { + {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, + {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, + {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, + {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL} }; -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) +/** + * NCR5380_print - print scsi bus signals + * @instance: adapter state to dump * - * Purpose : print the SCSI bus signals for debugging purposes + * Print the SCSI bus signals for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print(struct Scsi_Host *instance) @@ -410,6 +404,7 @@ static void NCR5380_print(struct Scsi_Host *instance) unsigned long flags; unsigned char status, data, basr, mr, icr, i; NCR5380_setup(instance); + /* FIXME - this needs proper locking */ save_flags(flags); cli(); data = NCR5380_read(CURRENT_SCSI_DATA_REG); @@ -441,23 +436,22 @@ static struct { unsigned char value; const char *name; } phases[] = { - - { - PHASE_DATAOUT, "DATAOUT"}, { - PHASE_DATAIN, "DATAIN"}, { - PHASE_CMDOUT, "CMDOUT"}, { - PHASE_STATIN, "STATIN"}, { - PHASE_MSGOUT, "MSGOUT"}, { - PHASE_MSGIN, "MSGIN"}, { - PHASE_UNKNOWN, "UNKNOWN"} + {PHASE_DATAOUT, "DATAOUT"}, + {PHASE_DATAIN, "DATAIN"}, + {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, + {PHASE_MSGOUT, "MSGOUT"}, + {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"} }; /* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * NCR5380_print_phase - show SCSI phase + * @instance: adapter to dump * - * Purpose : print the current SCSI phase for debugging purposes + * Print the current SCSI phase for debugging purposes * - * Input : instance - which NCR5380 + * Locks: none */ static void NCR5380_print_phase(struct Scsi_Host *instance) @@ -496,7 +490,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) * conditions are possible. */ -static volatile int main_running = 0; +static unsigned long main_running = 0; /* * Function : run_main(void) @@ -510,14 +504,10 @@ static volatile int main_running = 0; static __inline__ void run_main(void) { - if (!main_running) { - main_running = 1; + if (!test_and_set_bit(0, &main_running)) NCR5380_main(); - } } -#ifdef USLEEP - /* * These need tweaking, and would probably work best as per-device * flags initialized differently for disk, tape, cd, etc devices. @@ -587,17 +577,15 @@ static int should_disconnect(unsigned char cmd) /* * Assumes instance->time_expires has been set in higher level code. + * + * Locks: Caller must hold io_request_lock */ static int NCR5380_set_timer(struct Scsi_Host *instance) { - unsigned long flags; struct Scsi_Host *tmp, **prev; - save_flags(flags); - cli(); if (((struct NCR5380_hostdata *) (instance->hostdata))->next_timer) { - restore_flags(flags); return -1; } for (prev = &expires_first, tmp = expires_first; tmp; prev = &(((struct NCR5380_hostdata *) tmp->hostdata)->next_timer), tmp = ((struct NCR5380_hostdata *) tmp->hostdata)->next_timer) @@ -608,17 +596,28 @@ static int NCR5380_set_timer(struct Scsi_Host *instance) *prev = instance; mod_timer(&usleep_timer, ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires); - restore_flags(flags); return 0; } -/* Doing something about unwanted reentrancy here might be useful */ -void NCR5380_timer_fn(unsigned long surplus_to_requirements) +/** + * NCR5380_timer_fn - handle polled timeouts + * @unused: unused + * + * Walk the list of controllers, find which controllers have exceeded + * their expiry timeout and then schedule the processing co-routine to + * do the real work. + * + * Doing something about unwanted reentrancy here might be useful + * + * Locks: disables irqs, takes and frees io_request_lock + */ + +void NCR5380_timer_fn(unsigned long unused) { - unsigned long flags; struct Scsi_Host *instance; - save_flags(flags); - cli(); + + spin_lock_irq(&io_request_lock); + for (; expires_first && time_before_eq(((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires, jiffies);) { instance = ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer; ((struct NCR5380_hostdata *) expires_first->hostdata)->next_timer = NULL; @@ -631,51 +630,56 @@ void NCR5380_timer_fn(unsigned long surplus_to_requirements) usleep_timer.expires = ((struct NCR5380_hostdata *) expires_first->hostdata)->time_expires; add_timer(&usleep_timer); } - restore_flags(flags); - - spin_lock_irqsave(&io_request_lock, flags); run_main(); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_unlock_irq(&io_request_lock); } -#endif /* def USLEEP */ +/** + * NCR5380_all_init - global setup + * + * Set up the global values and timers needed by the NCR5380 driver + */ + static inline void NCR5380_all_init(void) { static int done = 0; if (!done) { -#if (NDEBUG & NDEBUG_INIT) - printk("scsi : NCR5380_all_init()\n"); -#endif + dprintk(NDEBUG_INIT, ("scsi : NCR5380_all_init()\n")); done = 1; -#ifdef USLEEP init_timer(&usleep_timer); usleep_timer.function = NCR5380_timer_fn; -#endif } } -#ifdef AUTOPROBE_IRQ -/* - * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) - * - * Purpose : autoprobe for the IRQ line used by the NCR5380. - * - * Inputs : instance - pointer to this instance of the NCR5380 driver, - * possible - bitmask of permissible interrupts. - * - * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired. - * - * XXX no effort is made to deal with spurious interrupts. - */ - static int probe_irq __initdata = 0; +/** + * probe_intr - helper for IRQ autoprobe + * @irq: interrupt number + * @dev_id: unused + * @regs: unused + * + * Set a flag to indicate the IRQ in question was received. This is + * used by the IRQ probe code. + */ + static void __init probe_intr(int irq, void *dev_id, struct pt_regs *regs) { probe_irq = irq; } +/** + * NCR5380_probe_irq - find the IRQ of an NCR5380 + * @instance: NCR5380 controller + * @possible: bitmask of ISA IRQ lines + * + * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ + * and then looking to see what interrupt actually turned up. + * + * Locks: none, irqs must be enabled on entry + */ + static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) { NCR5380_local_declare(); @@ -685,22 +689,21 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) NCR5380_setup(instance); for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) - == 0)) + if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0)) trying_irqs |= mask; timeout = jiffies + (250 * HZ / 1000); probe_irq = IRQ_NONE; -/* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ + /* + * A interrupt is triggered whenever BSY = false, SEL = true + * and a bit set in the SELECT_ENABLE_REG is asserted on the + * SCSI bus. + * + * Note that the bus is only driven when the phase control signals + * (I/O, C/D, and MSG) match those in the TCR, so we must reset that + * to zero. + */ NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); @@ -719,15 +722,16 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) return probe_irq; } -#endif /* AUTOPROBE_IRQ */ -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) +/** + * NCR58380_print_options - show options + * @instance: unused for now * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. + * Called by probe code indicating the NCR5380 driver options that + * were selected. At some point this will switch to runtime options + * read from the adapter in question * - * Inputs : instance, pointer to this instance. Unused. + * Locks: none */ static void __init NCR5380_print_options(struct Scsi_Host *instance) @@ -754,29 +758,25 @@ static void __init NCR5380_print_options(struct Scsi_Host *instance) #ifdef PSEUDO_DMA " PSEUDO DMA" #endif -#ifdef SCSI2 - " SCSI-2" -#endif #ifdef UNSAFE " UNSAFE " #endif ); -#ifdef USLEEP printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); -#endif printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); } } -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) +/** + * NCR5380_print_status - dump controller info + * @instance: controller to dump * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. + * Print commands in the various queues, called from NCR5380_abort + * and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Locks: called functions disable irqs, missing queue lock in proc call */ static void NCR5380_print_status(struct Scsi_Host *instance) @@ -787,10 +787,8 @@ static void NCR5380_print_status(struct Scsi_Host *instance) printk("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); -#ifdef NDEBUG - NCR5380_print(instance); - NCR5380_print_phase(instance); -#endif + NCR5380_dprint(NDEBUG_ANY, instance); + NCR5380_dprint_phase(NDEBUG_ANY, instance); len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); pr_bfr[len] = 0; @@ -825,7 +823,6 @@ static #endif int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { - unsigned long flags; char *pos = buffer; struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; @@ -874,8 +871,7 @@ int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int #ifdef PAS16_PUBLIC_RELEASE SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); #endif - save_flags(flags); - cli(); + spin_lock_irq(&io_request_lock); SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); if (!hostdata->connected) SPRINTF("scsi%d: no currently connected command\n", instance->host_no); @@ -889,7 +885,8 @@ int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - restore_flags(flags); + spin_unlock_irq(&io_request_lock); + *start = buffer; if (pos - buffer < offset) return 0; @@ -926,17 +923,18 @@ char *lprint_opcode(int opcode, char *pos, char *buffer, int length) } -/* - * Function : void NCR5380_init (struct Scsi_Host *instance, flags) +/** + * NCR5380_init - initialise an NCR5380 + * @instance: adapter to configure + * @flags: control flags * - * Purpose : initializes *instance and corresponding 5380 chip, + * Initializes *instance and corresponding 5380 chip, * with flags OR'd into the initial flags value. * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been + * Notes : I assume that the host, hostno, and id bits have been * set correctly. I don't care about the irq and other fields. - * + * + * Locks: interrupts must be enabled when we are called */ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) @@ -946,6 +944,8 @@ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) unsigned long timeout; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + if(in_interrupt()) + printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); /* * On NCR53C400 boards, NCR5380 registers are mapped 8 past * the base address. @@ -957,7 +957,6 @@ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) #endif NCR5380_setup(instance); - NCR5380_all_init(); hostdata->aborted = 0; @@ -996,15 +995,13 @@ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) the_template = instance->hostt; first_instance = instance; } -#ifdef USLEEP hostdata->time_expires = 0; hostdata->next_timer = NULL; -#endif #ifndef AUTOSENSE if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) - ) - printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" " be incorrectly cleared.\n", instance->host_no); + printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", instance->host_no); #endif /* def AUTOSENSE */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -1053,22 +1050,17 @@ static void __init NCR5380_init(struct Scsi_Host *instance, int flags) } } -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) +/** + * NCR5380_queue_command - queue a command + * @cmd: SCSI command + * @done: completion handler * - * Purpose : enqueues a SCSI command - * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 - * - * Side effects : * cmd is added to the per instance issue_queue, with minor * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * + * Locks: io_request lock held by caller. Called functions drop and + * retake this lock. Called functions take dma lock. */ /* Only make static if a wrapper function is used */ @@ -1092,15 +1084,7 @@ int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ #ifdef NCR5380_STATS -#if 0 - if (!hostdata->connected && !hostdata->issue_queue && !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -#endif -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -#endif - switch (cmd->cmnd[0]) { + switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: @@ -1115,7 +1099,7 @@ int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { hostdata->bytes_read[cmd->target] += cmd->request_bufflen; hostdata->pendingr++; break; - } + } #endif /* @@ -1125,10 +1109,8 @@ int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { cmd->host_scribble = NULL; cmd->scsi_done = done; - cmd->result = 0; - /* * Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will @@ -1145,25 +1127,24 @@ int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { LIST(cmd, tmp); tmp->host_scribble = (unsigned char *) cmd; } -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); -/* Run the coroutine if it isn't already running. */ + /* Run the coroutine if it isn't already running. */ run_main(); return 0; } -/* - * Function : NCR5380_main (void) +/** + * NCR5380_main - NCR state machines * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * NCR5380_main is a coroutine that runs as long as more work can * be done on the NCR5380 host adapters in a system. Both * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. + * Locks; The caller must hold the io_request_lock. The lock will still be + * held on return but may be dropped while running. Called functions take + * the DMA lock. */ static void NCR5380_main(void) { @@ -1171,7 +1152,6 @@ static void NCR5380_main(void) { struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; int done; - unsigned long flags; /* * We run (with interrupts disabled) until we're sure that none of @@ -1185,40 +1165,22 @@ static void NCR5380_main(void) { * this should prevent any race conditions. */ - spin_unlock_irq(&io_request_lock); - - save_flags(flags); - do { - cli(); /* Freeze request queues */ + /* Lock held here */ done = 1; for (instance = first_instance; instance && instance->hostt == the_template; instance = instance->next) { hostdata = (struct NCR5380_hostdata *) instance->hostdata; - cli(); -#ifdef USLEEP + /* Lock held here */ if (!hostdata->connected && !hostdata->selecting) { -#else - if (!hostdata->connected) { -#endif -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : not connected\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); /* * Search through the issue_queue for a command destined * for a target that's not busy. */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); - /*printk("%p ", tmp); */ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); /* else printk("\n"); */ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) { - -#if (NDEBUG & NDEBUG_LISTS) + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + { if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); -#endif + dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); /* When we find one, remove it from the issue queue. */ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { if (prev) { @@ -1230,8 +1192,6 @@ static void NCR5380_main(void) { } tmp->host_scribble = NULL; - /* reenable interrupts after finding one */ - restore_flags(flags); /* * Attempt to establish an I_T_L nexus here. @@ -1239,9 +1199,7 @@ static void NCR5380_main(void) { * On failure, we must add the command back to the * issue queue so we can keep trying. */ -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); /* * A successful selection is defined as one that @@ -1253,10 +1211,8 @@ static void NCR5380_main(void) { * and see if we can do an information transfer, * with failures we will restart. */ -#ifdef USLEEP - hostdata->selecting = 0; /* RvC: have to preset this - to indicate a new command is being performed */ -#endif + hostdata->selecting = 0; + /* RvC: have to preset this to indicate a new command is being performed */ if (!NCR5380_select(instance, tmp, /* @@ -1268,23 +1224,20 @@ static void NCR5380_main(void) { (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { break; } else { - cli(); LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) - hostdata->issue_queue; + tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; done = 0; - restore_flags(flags); -#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no)); } + /* lock held here still */ } /* if target/lun is not busy */ } /* for */ + /* exited locked */ } /* if (!hostdata->connected) */ -#ifdef USLEEP if (hostdata->selecting) { tmp = (Scsi_Cmnd *) hostdata->selecting; + /* Selection will drop and retake the lock */ if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { /* Ok ?? */ } else { @@ -1293,56 +1246,46 @@ static void NCR5380_main(void) { do not respond to commands immediately after a scan */ printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target); - cli(); + //spin_lock_irq(&io_request_lock); LIST(tmp, hostdata->issue_queue); tmp->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = tmp; - restore_flags(flags); + //spin_unlock_irq(&io_request_lock); hostdata->time_expires = jiffies + USLEEP_WAITLONG; NCR5380_set_timer(instance); } } /* if hostdata->selecting */ -#endif if (hostdata->connected #ifdef REAL_DMA && !hostdata->dmalen #endif -#ifdef USLEEP && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) -#endif ) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : performing information transfer\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no)); NCR5380_information_transfer(instance); -#if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : done set false\n", instance->host_no); -#endif + dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no)); done = 0; } else break; } /* for instance */ } while (!done); - spin_lock_irq(&io_request_lock); - /* cli(); */ - main_running = 0; + /* Exit lock held */ + clear_bit(0, &main_running); } #ifndef DONT_USE_INTR #include <linux/blk.h> #include <linux/spinlock.h> -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses +/** + * NCR5380_intr - generic NCR5380 irq handler + * + * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses * from the disconnected queue, and restarting NCR5380_main() * as required. * - * Inputs : int irq, irq that caused this interrupt. - * + * Locks: caller must hold the io_request lock. */ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { @@ -1350,13 +1293,9 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { struct Scsi_Host *instance; int done; unsigned char basr; - unsigned long flags; - save_flags(flags); - cli(); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : NCR5380 irq %d triggered\n", irq); -#endif + dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); + do { done = 1; for (instance = first_instance; instance && (instance->hostt == the_template); instance = instance->next) @@ -1367,33 +1306,19 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { basr = NCR5380_read(BUS_AND_STATUS_REG); /* XXX dispatch to appropriate routine if found and done=0 */ if (basr & BASR_IRQ) { -#if (NDEBUG & NDEBUG_INTR) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_INTR, instance); if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { done = 0; - restore_flags(flags); -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : SEL interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no)); NCR5380_reselect(instance); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if (basr & BASR_PARITY_ERROR) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : PARITY interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { -#if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : RESET interrupt\n", instance->host_no); -#endif + dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { -/* - * XXX the rest of the interrupt conditions should *only* occur during a - * DMA transfer, which I haven't gotten around to fixing yet. - */ - #if defined(REAL_DMA) /* * We should only get PHASE MISMATCH and EOP interrupts @@ -1424,7 +1349,7 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { if (time_after_eq(jiffies, timeout)) printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__); } -#else /* NCR_TIMEOUT */ +#else /* NCR_TIMEOUT */ while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); #endif @@ -1432,9 +1357,7 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); } #else -#if (NDEBUG & NDEBUG_INTR) - printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG))); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #endif } @@ -1445,6 +1368,17 @@ static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { } while (!done); } +/** + * do_NCR5380_intr + * @irq: interrupt number + * @dev_id: device info + * @regs: registers (unused) + * + * Takes the io_request_lock and invokes the generic NCR5380 interrupt + * handler code + * + * Locks: takes and releases the io_request lock + */ static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; @@ -1454,26 +1388,37 @@ static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { spin_unlock_irqrestore(&io_request_lock, flags); } #endif + + +/** + * collect_stats - collect stats on a scsi command + * @hostdata: adapter + * @cmd: command being issued + * + * Update the statistical data by parsing the command in question + */ + +static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) +{ #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { -#ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + hostdata->pendingr--; + break; + } #endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingw--; - break; - case READ:case READ_6:case READ_10:hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ - hostdata->pendingr--; - break; - } } -#endif + + /* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); @@ -1503,34 +1448,30 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { * * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. - */ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { + * + * Locks: caller holds io_request_lock + */ + +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) +{ NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; unsigned char tmp[3], phase; unsigned char *data; int len; unsigned long timeout; - unsigned long flags; -#ifdef USLEEP unsigned char value; -#endif - - NCR5380_setup(instance); - -#ifdef USLEEP + NCR5380_setup(instance); if (hostdata->selecting) { goto part2; /* RvC: sorry prof. Dijkstra, but it keeps the rest of the code nearly the same */ } -#endif + hostdata->restart_select = 0; -#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) - NCR5380_print(instance); - printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id); -#endif - save_flags(flags); - cli(); + + NCR5380_dprint(NDEBUG_ARBITRATION, instance); + dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id)); /* * Set the phase bits to 0, otherwise the NCR5380 won't drive the @@ -1539,7 +1480,6 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { NCR5380_write(TARGET_COMMAND_REG, 0); - /* * Start arbitration. */ @@ -1547,8 +1487,6 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); NCR5380_write(MODE_REG, MR_ARBITRATE); - restore_flags(flags); - /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT { @@ -1572,11 +1510,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); #endif -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : arbitration complete\n", instance->host_no); -/* Avoid GCC 2.4.5 asm needs to many reloads error */ - __asm__("nop"); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no)); /* * The arbitration delay is 2.2us, but this is a minimum and there is @@ -1590,9 +1524,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { /* Check for lost arbitration */ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no)); return -1; } NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); @@ -1605,9 +1537,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no); -#endif + dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no)); return -1; } /* @@ -1617,10 +1547,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { udelay(2); -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : won arbitration\n", instance->host_no); -#endif - + dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no)); /* * Now that we have won arbitration, start Selection process, asserting @@ -1672,9 +1599,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { udelay(1); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->target)); /* * The SCSI specification calls for a 250 ms timeout for the actual @@ -1689,11 +1614,10 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { * and it's detecting as true. Sigh. */ -#ifdef USLEEP hostdata->select_time = 0; /* we count the clock ticks at which we polled */ hostdata->selecting = cmd; - part2: +part2: /* RvC: here we enter after a sleeping period, or immediately after execution of part 1 we poll only once ech clock tick */ @@ -1710,11 +1634,6 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { hostdata->selecting = 0; /* clear this pointer, because we passed the waiting period */ -#else - spin_unlock_irq(&io_request_lock); - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))); - spin_lock_irq(&io_request_lock); -#endif if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); @@ -1738,21 +1657,15 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { printk("scsi%d : weirdness\n", instance->host_no); if (hostdata->restart_select) printk("\trestart select\n"); -#if (NDEBUG & NDEBUG_SELECTION) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_SELECTION, instance); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return -1; } cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target did not respond within 250ms\n", instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no)); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return 0; } @@ -1792,46 +1705,20 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { while (!(NCR5380_read(STATUS_REG) & SR_REQ)); #endif /* def NCR_TIMEOUT */ -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target)); tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); -#ifdef SCSI2 - if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) - cmd->device->current_tag = 1; - - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - } else - cmd->tag = (unsigned char) tag; - - tmp[2] = cmd->tag; - hostdata->last_message = SIMPLE_QUEUE_TAG; - len = 3; - } else -#endif /* def SCSI2 */ - { - len = 1; - cmd->tag = 0; - } + + len = 1; + cmd->tag = 0; /* Send message(s) */ data = tmp; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : nexus established.\n", instance->host_no); -#endif + dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no)); /* XXX need to handle errors here */ hostdata->connected = cmd; -#ifdef SCSI2 - if (!cmd->device->tagged_queue) -#endif - hostdata->busy[cmd->target] |= (1 << cmd->lun); + hostdata->busy[cmd->target] |= (1 << cmd->lun); initialize_SCp(cmd); @@ -1866,24 +1753,20 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { NCR5380_local_declare(); - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; -#ifdef USLEEP + unsigned char p = *phase, tmp; + int c = *count; + unsigned char *d = *data; /* * RvC: some administrative data to process polling time */ int break_allowed = 0; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; -#endif - NCR5380_setup(instance); + NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_PIO) if (!(p & SR_IO)) - printk("scsi%d : pio write %d bytes\n", instance->host_no, c); + dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c)); else - printk("scsi%d : pio read %d bytes\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c)); /* * The NCR5380 chip will only drive the SCSI bus when the @@ -1893,21 +1776,18 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); -#ifdef USLEEP /* RvC: don't know if this is necessary, but other SCSI I/O is short * so breaks are not necessary there */ if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { break_allowed = 1; } -#endif do { /* * Wait for assertion of REQ, after which the phase bits will be * valid */ -#ifdef USLEEP /* RvC: we simply poll once, after that we stop temporarily * and let the device buffer fill up * if breaking is not allowed, we keep polling as long as needed @@ -1920,20 +1800,13 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase NCR5380_set_timer(instance); break; } -#else - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); -#endif -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : REQ detected\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no)); /* Check for phase mismatch */ if ((tmp & PHASE_MASK) != p) { -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : phase mismatch\n", instance->host_no); - NCR5380_print_phase(instance); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no)); + NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance); break; } /* Do actual transfer from SCSI bus to / from memory */ @@ -1954,29 +1827,21 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase if (!(p & SR_IO)) { if (!((p & SR_MSG) && c > 1)) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); } else { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); } } else { -#if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_PIO, instance); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); } while (NCR5380_read(STATUS_REG) & SR_REQ); -#if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : req false, handshake complete\n", instance->host_no); -#endif + dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no)); /* * We have several special cases to consider during REQ/ACK handshaking : @@ -1997,9 +1862,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase } } while (--c); -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : residual %d\n", instance->host_no, c); -#endif + dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c)); *count = c; *data = d; @@ -2015,35 +1878,46 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase return -1; } +/** + * do_reset - issue a reset command + * @host: adapter to reset + * + * Issue a reset sequence to the NCR5380 and try and get the bus + * back into sane shape. + * + * Locks: caller holds io_request lock + */ + static void do_reset(struct Scsi_Host *host) { - unsigned long flags; - NCR5380_local_declare(); - NCR5380_setup(host); - - save_flags(flags); - cli(); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - restore_flags(flags); -} /* - - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ static int do_abort(struct Scsi_Host *host) { + NCR5380_local_declare(); + NCR5380_setup(host); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(25); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +} + +/* + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + * + * Locks: io_request lock held by caller + */ + +static int do_abort(struct Scsi_Host *host) { NCR5380_local_declare(); unsigned char tmp, *msgptr, phase; int len; - NCR5380_setup(host); + NCR5380_setup(host); /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); /* * Wait for the target to indicate a valid phase by asserting @@ -2057,7 +1931,7 @@ static void do_reset(struct Scsi_Host *host) { while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); @@ -2096,6 +1970,7 @@ static void do_reset(struct Scsi_Host *host) { * * Also, *phase, *count, *data are modified in place. * + * Locks: io_request lock held by caller */ @@ -2105,19 +1980,15 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase register unsigned char p = *phase; register unsigned char *d = *data; unsigned char tmp; -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - unsigned long flags; -#endif int foo; #if defined(REAL_DMA_POLL) int cnt, toPIO; unsigned char saved_data = 0, overrun = 0, residue; #endif - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - NCR5380_setup(instance); + NCR5380_setup(instance); if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { *phase = tmp; @@ -2129,9 +2000,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase c -= 2; } #endif -#if (NDEBUG & NDEBUG_DMA) - printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d)); hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); #endif @@ -2148,9 +2017,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase * before the setting of DMA mode to after transfer of the last byte. */ -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - save_flags(flags); - cli(); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_unlock_irq(&io_request_lock); #endif /* KLL May need eop and parity in 53c400 */ if (hostdata->flags & FLAG_NCR53C400) @@ -2159,36 +2027,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #endif /* def REAL_DMA */ -#if (NDEBUG & NDEBUG_DMA) & 0 - printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG))); -/* - * FOO stuff. For some UNAPPARENT reason, I'm getting - * watchdog timers fired on bootup for NO APPARENT REASON, meaning it's - * probably a timing problem. - * - * Since this is the only place I have back-to-back writes, perhaps this - * is the problem? - */ + /* + * On the PAS16 at least I/O recovery delays are not needed here. + * Everyone else seems to want them. + */ if (p & SR_IO) { -#ifndef FOO - udelay(1); -#endif + io_recovery_delay(1); NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); } else { -#ifndef FOO - udelay(1); -#endif + io_recovery_delay(1); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); -#ifndef FOO - udelay(1); -#endif + io_recovery_delay(1); NCR5380_write(START_DMA_SEND_REG, 0); -#ifndef FOO - udelay(1); -#endif + io_recovery_delay(1); } #if defined(REAL_DMA_POLL) @@ -2250,10 +2104,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase } } - -#if (NDEBUG & NDEBUG_DMA) - printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG))); NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); @@ -2267,9 +2118,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase #ifdef READ_OVERRUNS if (*phase == p && (p & SR_IO) && residue == 0) { if (overrun) { -#if (NDEBUG & NDEBUG_DMA) - printk("Got an input overrun, using saved byte\n"); -#endif + dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n")); **data = saved_data; *data += 1; *count -= 1; @@ -2278,17 +2127,13 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase printk("No overrun??\n"); cnt = toPIO = 2; } -#if (NDEBUG & NDEBUG_DMA) - printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); -#endif + dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data)); NCR5380_transfer_pio(instance, phase, &cnt, data); *count -= toPIO - cnt; } #endif -#if (NDEBUG & NDEBUG_DMA) - printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count)); -#endif + dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count))); return 0; #elif defined(REAL_DMA) @@ -2338,9 +2183,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase foo = NCR5380_pwrite(instance, d, c); #else int timeout; -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("About to pwrite %d bytes\n", c); -#endif + dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c)); if (!(foo = NCR5380_pwrite(instance, d, c))) { /* * Wait for the last byte to be sent. If REQ is being asserted for @@ -2350,30 +2193,20 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase timeout = 20000; while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)); - -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) if (!timeout) - printk("scsi%d : timed out on last byte\n", instance->host_no); -#endif - + dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no)); if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; -#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - printk("scsi%d : last bit sent works\n", instance->host_no); -#endif + dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no)); } } } else { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Waiting for LASTBYTE\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n")); while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Got LASTBYTE\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n")); } } #endif @@ -2382,13 +2215,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Checking for IRQ\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n")); if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { -#if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got it, reading reset interrupt reg\n"); -#endif + dprintk(NDEBUG_C400_PWRITE, ("53C400w: got it, reading reset interrupt reg\n")); NCR5380_read(RESET_PARITY_INTERRUPT_REG); } else { printk("53C400w: IRQ NOT THERE!\n"); @@ -2397,11 +2226,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase *data = d + c; *count = 0; *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; -#if 0 - NCR5380_print_phase(instance); -#endif -#if defined(PSEUDO_DMA) && !defined(UNSAFE) - restore_flags(flags); +#if defined(PSEUDO_DMA) && defined(UNSAFE) + spin_lock_irq(&io_request_lock); #endif /* defined(REAL_DMA_POLL) */ return foo; #endif /* def REAL_DMA */ @@ -2423,12 +2249,13 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase * * XXX Note : we need to watch for bus free or a reset condition here * to recover from an unexpected bus free condition. + * + * Locks: io_request_lock held by caller */ static void NCR5380_information_transfer(struct Scsi_Host *instance) { NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; unsigned char msgout = NOP; int sink = 0; int len; @@ -2438,12 +2265,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { unsigned char *data; unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; -#ifdef USLEEP /* RvC: we need to set the end of the polling time */ unsigned long poll_time = jiffies + USLEEP_POLL; -#endif - NCR5380_setup(instance); + NCR5380_setup(instance); while (1) { tmp = NCR5380_read(STATUS_REG); @@ -2452,9 +2277,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { phase = (tmp & PHASE_MASK); if (phase != old_phase) { old_phase = phase; -#if (NDEBUG & NDEBUG_INFORMATION) - NCR5380_print_phase(instance); -#endif + NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); } if (sink && (phase != PHASE_MSGOUT)) { NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); @@ -2486,9 +2309,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; -#if (NDEBUG & NDEBUG_INFORMATION) - printk("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual); -#endif + dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); } /* * The preferred transfer method is going to be @@ -2567,16 +2388,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { case LINKED_FLG_CMD_COMPLETE: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->target, cmd->lun)); /* * Sanity check : A linked command should only terminate with * one of these messages if there are more linked commands * available. */ - if (!cmd->next_link) { printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->target, cmd->lun); sink = 1; @@ -2587,12 +2404,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { /* The next command is still part of this process */ cmd->next_link->tag = cmd->tag; cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun); -#endif -#ifdef NCR5380_STATS + dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->target, cmd->lun)); collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); cmd = hostdata->connected; break; @@ -2603,9 +2416,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { sink = 1; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); hostdata->connected = NULL; -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->target, cmd->lun)); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); /* @@ -2631,10 +2442,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { #ifdef AUTOSENSE if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { - unsigned long flags; -#if (NDEBUG & NDEBUG_AUTOSENSE) - printk("scsi%d : performing request sense\n", instance->host_no); -#endif + dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); cmd->cmnd[0] = REQUEST_SENSE; cmd->cmnd[1] &= 0xe0; cmd->cmnd[2] = 0; @@ -2647,21 +2455,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { cmd->SCp.ptr = (char *) cmd->sense_buffer; cmd->SCp.this_residual = sizeof(cmd->sense_buffer); - save_flags(flags); - cli(); LIST(cmd, hostdata->issue_queue); cmd->host_scribble = (unsigned char *) hostdata->issue_queue; hostdata->issue_queue = (Scsi_Cmnd *) cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); } else { #endif /* def AUTOSENSE */ -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); } @@ -2689,21 +2490,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { break; } case DISCONNECT:{ - unsigned long flags; /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); cmd->device->disconnect = 1; - save_flags(flags); - cli(); LIST(cmd, hostdata->disconnected_queue); cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; hostdata->connected = NULL; hostdata->disconnected_queue = cmd; - restore_flags(flags); -#if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun); -#endif + dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->target, cmd->lun)); /* * Restore phase bits to 0 so an interrupted selection, * arbitration can resume. @@ -2715,9 +2510,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); -#if 0 - NCR5380_print_status(instance); -#endif return; } /* @@ -2751,19 +2543,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { extended_msg[0] = EXTENDED_MESSAGE; /* Accept first byte by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : receiving extended message\n", instance->host_no); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no)); len = 2; data = extended_msg + 1; phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2])); if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) { /* Accept third byte by clearing ACK */ @@ -2773,10 +2560,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { phase = PHASE_MSGIN; NCR5380_transfer_pio(instance, &phase, &len, &data); - -#if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : message received, residual %d\n", instance->host_no, len); -#endif + dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len)); switch (extended_msg[2]) { case EXTENDED_SDTR: @@ -2822,9 +2606,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS collect_stats(hostdata, cmd); -#endif cmd->scsi_done(cmd); NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; @@ -2840,16 +2622,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { * use the dma transfer function. */ NCR5380_transfer_pio(instance, &phase, &len, &data); -#ifdef USLEEP if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } -#endif /* def USLEEP */ break; case PHASE_STATIN: len = 1; @@ -2859,25 +2637,19 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { break; default: printk("scsi%d : unknown phase\n", instance->host_no); -#ifdef NDEBUG - NCR5380_print(instance); -#endif + NCR5380_dprint(NDEBUG_ALL, instance); } /* switch(phase) */ } /* if (tmp * SR_REQ) */ -#ifdef USLEEP else { /* RvC: go to sleep if polling time expired */ if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { hostdata->time_expires = jiffies + USLEEP_SLEEP; -#if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires); -#endif + dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); NCR5380_set_timer(instance); return; } } -#endif } /* while (1) */ } @@ -2890,9 +2662,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) { * * Inputs : instance - this instance of the NCR5380. * + * Locks: io_request_lock held by caller */ - static void NCR5380_reselect(struct Scsi_Host *instance) { NCR5380_local_declare(); struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) @@ -2900,28 +2672,22 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { unsigned char target_mask; unsigned char lun, phase; int len; -#ifdef SCSI2 - unsigned char tag; -#endif unsigned char msg[3]; unsigned char *data; Scsi_Cmnd *tmp = NULL, *prev; int abort = 0; - NCR5380_setup(instance); + NCR5380_setup(instance); /* * Disable arbitration, etc. since the host adapter obviously * lost, and tell an interrupted NCR5380_select() to restart. */ - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : reselect\n", instance->host_no); -#endif + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no)); /* * At this point, we have detected that our SCSI ID is on the bus, @@ -2932,10 +2698,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { * signal. */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); /* * Wait for target to go into MSGIN. @@ -2943,11 +2709,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); if (!msg[0] & 0x80) { printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no); @@ -2964,10 +2729,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { * nexuses so we can chose to do additional data transfer. */ -#ifdef SCSI2 -#error "SCSI-II tagged queueing is not supported yet" -#endif - /* * Find the command corresponding to the I_T_L or I_T_L_Q nexus we * just reestablished, and remove it from the disconnected queue. @@ -2976,9 +2737,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) -#ifdef SCSI2 - && (tag == tmp->tag) -#endif ) { if (prev) { REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); @@ -2991,11 +2749,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { break; } if (!tmp) { -#ifdef SCSI2 - printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", instance->host_no, target_mask, lun, tag); -#else printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun); -#endif /* * Since we have an established nexus that we can't do anything with, * we must abort it. @@ -3008,9 +2762,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) { do_abort(instance); } else { hostdata->connected = tmp; -#if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag); -#endif + dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag)); } } @@ -3072,10 +2824,12 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) { * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). + * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_abort @@ -3083,10 +2837,8 @@ static #endif int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_local_declare(); - unsigned long flags; struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp, **prev; printk("scsi%d : aborting command\n", instance->host_no); @@ -3099,14 +2851,10 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_print_status(instance); - save_flags(flags); - cli(); NCR5380_setup(instance); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort called\n", instance->host_no); - printk(" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no)); + dprintk(NDEBUG_ABORT, (" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG))); #if 0 /* @@ -3116,9 +2864,7 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { */ if (hostdata->connected == cmd) { -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting connected command\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no)); hostdata->aborted = 1; /* * We should perform BSY checking, and make sure we haven't slipped @@ -3145,20 +2891,15 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { * Case 2 : If the command hasn't been issued yet, we simply remove it * from the issue queue. */ -#if (NDEBUG & NDEBUG_ABORT) /* KLL */ - printk("scsi%d : abort going into loop.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no)); for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); (*prev) = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort removed command from issue queue.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3180,10 +2921,7 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { */ if (hostdata->connected) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort failed, command connected.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); return SCSI_ABORT_NOT_RUNNING; } /* @@ -3213,28 +2951,20 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { - restore_flags(flags); -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting disconnected command.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no)); if (NCR5380_select(instance, cmd, (int) cmd->tag)) return SCSI_ABORT_BUSY; - -#if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : nexus reestablished.\n", instance->host_no); -#endif + dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no)); do_abort(instance); - cli(); for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) if (cmd == tmp) { REMOVE(5, *prev, tmp, tmp->host_scribble); *prev = (Scsi_Cmnd *) tmp->host_scribble; tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; - restore_flags(flags); tmp->done(tmp); return SCSI_ABORT_SUCCESS; } @@ -3248,8 +2978,6 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { * so we won't panic, but we will notify the user in case something really * broke. */ - - restore_flags(flags); printk("scsi%d : warning : SCSI command probably completed successfully\n" " before abortion\n", instance->host_no); return SCSI_ABORT_NOT_RUNNING; } @@ -3262,6 +2990,7 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { * * Returns : SCSI_RESET_WAKEUP * + * Locks: io_request_lock held by caller */ #ifndef NCR5380_reset diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index a577589aa..c7882e224 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -55,6 +55,8 @@ #define NDEBUG_C400_PWRITE 0x200000 #define NDEBUG_LISTS 0x400000 +#define NDEBUG_ANY 0xFFFFFFFFUL + /* * The contents of the OUTPUT DATA register are asserted on the bus when * either arbitration is occurring or the phase-indicating signals ( @@ -91,10 +93,10 @@ */ #define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */ #define MR_TARGET 0x40 /* rw target mode */ -#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ +#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ #define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */ #define MR_ENABLE_EOP_INTR 0x08 /* rw enable eop interrupt */ -#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ +#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ #define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ #define MR_ARBITRATE 0x01 /* rw start arbitration */ @@ -245,36 +247,34 @@ #ifndef ASM struct NCR5380_hostdata { - NCR5380_implementation_fields; /* implementation specific */ + NCR5380_implementation_fields; /* implementation specific */ unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ - unsigned char targets_present; /* targets we have connected - to, so we can call a select - failure a retryable condition */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ + unsigned char targets_present; /* targets we have connected + to, so we can call a select + failure a retryable condition */ + volatile unsigned char busy[8]; /* index = target, bit = lun */ #if defined(REAL_DMA) || defined(REAL_DMA_POLL) - volatile int dma_len; /* requested length of DMA */ + volatile int dma_len; /* requested length of DMA */ #endif volatile unsigned char last_message; /* last message OUT */ - volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *connected; /* currently connected command */ volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile int restart_select; /* we have disconnected, - used to restart - NCR5380_select() */ - volatile unsigned aborted:1; /* flag, says aborted */ + volatile int restart_select; /* we have disconnected, + used to restart + NCR5380_select() */ + volatile unsigned aborted:1; /* flag, says aborted */ int flags; -#ifdef USLEEP - unsigned long time_expires; /* in jiffies, set prior to sleeping */ + unsigned long time_expires; /* in jiffies, set prior to sleeping */ struct Scsi_Host *next_timer; - int select_time; /* timer in select for target response */ + int select_time; /* timer in select for target response */ volatile Scsi_Cmnd *selecting; -#endif #ifdef NCR5380_STATS - unsigned timebase; /* Base for time calcs */ - long time_read[8]; /* time to do reads */ - long time_write[8]; /* time to do writes */ - unsigned long bytes_read[8]; /* bytes read */ - unsigned long bytes_write[8]; /* bytes written */ + unsigned timebase; /* Base for time calcs */ + long time_read[8]; /* time to do reads */ + long time_write[8]; /* time to do writes */ + unsigned long bytes_read[8]; /* bytes read */ + unsigned long bytes_write[8]; /* bytes written */ unsigned pendingr; unsigned pendingw; #endif @@ -283,6 +283,10 @@ struct NCR5380_hostdata { #ifdef __KERNEL__ static struct Scsi_Host *first_instance; /* linked list of 5380's */ +#define dprintk(a,b) do {} while(0) +#define NCR5380_dprint(a,b) do {} while(0) +#define NCR5380_dprint_phase(a,b) do {} while(0) + #if defined(AUTOPROBE_IRQ) static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); #endif @@ -321,10 +325,24 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase #if defined(i386) || defined(__alpha__) +/** + * NCR5380_pc_dma_setup - setup ISA DMA + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * @mode: DMA controller mode to use + * + * Program the DMA controller ready to perform an ISA DMA transfer + * on this chip. + * + * Locks: takes and releases the ISA DMA lock. + */ + static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) { unsigned limit; unsigned long bus_addr = virt_to_bus(ptr); + unsigned long flags; if (instance->dma_channel <= 3) { if (count > 65536) @@ -341,34 +359,72 @@ static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned if ((count & 1) || (bus_addr & 1)) panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); - cli(); + + flags=claim_dma_lock(); disable_dma(instance->dma_channel); clear_dma_ff(instance->dma_channel); set_dma_addr(instance->dma_channel, bus_addr); set_dma_count(instance->dma_channel, count); set_dma_mode(instance->dma_channel, mode); enable_dma(instance->dma_channel); - sti(); + release_dma_lock(flags); + return count; } +/** + * NCR5380_pc_dma_write_setup - setup ISA DMA write + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA write to the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) { return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE); } +/** + * NCR5380_pc_dma_read_setup - setup ISA DMA read + * @instance: adapter to set up + * @ptr: block to transfer (virtual address) + * @count: number of bytes to transfer + * + * Program the DMA controller ready to perform an ISA DMA read from the + * SCSI controller. + * + * Locks: called routines take and release the ISA DMA lock. + */ + static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) { return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ); } +/** + * NCR5380_pc_dma_residual - return bytes left + * @instance: adapter + * + * Reports the number of bytes left over after the DMA was terminated. + * + * Locks: takes and releases the ISA DMA lock. + */ + static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance) { - register int tmp; - cli(); + unsigned long flags; + int tmp; + + flags = claim_dma_lock(); clear_dma_ff(instance->dma_channel); tmp = get_dma_residue(instance->dma_channel); - sti(); + release_dma_lock(flags); + return tmp; } #endif /* defined(i386) || defined(__alpha__) */ diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a8745e4b1..ad5a6ba2e 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -161,6 +161,8 @@ static struct dev_info device_list[] = {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders {"DELL", "PERCRAID", "*", BLIST_FORCELUN}, {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, + {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, + {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, /* * Must be at end of list... diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index f52174182..f6ac188c9 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -40,6 +40,9 @@ dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND dep_tristate ' ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND dep_tristate ' ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI +if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then + dep_tristate ' IT8172G Sound' CONFIG_SOUND_IT8172 $CONFIG_SOUND +fi dep_tristate ' RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND if [ "$CONFIG_VISWS" = "y" ]; then diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index b9904f7a5..ac7150de1 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o +obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o ifeq ($(CONFIG_MIDI_EMU10K1),y) obj-$(CONFIG_SOUND_EMU10K1) += sound.o diff --git a/drivers/sound/btaudio.c b/drivers/sound/btaudio.c index 341fc0420..22daae685 100644 --- a/drivers/sound/btaudio.c +++ b/drivers/sound/btaudio.c @@ -1030,7 +1030,7 @@ static struct pci_driver btaudio_pci_driver = { name: "btaudio", id_table: btaudio_pci_tbl, probe: btaudio_probe, - remove: btaudio_remove, + remove: __devexit_p(btaudio_remove), }; int btaudio_init_module(void) diff --git a/drivers/sound/emu10k1/main.c b/drivers/sound/emu10k1/main.c index bc53fcfd7..69f192c8d 100644 --- a/drivers/sound/emu10k1/main.c +++ b/drivers/sound/emu10k1/main.c @@ -1127,7 +1127,7 @@ static struct pci_driver emu10k1_pci_driver = { name: "emu10k1", id_table: emu10k1_pci_tbl, probe: emu10k1_probe, - remove: emu10k1_remove, + remove: __devexit_p(emu10k1_remove), }; static int __init emu10k1_init_module(void) diff --git a/drivers/sound/ymfpci.c b/drivers/sound/ymfpci.c index 8d5de5c37..3a0ca9a70 100644 --- a/drivers/sound/ymfpci.c +++ b/drivers/sound/ymfpci.c @@ -1443,13 +1443,14 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) { struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf; + int redzone; unsigned long flags; unsigned int mask = 0; if (file->f_mode & FMODE_WRITE) poll_wait(file, &state->wpcm.dmabuf.wait, wait); - // if (file->f_mode & FMODE_READ) - // poll_wait(file, &dmabuf->wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &state->rpcm.dmabuf.wait, wait); spin_lock_irqsave(&state->unit->reg_lock, flags); if (file->f_mode & FMODE_READ) { @@ -1458,12 +1459,21 @@ static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait) mask |= POLLIN | POLLRDNORM; } if (file->f_mode & FMODE_WRITE) { + redzone = ymf_calc_lend(state->format.rate); + redzone <<= state->format.shift; + redzone *= 3; + dmabuf = &state->wpcm.dmabuf; if (dmabuf->mapped) { if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize) + /* + * Don't select unless a full fragment is available. + * Otherwise artsd does GETOSPACE, sees 0, and loops. + */ + if (dmabuf->count + redzone + dmabuf->fragsize + <= dmabuf->dmasize) mask |= POLLOUT | POLLWRNORM; } } @@ -1498,6 +1508,7 @@ static int ymf_mmap(struct file *file, struct vm_area_struct *vma) return -EAGAIN; dmabuf->mapped = 1; +/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n"); return 0; } @@ -2430,6 +2441,7 @@ static int assigned; static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent) { u16 ctrl; + unsigned long base; ymfpci_t *codec; int err; @@ -2438,6 +2450,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi printk(KERN_ERR "ymfpci: pci_enable_device failed\n"); return err; } + base = pci_resource_start(pcidev, 0); if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) { printk(KERN_ERR "ymfpci: no core\n"); @@ -2452,16 +2465,21 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi codec->pci = pcidev; pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev); - codec->reg_area_virt = ioremap(pci_resource_start(pcidev, 0), 0x8000); - if (codec->reg_area_virt == NULL) { - printk(KERN_ERR "ymfpci: unable to map registers\n"); + + if (request_mem_region(base, 0x8000, "ymfpci") == NULL) { + printk(KERN_ERR "ymfpci: unable to request mem region\n"); goto out_free; } + if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) { + printk(KERN_ERR "ymfpci: unable to map registers\n"); + goto out_release_region; + } + pci_set_master(pcidev); printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n", - (char *)ent->driver_data, pci_resource_start(pcidev, 0), pcidev->irq); + (char *)ent->driver_data, base, pcidev->irq); ymfpci_aclink_reset(pcidev); if (ymfpci_codec_ready(codec, 0, 1) < 0) @@ -2491,8 +2509,7 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi /* register /dev/dsp */ if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) { - printk(KERN_ERR "ymfpci%d: unable to register dsp\n", - codec->dev_audio); + printk(KERN_ERR "ymfpci: unable to register dsp\n"); goto out_free_irq; } @@ -2538,6 +2555,8 @@ static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_devi ymfpci_writel(codec, YDSXGR_STATUS, ~0); out_unmap: iounmap(codec->reg_area_virt); + out_release_region: + release_mem_region(pci_resource_start(pcidev, 0), 0x8000); out_free: kfree(codec); return -ENODEV; @@ -2561,6 +2580,7 @@ static void __devexit ymf_remove_one(struct pci_dev *pcidev) ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL); ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); iounmap(codec->reg_area_virt); + release_mem_region(pci_resource_start(pcidev, 0), 0x8000); #ifdef CONFIG_SOUND_YMFPCI_LEGACY if (codec->iomidi) { unload_uart401(&codec->mpu_data); @@ -2577,7 +2597,7 @@ static struct pci_driver ymfpci_driver = { name: "ymfpci", id_table: ymf_id_tbl, probe: ymf_probe_one, - remove: ymf_remove_one, + remove: __devexit_p(ymf_remove_one), suspend: ymf_suspend, resume: ymf_resume }; diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index a3556dfe7..1f19cb11a 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -2990,7 +2990,7 @@ static struct pci_driver uhci_pci_driver = { id_table: uhci_pci_ids, probe: uhci_pci_probe, - remove: uhci_pci_remove, + remove: __devexit_p(uhci_pci_remove), #ifdef CONFIG_PM suspend: uhci_pci_suspend, diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 96787e4a3..a090f1c1c 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -2860,7 +2860,7 @@ static struct pci_driver ohci_pci_driver = { id_table: &ohci_pci_ids [0], probe: ohci_pci_probe, - remove: ohci_pci_remove, + remove: __devexit_p(ohci_pci_remove), #ifdef CONFIG_PM suspend: ohci_pci_suspend, diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c index f7df53322..d753af20f 100644 --- a/drivers/usb/usb-uhci.c +++ b/drivers/usb/usb-uhci.c @@ -3070,7 +3070,7 @@ static struct pci_driver uhci_pci_driver = { id_table: &uhci_pci_ids [0], probe: uhci_pci_probe, - remove: uhci_pci_remove, + remove: __devexit_p(uhci_pci_remove), #ifdef CONFIG_PM suspend: uhci_pci_suspend, diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index d83338cc3..74553d139 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1683,7 +1683,7 @@ static struct pci_device_id cyberpro_pci_table[] __devinitdata = { static struct pci_driver cyberpro_driver = { name: "CyberPro", probe: cyberpro_probe, - remove: cyberpro_remove, + remove: __devexit_p(cyberpro_remove), suspend: cyberpro_suspend, resume: cyberpro_resume, id_table: cyberpro_pci_table diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 2030ab596..3ec9b07d6 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1643,7 +1643,7 @@ static struct pci_driver imsttfb_pci_driver = { name: "imsttfb", id_table: imsttfb_pci_tbl, probe: imsttfb_probe, - remove: imsttfb_remove, + remove: __devexit_p(imsttfb_remove), }; static struct fb_ops imsttfb_ops = { diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 0902bee80..bd51027b0 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -108,6 +108,7 @@ static int default_cmode = CMODE_NVRAM; #endif static void matroxfb_unregister_device(struct matrox_fb_info* minfo); +int matroxfb_switch(int con, struct fb_info *info); /* --------------------------------------------------------------------- */ diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index 30db837cb..2b3dbe4f2 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c @@ -619,7 +619,7 @@ static struct pci_driver radeonfb_driver = { name: "radeonfb", id_table: radeonfb_pci_table, probe: radeonfb_pci_register, - remove: radeonfb_pci_unregister, + remove: __devexit_p(radeonfb_pci_unregister), }; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 2213a8595..72d42b197 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -2082,7 +2082,7 @@ static struct pci_driver rivafb_driver = { name: "rivafb", id_table: rivafb_pci_tbl, probe: rivafb_init_one, - remove: rivafb_remove_one, + remove: __devexit_p(rivafb_remove_one), }; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 11c93e737..b7e522187 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -495,7 +495,7 @@ static struct pci_driver tdfxfb_driver = { name: "tdfxfb", id_table: tdfxfb_id_table, probe: tdfxfb_probe, - remove: tdfxfb_remove, + remove: __devexit_p(tdfxfb_remove), }; MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 019839acd..cbeb0fb38 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -32,7 +32,7 @@ #include <linux/highuid.h> #include <linux/smp_lock.h> #include <linux/compiler.h> -#include <linux/limits.h> +#include <linux/highmem.h> #include <asm/uaccess.h> #include <asm/param.h> @@ -1032,6 +1032,25 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ + /* first copy the parameters from user space */ + memset(&psinfo, 0, sizeof(psinfo)); + { + int i, len; + + len = current->mm->arg_end - current->mm->arg_start; + if (len >= ELF_PRARGSZ) + len = ELF_PRARGSZ-1; + copy_from_user(&psinfo.pr_psargs, + (const char *)current->mm->arg_start, len); + for(i = 0; i < len; i++) + if (psinfo.pr_psargs[i] == 0) + psinfo.pr_psargs[i] = ' '; + psinfo.pr_psargs[len] = 0; + + } + + /* now stop all vm operations */ + down_write(¤t->mm->mmap_sem); segs = current->mm->map_count; #ifdef DEBUG @@ -1073,7 +1092,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) * Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ - memset(&psinfo, 0, sizeof(psinfo)); memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; @@ -1129,23 +1147,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) psinfo.pr_flag = current->flags; psinfo.pr_uid = NEW_TO_OLD_UID(current->uid); psinfo.pr_gid = NEW_TO_OLD_GID(current->gid); - { - int i, len; - - set_fs(fs); - - len = current->mm->arg_end - current->mm->arg_start; - if (len >= ELF_PRARGSZ) - len = ELF_PRARGSZ-1; - copy_from_user(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); - for(i = 0; i < len; i++) - if (psinfo.pr_psargs[i] == 0) - psinfo.pr_psargs[i] = ' '; - psinfo.pr_psargs[len] = 0; - - set_fs(KERNEL_DS); - } strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); notes[2].name = "CORE"; @@ -1217,8 +1218,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) if (!writenote(¬es[i], file)) goto end_coredump; - set_fs(fs); - DUMP_SEEK(dataoff); for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { @@ -1232,22 +1231,24 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - pgd = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgd)) - goto nextpage_coredump; - pmd = pmd_offset(pgd, addr); - if (pmd_none(*pmd)) - goto nextpage_coredump; - pte = pte_offset(pmd, addr); - if (pte_none(*pte)) { -nextpage_coredump: + struct page* page; + struct vm_area_struct *vma; + + if (get_user_pages(current, current->mm, addr, 1, 0, 1, + &page, &vma) <= 0) { DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { - DUMP_WRITE((void*)addr, PAGE_SIZE); + if (page == ZERO_PAGE(addr)) { + DUMP_SEEK (file->f_pos + PAGE_SIZE); + } else { + void *kaddr; + flush_cache_page(vma, addr); + kaddr = kmap(page); + DUMP_WRITE(kaddr, PAGE_SIZE); + flush_page_to_ram(page); + kunmap(page); + } + put_page(page); } } } @@ -1260,6 +1261,7 @@ nextpage_coredump: end_coredump: set_fs(fs); + up_write(¤t->mm->mmap_sem); return has_dumped; } #endif /* USE_ELF_CORE_DUMP */ diff --git a/fs/block_dev.c b/fs/block_dev.c index 485e0bffe..0563a901b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -234,7 +234,7 @@ static struct vfsmount *bd_mnt; #define HASH_SIZE (1UL << HASH_BITS) #define HASH_MASK (HASH_SIZE-1) static struct list_head bdev_hashtable[HASH_SIZE]; -static spinlock_t bdev_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; static kmem_cache_t * bdev_cachep; #define alloc_bdev() \ diff --git a/fs/buffer.c b/fs/buffer.c index d1eb1e410..e9442ec38 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -73,7 +73,7 @@ static struct buffer_head **hash_table; static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED; static struct buffer_head *lru_list[NR_LIST]; -static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t lru_list_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; static int nr_buffers_type[NR_LIST]; static unsigned long size_buffers_type[NR_LIST]; diff --git a/fs/dcache.c b/fs/dcache.c index 313b4fe02..f04948742 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -29,7 +29,7 @@ #define DCACHE_PARANOIA 1 /* #define DCACHE_DEBUG 1 */ -spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED; +spinlock_t dcache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* Right now the dcache depends on the kernel lock */ #define check_lock() if (!kernel_locked()) BUG() @@ -973,9 +973,7 @@ int do_coredump(long signr, struct pt_regs * regs) if (do_truncate(file->f_dentry, 0) != 0) goto close_fail; - down_read(¤t->mm->mmap_sem); retval = binfmt->core_dump(signr, regs, file); - up_read(¤t->mm->mmap_sem); close_fail: filp_close(file, NULL); diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile index c64318e79..68cb48618 100644 --- a/fs/ext3/Makefile +++ b/fs/ext3/Makefile @@ -9,7 +9,7 @@ O_TARGET := ext3.o -obj-y := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ +obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o obj-m := $(O_TARGET) diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c deleted file mode 100644 index f77d42047..000000000 --- a/fs/ext3/acl.c +++ /dev/null @@ -1,17 +0,0 @@ -/* - * linux/fs/ext3/acl.c - * - * Copyright (C) 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include <linux/fs.h> -#include <linux/sched.h> - - -/* - * This file will contain the Access Control Lists management for the - * second extended file system. - */ diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 6059099fd..088f79673 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -508,7 +508,7 @@ repeat: insert_inode_hash(inode); inode->i_generation = event++; - inode->u.ext3_i.i_state = (1UL << EXT3_STATE_NEW); + inode->u.ext3_i.i_state = EXT3_STATE_NEW; err = ext3_mark_inode_dirty(handle, inode); if (err) goto fail; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 8b9008392..02ebe46d4 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -32,7 +32,6 @@ #include <linux/quotaops.h> #include <linux/module.h> - /* * SEARCH_FROM_ZERO forces each block allocation to search from the start * of the filesystem. This is to force rapid reallocation of recently-freed @@ -716,6 +715,8 @@ err_out: * reachable from inode. * * akpm: `handle' can be NULL if create == 0. + * + * The BKL may not be held on entry here. Be sure to take it early. */ static int ext3_get_block_handle(handle_t *handle, struct inode *inode, @@ -823,6 +824,9 @@ changed: goto reread; } +/* + * The BKL is not held on entry here. + */ static int ext3_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) { @@ -1022,13 +1026,26 @@ static int ext3_prepare_write(struct file *file, struct page *page, ret = PTR_ERR(handle); goto out; } + unlock_kernel(); ret = block_prepare_write(page, from, to, ext3_get_block); + lock_kernel(); if (ret != 0) goto prepare_write_failed; - if (ext3_should_journal_data(inode)) + if (ext3_should_journal_data(inode)) { ret = walk_page_buffers(handle, page->buffers, from, to, NULL, do_journal_get_write_access); + if (ret) { + /* + * We're going to fail this prepare_write(), + * so commit_write() will not be called. + * We need to undo block_prepare_write()'s kmap(). + * AKPM: Do we need to clear PageUptodate? I don't + * think so. + */ + kunmap(page); + } + } prepare_write_failed: if (ret) ext3_journal_stop(handle, inode); @@ -1096,7 +1113,7 @@ static int ext3_commit_write(struct file *file, struct page *page, kunmap(page); if (pos > inode->i_size) inode->i_size = pos; - set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state); + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; } else { if (ext3_should_order_data(inode)) { ret = walk_page_buffers(handle, page->buffers, @@ -1104,8 +1121,17 @@ static int ext3_commit_write(struct file *file, struct page *page, } /* Be careful here if generic_commit_write becomes a * required invocation after block_prepare_write. */ - if (ret == 0) + if (ret == 0) { ret = generic_commit_write(file, page, from, to); + } else { + /* + * block_prepare_write() was called, but we're not + * going to call generic_commit_write(). So we + * need to perform generic_commit_write()'s kunmap + * by hand. + */ + kunmap(page); + } } if (inode->i_size > inode->u.ext3_i.i_disksize) { inode->u.ext3_i.i_disksize = inode->i_size; @@ -1140,7 +1166,7 @@ static int ext3_bmap(struct address_space *mapping, long block) journal_t *journal; int err; - if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) { + if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { /* * This is a REALLY heavyweight approach, but the use of * bmap on dirty files is expected to be extremely rare: @@ -1159,6 +1185,7 @@ static int ext3_bmap(struct address_space *mapping, long block) * everything they get. */ + EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; journal = EXT3_JOURNAL(inode); journal_lock_updates(journal); err = journal_flush(journal); @@ -2203,7 +2230,7 @@ static int ext3_do_update_inode(handle_t *handle, /* If we are not tracking these fields in the in-memory inode, * then preserve them on disk, but still initialise them to zero * for new inodes. */ - if (inode->u.ext3_i.i_state & (1UL << EXT3_STATE_NEW)) { + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW) { raw_inode->i_faddr = 0; raw_inode->i_frag = 0; raw_inode->i_fsize = 0; @@ -2249,7 +2276,7 @@ static int ext3_do_update_inode(handle_t *handle, rc = ext3_journal_dirty_metadata(handle, bh); if (!err) err = rc; - inode->u.ext3_i.i_state &= ~(1UL << EXT3_STATE_NEW); + EXT3_I(inode)->i_state &= ~EXT3_STATE_NEW; out_brelse: brelse (bh); @@ -2333,7 +2360,7 @@ void ext3_write_inode(struct inode *inode, int wait) int ext3_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - int error, rc; + int error, rc = 0; error = inode_change_ok(inode, attr); if (error) @@ -2356,7 +2383,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ext3_journal_stop(handle, inode); } - inode_setattr(inode, attr); + rc = inode_setattr(inode, attr); /* If inode_setattr's call to ext3_truncate failed to get a * transaction handle at all, we need to clean up the in-core @@ -2366,7 +2393,9 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) err_out: ext3_std_error(inode->i_sb, error); - return 0; + if (!error) + error = rc; + return error; } @@ -2667,6 +2696,3 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we * need to extend" test in ext3_prepare_write() succeeds. */ - - -MODULE_LICENSE("GPL"); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9a5e18950..fb2303ffc 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1257,8 +1257,11 @@ static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum) } journal = journal_init_inode(journal_inode); - if (!journal) + if (!journal) { + printk(KERN_ERR "EXT3-fs: Could not load journal inode\n"); iput(journal_inode); + } + return journal; } @@ -1350,7 +1353,7 @@ static int ext3_load_journal(struct super_block * sb, journal_t *journal; int journal_inum = le32_to_cpu(es->s_journal_inum); int journal_dev = le32_to_cpu(es->s_journal_dev); - int err; + int err = 0; int really_read_only; really_read_only = is_read_only(sb->s_dev); @@ -1400,9 +1403,10 @@ static int ext3_load_journal(struct super_block * sb, } if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) - journal_wipe(journal, !really_read_only); + err = journal_wipe(journal, !really_read_only); + if (!err) + err = journal_load(journal); - err = journal_load(journal); if (err) { printk(KERN_ERR "EXT3-fs: error loading journal.\n"); journal_destroy(journal); @@ -1740,6 +1744,8 @@ static void __exit exit_ext3_fs(void) EXPORT_NO_SYMBOLS; +MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); +MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); MODULE_LICENSE("GPL"); module_init(init_ext3_fs) module_exit(exit_ext3_fs) diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 045b74ce9..29e96b885 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -47,7 +47,8 @@ void journal_commit_transaction(journal_t *journal) struct buffer_head *wbuf[64]; int bufs; int flags; - int blocknr; + int err; + unsigned long blocknr; char *tagp = NULL; journal_header_t *header; journal_block_tag_t *tag = NULL; @@ -352,6 +353,11 @@ sync_datalist_empty: jbd_debug(4, "JBD: get descriptor\n"); descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) { + __journal_abort_hard(journal); + continue; + } + bh = jh2bh(descriptor); jbd_debug(4, "JBD: got buffer %ld (%p)\n", bh->b_blocknr, bh->b_data); @@ -375,7 +381,14 @@ sync_datalist_empty: /* Where is the buffer to be written? */ - blocknr = journal_next_log_block(journal); + err = journal_next_log_block(journal, &blocknr); + /* If the block mapping failed, just abandon the buffer + and repeat this loop: we'll fall into the + refile-on-abort condition above. */ + if (err) { + __journal_abort_hard(journal); + continue; + } /* Bump b_count to prevent truncate from stumbling over the shadowed buffer! @@@ This can go if we ever get @@ -554,16 +567,20 @@ start_journal_io: jbd_debug(3, "JBD: commit phase 6\n"); + if (is_journal_aborted(journal)) + goto skip_commit; + /* Done it all: now write the commit record. We should have * cleaned up our previous buffers by now, so if we are in abort * mode we can now just skip the rest of the journal write * entirely. */ - if (is_journal_aborted(journal)) - goto skip_commit; - descriptor = journal_get_descriptor_buffer(journal); - + if (!descriptor) { + __journal_abort_hard(journal); + goto skip_commit; + } + /* AKPM: buglet - add `i' to tmp! */ for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) { journal_header_t *tmp = diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 2b86b94c7..cf381d4fa 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -70,7 +70,6 @@ EXPORT_SYMBOL(journal_load); EXPORT_SYMBOL(journal_destroy); EXPORT_SYMBOL(journal_recover); EXPORT_SYMBOL(journal_update_superblock); -EXPORT_SYMBOL(__journal_abort); EXPORT_SYMBOL(journal_abort); EXPORT_SYMBOL(journal_errno); EXPORT_SYMBOL(journal_ack_err); @@ -606,7 +605,7 @@ void log_wait_commit (journal_t *journal, tid_t tid) * Log buffer allocation routines: */ -unsigned long journal_next_log_block(journal_t *journal) +int journal_next_log_block(journal_t *journal, unsigned long *retp) { unsigned long blocknr; @@ -617,7 +616,7 @@ unsigned long journal_next_log_block(journal_t *journal) journal->j_free--; if (journal->j_head == journal->j_last) journal->j_head = journal->j_first; - return journal_bmap(journal, blocknr); + return journal_bmap(journal, blocknr, retp); } /* @@ -627,17 +626,28 @@ unsigned long journal_next_log_block(journal_t *journal) * this is a no-op. If needed, we can use j_blk_offset - everything is * ready. */ -unsigned long journal_bmap(journal_t *journal, unsigned long blocknr) +int journal_bmap(journal_t *journal, unsigned long blocknr, + unsigned long *retp) { + int err = 0; unsigned long ret; if (journal->j_inode) { ret = bmap(journal->j_inode, blocknr); - J_ASSERT(ret != 0); + if (ret) + *retp = ret; + else { + printk (KERN_ALERT __FUNCTION__ + ": journal block not found " + "at offset %lu on %s\n", + blocknr, bdevname(journal->j_dev)); + err = -EIO; + __journal_abort_soft(journal, err); + } } else { - ret = blocknr; /* +journal->j_blk_offset */ + *retp = blocknr; /* +journal->j_blk_offset */ } - return ret; + return err; } /* @@ -649,7 +659,13 @@ unsigned long journal_bmap(journal_t *journal, unsigned long blocknr) struct journal_head * journal_get_descriptor_buffer(journal_t *journal) { struct buffer_head *bh; - unsigned long blocknr = journal_next_log_block(journal); + unsigned long blocknr; + int err; + + err = journal_next_log_block(journal, &blocknr); + + if (err) + return NULL; bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); bh->b_state |= (1 << BH_Dirty); @@ -747,7 +763,8 @@ journal_t * journal_init_inode (struct inode *inode) { struct buffer_head *bh; journal_t *journal = journal_init_common(); - int blocknr; + int err; + unsigned long blocknr; if (!journal) return NULL; @@ -757,13 +774,22 @@ journal_t * journal_init_inode (struct inode *inode) journal->j_inode = inode; jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", - journal, bdevname(inode->i_dev), inode->i_ino, inode->i_size, + journal, bdevname(inode->i_dev), inode->i_ino, + (long long) inode->i_size, inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits; journal->j_blocksize = inode->i_sb->s_blocksize; - blocknr = journal_bmap(journal, 0); + err = journal_bmap(journal, 0, &blocknr); + /* If that failed, give up */ + if (err) { + printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal " + "superblock\n"); + kfree(journal); + return NULL; + } + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; @@ -772,6 +798,18 @@ journal_t * journal_init_inode (struct inode *inode) return journal; } +/* + * If the journal init or create aborts, we need to mark the journal + * superblock as being NULL to prevent the journal destroy from writing + * back a bogus superblock. + */ +static void journal_fail_superblock (journal_t *journal) +{ + struct buffer_head *bh = journal->j_sb_buffer; + brelse(bh); + journal->j_sb_buffer = NULL; +} + /* * Given a journal_t structure, initialise the various fields for * startup of a new journaling session. We use this both when creating @@ -817,14 +855,15 @@ static int journal_reset (journal_t *journal) int journal_create (journal_t *journal) { - int blocknr; + unsigned long blocknr; struct buffer_head *bh; journal_superblock_t *sb; - int i; + int i, err; if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { printk (KERN_ERR "Journal length (%d blocks) too short.\n", journal->j_maxlen); + journal_fail_superblock(journal); return -EINVAL; } @@ -841,7 +880,9 @@ int journal_create (journal_t *journal) have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); for (i = 0; i < journal->j_maxlen; i++) { - blocknr = journal_bmap(journal, i); + err = journal_bmap(journal, i, &blocknr); + if (err) + return err; bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); wait_on_buffer(bh); memset (bh->b_data, 0, journal->j_blocksize); @@ -851,6 +892,7 @@ int journal_create (journal_t *journal) mark_buffer_uptodate(bh, 1); __brelse(bh); } + sync_dev(journal->j_dev); jbd_debug(1, "JBD: journal cleared.\n"); @@ -915,7 +957,8 @@ static int journal_get_superblock(journal_t *journal) { struct buffer_head *bh; journal_superblock_t *sb; - + int err = -EIO; + bh = journal->j_sb_buffer; J_ASSERT(bh != NULL); @@ -925,16 +968,18 @@ static int journal_get_superblock(journal_t *journal) if (!buffer_uptodate(bh)) { printk (KERN_ERR "JBD: IO error reading journal superblock\n"); - return -EIO; + goto out; } } sb = journal->j_superblock; + err = -EINVAL; + if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || sb->s_blocksize != htonl(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); - return -EINVAL; + goto out; } switch(ntohl(sb->s_header.h_blocktype)) { @@ -946,17 +991,21 @@ static int journal_get_superblock(journal_t *journal) break; default: printk(KERN_WARNING "JBD: unrecognised superblock format ID\n"); - return -EINVAL; + goto out; } if (ntohl(sb->s_maxlen) < journal->j_maxlen) journal->j_maxlen = ntohl(sb->s_maxlen); else if (ntohl(sb->s_maxlen) > journal->j_maxlen) { printk (KERN_WARNING "JBD: journal file too short\n"); - return -EINVAL; + goto out; } return 0; + +out: + journal_fail_superblock(journal); + return err; } /* @@ -1061,7 +1110,10 @@ void journal_destroy (journal_t *journal) /* We can now mark the journal as empty. */ journal->j_tail = 0; journal->j_tail_sequence = ++journal->j_transaction_sequence; - journal_update_superblock(journal, 1); + if (journal->j_sb_buffer) { + journal_update_superblock(journal, 1); + brelse(journal->j_sb_buffer); + } if (journal->j_inode) iput(journal->j_inode); @@ -1069,7 +1121,6 @@ void journal_destroy (journal_t *journal) journal_destroy_revoke(journal); unlock_journal(journal); - brelse(journal->j_sb_buffer); kfree(journal); MOD_DEC_USE_COUNT; } @@ -1356,11 +1407,16 @@ const char * journal_dev_name(journal_t *journal) * progress). */ -/* Quick version for internal journal use (doesn't lock the journal) */ -void __journal_abort (journal_t *journal) +/* Quick version for internal journal use (doesn't lock the journal). + * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, + * and don't attempt to make any other journal updates. */ +void __journal_abort_hard (journal_t *journal) { transaction_t *transaction; + if (journal->j_flags & JFS_ABORT) + return; + printk (KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal)); @@ -1370,23 +1426,27 @@ void __journal_abort (journal_t *journal) log_start_commit(journal, transaction); } -/* Full version for external use */ -void journal_abort (journal_t *journal, int errno) +/* Soft abort: record the abort error status in the journal superblock, + * but don't do any other IO. */ +void __journal_abort_soft (journal_t *journal, int errno) { - lock_journal(journal); - if (journal->j_flags & JFS_ABORT) - goto out; + return; if (!journal->j_errno) journal->j_errno = errno; - __journal_abort(journal); + __journal_abort_hard(journal); if (errno) journal_update_superblock(journal, 1); +} - out: +/* Full version for external use */ +void journal_abort (journal_t *journal, int errno) +{ + lock_journal(journal); + __journal_abort_soft(journal, errno); unlock_journal(journal); } diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 491dc6cb6..e8e416306 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -70,7 +70,8 @@ void journal_brelse_array(struct buffer_head *b[], int n) static int do_readahead(journal_t *journal, unsigned int start) { int err; - unsigned int max, nbufs, next, blocknr; + unsigned int max, nbufs, next; + unsigned long blocknr; struct buffer_head *bh; struct buffer_head * bufs[MAXBUF]; @@ -86,12 +87,11 @@ static int do_readahead(journal_t *journal, unsigned int start) nbufs = 0; for (next = start; next < max; next++) { - blocknr = journal_bmap(journal, next); + err = journal_bmap(journal, next, &blocknr); - if (!blocknr) { + if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", next); - err = -EIO; goto failed; } @@ -132,19 +132,20 @@ failed: static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset) { - unsigned int blocknr; + int err; + unsigned long blocknr; struct buffer_head *bh; *bhp = NULL; J_ASSERT (offset < journal->j_maxlen); - blocknr = journal_bmap(journal, offset); + err = journal_bmap(journal, offset, &blocknr); - if (!blocknr) { + if (err) { printk (KERN_ERR "JBD: bad block at offset %u\n", offset); - return -EIO; + return err; } bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 8feb8aae8..01b7684e9 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -495,6 +495,8 @@ static void write_one_revoke_record(journal_t *journal, if (!descriptor) { descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) + return; header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; header->h_magic = htonl(JFS_MAGIC_NUMBER); header->h_blocktype = htonl(JFS_REVOKE_BLOCK); diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index a254c2ce3..10b54892d 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1058,21 +1058,6 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) JBUFFER_TRACE(jh, "not on a transaction"); __journal_file_buffer(jh, handle->h_transaction, wanted_jlist); } - /* - * We need to mark the buffer dirty and refile it inside the lock to - * protect it from release by journal_try_to_free_buffer() - * - * We set ->b_flushtime to something small enough to typically keep - * kupdate away from the buffer. - * - * We don't need to do a balance_dirty() - __block_commit_write() - * does that. - */ - if (!async && !atomic_set_buffer_dirty(jh2bh(jh))) { - jh2bh(jh)->b_flushtime = - jiffies + journal->j_commit_interval + 1 * HZ; - refile_buffer(jh2bh(jh)); - } no_journal: spin_unlock(&journal_datalist_lock); if (need_brelse) { @@ -1604,8 +1589,6 @@ static int __journal_try_to_free_buffer(struct buffer_head *bh, assert_spin_locked(&journal_datalist_lock); - if (!buffer_jbd(bh)) - return 1; jh = bh2jh(bh); if (buffer_locked(bh) || buffer_dirty(bh)) { diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 2c9987eba..545e1c1af 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -17,6 +17,37 @@ #define NFSDBG_FACILITY NFSDBG_PROC +/* A wrapper to handle the EJUKEBOX error message */ +static int +nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) +{ + sigset_t oldset; + int res; + rpc_clnt_sigmask(clnt, &oldset); + do { + res = rpc_call_sync(clnt, msg, flags); + if (res != -EJUKEBOX) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(NFS_JUKEBOX_RETRY_TIME); + res = -ERESTARTSYS; + } while (!signalled()); + rpc_clnt_sigunmask(clnt, &oldset); + return res; +} + +static inline int +nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) +{ + struct rpc_message msg = { proc, argp, resp, NULL }; + return nfs3_rpc_wrapper(clnt, &msg, flags); +} + +#define rpc_call(clnt, proc, argp, resp, flags) \ + nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags) +#define rpc_call_sync(clnt, msg, flags) \ + nfs3_rpc_wrapper(clnt, msg, flags) + /* * Bare-bones access to getattr: this is for nfs_read_super. */ diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 3ae20c8bd..ec88c3ccb 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -187,7 +187,7 @@ nfs_list_add_request(struct nfs_page *req, struct list_head *head) BUG(); } #endif - for (pos = head->prev; pos != head; pos = pos->prev) { + list_for_each_prev(pos, head) { struct nfs_page *p = nfs_list_entry(pos); if (page_index(p->wb_page) < pg_idx) break; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 53d2dcdda..ff3478d67 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -402,6 +402,9 @@ nfs_readpage_result(struct rpc_task *task) dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + nfs_refresh_inode(inode, &data->fattr); while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 800fc5767..08e67912f 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -123,6 +123,8 @@ nfs_async_unlink_done(struct rpc_task *task) struct dentry *dir = data->dir; struct inode *dir_i; + if (nfs_async_handle_jukebox(task)) + return; if (!dir) return; dir_i = dir->d_inode; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2d7d65392..324c6066a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -305,18 +305,30 @@ region_locked(struct inode *inode, struct nfs_page *req) /* * Insert a write request into an inode + * Note: we sort the list in order to be able to optimize nfs_find_request() + * & co. for the 'write append' case. For 2.5 we may want to consider + * some form of hashing so as to perform well on random writes. */ static inline void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) { + struct list_head *pos, *head; + unsigned long pg_idx = page_index(req->wb_page); + if (!list_empty(&req->wb_hash)) return; if (!NFS_WBACK_BUSY(req)) printk(KERN_ERR "NFS: unlocked request attempted hashed!\n"); - if (list_empty(&inode->u.nfs_i.writeback)) + head = &inode->u.nfs_i.writeback; + if (list_empty(head)) igrab(inode); + list_for_each_prev(pos, head) { + struct nfs_page *entry = nfs_inode_wb_entry(pos); + if (page_index(entry->wb_page) < pg_idx) + break; + } inode->u.nfs_i.npages++; - list_add(&req->wb_hash, &inode->u.nfs_i.writeback); + list_add(&req->wb_hash, pos); req->wb_count++; } @@ -354,15 +366,18 @@ nfs_inode_remove_request(struct nfs_page *req) static inline struct nfs_page * _nfs_find_request(struct inode *inode, struct page *page) { - struct list_head *head, *next; + struct list_head *head, *pos; + unsigned long pg_idx = page_index(page); head = &inode->u.nfs_i.writeback; - next = head->next; - while (next != head) { - struct nfs_page *req = nfs_inode_wb_entry(next); - next = next->next; - if (page_index(req->wb_page) != page_index(page)) + list_for_each_prev(pos, head) { + struct nfs_page *req = nfs_inode_wb_entry(pos); + unsigned long found_idx = page_index(req->wb_page); + + if (pg_idx < found_idx) continue; + if (pg_idx != found_idx) + break; req->wb_count++; return req; } @@ -444,20 +459,20 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_s else idx_end = idx_start + npages - 1; - spin_lock(&nfs_wreq_lock); head = &inode->u.nfs_i.writeback; - p = head->next; - while (p != head) { + restart: + spin_lock(&nfs_wreq_lock); + list_for_each_prev(p, head) { unsigned long pg_idx; struct nfs_page *req = nfs_inode_wb_entry(p); - p = p->next; - if (file && req->wb_file != file) continue; pg_idx = page_index(req->wb_page); - if (pg_idx < idx_start || pg_idx > idx_end) + if (pg_idx < idx_start) + break; + if (pg_idx > idx_end) continue; if (!NFS_WBACK_BUSY(req)) @@ -468,9 +483,8 @@ nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_s nfs_release_request(req); if (error < 0) return error; - spin_lock(&nfs_wreq_lock); - p = head->next; res++; + goto restart; } spin_unlock(&nfs_wreq_lock); return res; @@ -991,6 +1005,9 @@ nfs_writeback_done(struct rpc_task *task) dprintk("NFS: %4d nfs_writeback_done (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + /* We can't handle that yet but we check for it nevertheless */ if (resp->count < argp->count && task->tk_status >= 0) { static unsigned long complain; @@ -1184,6 +1201,9 @@ nfs_commit_done(struct rpc_task *task) dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); + if (nfs_async_handle_jukebox(task)) + return; + nfs_write_attributes(inode, resp->fattr); while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); diff --git a/include/linux/cache.h b/include/linux/cache.h index 086accecf..14e9c0b89 100644 --- a/include/linux/cache.h +++ b/include/linux/cache.h @@ -34,4 +34,12 @@ #endif #endif /* __cacheline_aligned */ +#ifndef __cacheline_aligned_in_smp +#ifdef CONFIG_SMP +#define __cacheline_aligned_in_smp __cacheline_aligned +#else +#define __cacheline_aligned_in_smp +#endif /* CONFIG_SMP */ +#endif + #endif /* __LINUX_CACHE_H */ diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 1768e5249..db5de1462 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -36,8 +36,8 @@ /* * The second extended file system version */ -#define EXT3FS_DATE "06 Nov 2001" -#define EXT3FS_VERSION "2.4-0.9.15" +#define EXT3FS_DATE "02 Dec 2001" +#define EXT3FS_VERSION "2.4-0.9.16" /* * Debug code @@ -209,10 +209,10 @@ struct ext3_group_desc #define EXT3_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ /* - * Inode dynamic state bit positions + * Inode dynamic state flags */ -#define EXT3_STATE_JDATA 0 /* journaled data exists */ -#define EXT3_STATE_NEW 1 /* inode is newly created */ +#define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ +#define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ /* * ioctl commands @@ -577,10 +577,6 @@ struct ext3_dir_entry_2 { ~EXT3_DIR_ROUND) #ifdef __KERNEL__ - -/* Filesize hard limits for 64-bit file offsets */ -extern long long ext3_max_sizes[]; - /* * Describe an inode's exact location on disk and in memory */ @@ -603,9 +599,6 @@ struct ext3_iloc # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, -/* acl.c */ -extern int ext3_permission (struct inode *, int); - /* balloc.c */ extern int ext3_bg_has_super(struct super_block *sb, int group); extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); @@ -619,16 +612,10 @@ extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, unsigned int block_group, struct buffer_head ** bh); -/* bitmap.c */ -extern unsigned long ext3_count_free (struct buffer_head *, unsigned); - /* dir.c */ extern int ext3_check_dir_entry(const char *, struct inode *, struct ext3_dir_entry_2 *, struct buffer_head *, unsigned long); - -/* file.c */ - /* fsync.c */ extern int ext3_sync_file (struct file *, struct dentry *, int); @@ -638,9 +625,9 @@ extern void ext3_free_inode (handle_t *, struct inode *); extern struct inode * ext3_orphan_get (struct super_block *, ino_t); extern unsigned long ext3_count_free_inodes (struct super_block *); extern void ext3_check_inodes_bitmap (struct super_block *); +extern unsigned long ext3_count_free (struct buffer_head *, unsigned); /* inode.c */ - extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); @@ -654,13 +641,13 @@ extern int ext3_sync_inode (handle_t *, struct inode *); extern void ext3_discard_prealloc (struct inode *); extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); +extern void ext3_truncate (struct inode *); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, unsigned long); /* namei.c */ -extern struct inode_operations ext3_dir_inode_operations; extern int ext3_orphan_add(handle_t *, struct inode *); extern int ext3_orphan_del(handle_t *, struct inode *); @@ -684,9 +671,6 @@ extern int ext3_remount (struct super_block *, int *, char *); extern struct super_block * ext3_read_super (struct super_block *,void *,int); extern int ext3_statfs (struct super_block *, struct statfs *); -/* truncate.c */ -extern void ext3_truncate (struct inode *); - #define ext3_std_error(sb, errno) \ do { \ if ((errno)) \ @@ -705,10 +689,15 @@ extern struct file_operations ext3_dir_operations; extern struct inode_operations ext3_file_inode_operations; extern struct file_operations ext3_file_operations; +/* inode.c */ +extern struct address_space_operations ext3_aops; + +/* namei.c */ +extern struct inode_operations ext3_dir_inode_operations; + /* symlink.c */ extern struct inode_operations ext3_fast_symlink_inode_operations; -extern struct address_space_operations ext3_aops; #endif /* __KERNEL__ */ diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index c3cb21235..3c8d398a8 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -34,7 +34,7 @@ struct ext3_inode_info { __u32 i_dir_acl; __u32 i_dtime; __u32 i_block_group; - unsigned long i_state; /* Dynamic state flags for ext3 */ + __u32 i_state; /* Dynamic state flags for ext3 */ __u32 i_next_alloc_block; __u32 i_next_alloc_goal; #ifdef EXT3_PREALLOCATE diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index 9e4002b52..88bb8a516 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -196,9 +196,22 @@ __ext3_journal_dirty_metadata(const char *where, */ static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) { + journal_t *journal; + if (inode->i_sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); - return journal_start(EXT3_JOURNAL(inode), nblocks); + + /* Special case here: if the journal has aborted behind our + * backs (eg. EIO in the commit thread), then we still need to + * take the FS itself readonly cleanly. */ + journal = EXT3_JOURNAL(inode); + if (is_journal_aborted(journal)) { + ext3_abort(inode->i_sb, __FUNCTION__, + "Detected aborted journal"); + return ERR_PTR(-EROFS); + } + + return journal_start(journal, nblocks); } static inline handle_t * diff --git a/include/linux/init.h b/include/linux/init.h index f0644ca30..53218e330 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -111,7 +111,7 @@ extern struct kernel_param __setup_start, __setup_end; */ #define module_exit(x) __exitcall(x); -#else +#else /* MODULE */ #define __init #define __exit @@ -141,7 +141,7 @@ typedef void (*__cleanup_module_func_t)(void); #define __setup(str,func) /* nothing */ -#endif +#endif /* !MODULE */ #ifdef CONFIG_HOTPLUG #define __devinit @@ -155,4 +155,16 @@ typedef void (*__cleanup_module_func_t)(void); #define __devexitdata __exitdata #endif +/* Functions marked as __devexit may be discarded at kernel link time, depending + on config options. Newer versions of binutils detect references from + retained sections to discarded sections and flag an error. Pointers to + __devexit functions must use __devexit_p(function_name), the wrapper will + insert either the function_name or NULL, depending on the config options. + */ +#if defined(MODULE) || defined(CONFIG_HOTPLUG) +#define __devexit_p(x) x +#else +#define __devexit_p(x) NULL +#endif + #endif /* _LINUX_INIT_H */ diff --git a/include/linux/jbd.h b/include/linux/jbd.h index 64d90a289..2cb980fbb 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -564,7 +564,7 @@ extern void __journal_clean_data_list(transaction_t *transaction); /* Log buffer allocation */ extern struct journal_head * journal_get_descriptor_buffer(journal_t *); -extern unsigned long journal_next_log_block(journal_t *); +int journal_next_log_block(journal_t *, unsigned long *); /* Commit management */ extern void journal_commit_transaction(journal_t *); @@ -664,15 +664,16 @@ extern int journal_load (journal_t *journal); extern void journal_destroy (journal_t *); extern int journal_recover (journal_t *journal); extern int journal_wipe (journal_t *, int); -extern int journal_skip_recovery (journal_t *); -extern void journal_update_superblock (journal_t *, int); -extern void __journal_abort (journal_t *); +extern int journal_skip_recovery (journal_t *); +extern void journal_update_superblock (journal_t *, int); +extern void __journal_abort_hard (journal_t *); +extern void __journal_abort_soft (journal_t *, int); extern void journal_abort (journal_t *, int); extern int journal_errno (journal_t *); extern void journal_ack_err (journal_t *); extern int journal_clear_err (journal_t *); -extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); -extern int journal_force_commit(journal_t *journal); +extern int journal_bmap(journal_t *, unsigned long, unsigned long *); +extern int journal_force_commit(journal_t *); /* * journal_head management diff --git a/include/linux/list.h b/include/linux/list.h index 0d04422e8..61b1493f5 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -162,6 +162,16 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) +/** + * list_for_each_prev - iterate over a list in reverse order + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index 186fe152a..98b763c4f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -422,6 +422,9 @@ extern int ptrace_detach(struct task_struct *, unsigned int); extern void ptrace_disable(struct task_struct *); extern int ptrace_check_attach(struct task_struct *task, int kill); +int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); + /* * On a two-level page table, this ends up being trivial. Thus the * inlining and the symmetry break with pte_alloc() that does all diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index efbbdba3a..4266b3ce0 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -16,6 +16,7 @@ #include <linux/sunrpc/debug.h> #include <linux/sunrpc/auth.h> +#include <linux/sunrpc/clnt.h> #include <linux/nfs.h> #include <linux/nfs2.h> @@ -332,6 +333,29 @@ extern void * nfs_root_data(void); __retval; \ }) +#ifdef CONFIG_NFS_V3 + +#define NFS_JUKEBOX_RETRY_TIME (5 * HZ) +static inline int +nfs_async_handle_jukebox(struct rpc_task *task) +{ + if (task->tk_status != -EJUKEBOX) + return 0; + task->tk_status = 0; + rpc_restart_call(task); + rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); + return 1; +} + +#else + +static inline int +nfs_async_handle_jukebox(struct rpc_task *task) +{ + return 0; +} +#endif /* CONFIG_NFS_V3 */ + #endif /* __KERNEL__ */ /* diff --git a/kernel/ptrace.c b/kernel/ptrace.c index da45fa2be..b729b6f30 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -121,119 +121,17 @@ int ptrace_detach(struct task_struct *child, unsigned int data) } /* - * Access another process' address space, one page at a time. + * Access another process' address space. + * Source/target buffer must be kernel space, + * Do not walk the page table directly, use get_user_pages */ -static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write) -{ - pgd_t * pgdir; - pmd_t * pgmiddle; - pte_t * pgtable; - char *maddr; - struct page *page; - -repeat: - spin_lock(&mm->page_table_lock); - pgdir = pgd_offset(vma->vm_mm, addr); - if (pgd_none(*pgdir)) - goto fault_in_page; - if (pgd_bad(*pgdir)) - goto bad_pgd; - pgmiddle = pmd_offset(pgdir, addr); - if (pmd_none(*pgmiddle)) - goto fault_in_page; - if (pmd_bad(*pgmiddle)) - goto bad_pmd; - pgtable = pte_offset(pgmiddle, addr); - if (!pte_present(*pgtable)) - goto fault_in_page; - if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable))) - goto fault_in_page; - page = pte_page(*pgtable); - - /* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */ - if (page != ZERO_PAGE(addr) || write) { - if ((!VALID_PAGE(page)) || PageReserved(page)) { - spin_unlock(&mm->page_table_lock); - return 0; - } - } - get_page(page); - spin_unlock(&mm->page_table_lock); - flush_cache_page(vma, addr); - - if (write) { - maddr = kmap(page); - memcpy(maddr + (addr & ~PAGE_MASK), buf, len); - flush_page_to_ram(page); - flush_icache_page(vma, page); - kunmap(page); - } else { - maddr = kmap(page); - memcpy(buf, maddr + (addr & ~PAGE_MASK), len); - flush_page_to_ram(page); - kunmap(page); - } - put_page(page); - return len; - -fault_in_page: - spin_unlock(&mm->page_table_lock); - /* -1: out of memory. 0 - unmapped page */ - if (handle_mm_fault(mm, vma, addr, write) > 0) - goto repeat; - return 0; - -bad_pgd: - spin_unlock(&mm->page_table_lock); - pgd_ERROR(*pgdir); - return 0; - -bad_pmd: - spin_unlock(&mm->page_table_lock); - pmd_ERROR(*pgmiddle); - return 0; -} - -static int access_mm(struct mm_struct *mm, struct vm_area_struct * vma, unsigned long addr, void *buf, int len, int write) -{ - int copied = 0; - - for (;;) { - unsigned long offset = addr & ~PAGE_MASK; - int this_len = PAGE_SIZE - offset; - int retval; - - if (this_len > len) - this_len = len; - retval = access_one_page(mm, vma, addr, buf, this_len, write); - copied += retval; - if (retval != this_len) - break; - - len -= retval; - if (!len) - break; - - addr += retval; - buf += retval; - - if (addr < vma->vm_end) - continue; - if (!vma->vm_next) - break; - if (vma->vm_next->vm_start != vma->vm_end) - break; - - vma = vma->vm_next; - } - return copied; -} int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) { - int copied; struct mm_struct *mm; - struct vm_area_struct * vma; + struct vm_area_struct *vma; + struct page *page; + void *old_buf = buf; /* Worry about races with exit() */ task_lock(tsk); @@ -245,14 +143,41 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in return 0; down_read(&mm->mmap_sem); - vma = find_extend_vma(mm, addr); - copied = 0; - if (vma) - copied = access_mm(mm, vma, addr, buf, len, write); + /* ignore errors, just check how much was sucessfully transfered */ + while (len) { + int bytes, ret, offset; + void *maddr; + + ret = get_user_pages(current, mm, addr, 1, + write, 1, &page, &vma); + if (ret <= 0) + break; + bytes = len; + offset = addr & (PAGE_SIZE-1); + if (bytes > PAGE_SIZE-offset) + bytes = PAGE_SIZE-offset; + + flush_cache_page(vma, addr); + + maddr = kmap(page); + if (write) { + memcpy(maddr + offset, buf, bytes); + flush_page_to_ram(page); + flush_icache_page(vma, page); + } else { + memcpy(buf, maddr + offset, bytes); + flush_page_to_ram(page); + } + kunmap(page); + put_page(page); + len -= bytes; + buf += bytes; + } up_read(&mm->mmap_sem); mmput(mm); - return copied; + + return buf - old_buf; } int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len) diff --git a/mm/filemap.c b/mm/filemap.c index 9eccb5783..129849b4b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -53,7 +53,7 @@ EXPORT_SYMBOL(vm_max_readahead); EXPORT_SYMBOL(vm_min_readahead); -spinlock_t pagecache_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +spinlock_t pagecache_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; /* * NOTE: to avoid deadlocking you must never acquire the pagemap_lru_lock * with the pagecache_lock held. @@ -63,7 +63,7 @@ spinlock_t pagecache_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; * pagemap_lru_lock -> * pagecache_lock */ -spinlock_t pagemap_lru_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +spinlock_t pagemap_lru_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; #define CLUSTER_PAGES (1 << page_cluster) #define CLUSTER_OFFSET(x) (((x) >> page_cluster) << page_cluster) diff --git a/mm/highmem.c b/mm/highmem.c index dce6c792f..a4a3fbb71 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -32,7 +32,7 @@ */ static int pkmap_count[LAST_PKMAP]; static unsigned int last_pkmap_nr; -static spinlock_t kmap_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t kmap_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; pte_t * pkmap_page_table; diff --git a/mm/memory.c b/mm/memory.c index 19924efce..f455a5d3d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -397,17 +397,16 @@ void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long s spin_unlock(&mm->page_table_lock); } - /* * Do a quick page-table lookup for a single page. */ -static struct page * follow_page(unsigned long address, int write) +static struct page * follow_page(struct mm_struct *mm, unsigned long address, int write) { pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte; - pgd = pgd_offset(current->mm, address); + pgd = pgd_offset(mm, address); if (pgd_none(*pgd) || pgd_bad(*pgd)) goto out; @@ -443,21 +442,74 @@ static inline struct page * get_page_map(struct page *page) return page; } +int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas) +{ + int i = 0; + + do { + struct vm_area_struct * vma; + + vma = find_extend_vma(mm, start); + + if ( !vma || + (!force && + ((write && (!(vma->vm_flags & VM_WRITE))) || + (!write && (!(vma->vm_flags & VM_READ))) ) )) { + if (i) return i; + return -EFAULT; + } + + spin_lock(&mm->page_table_lock); + do { + struct page *map; + while (!(map = follow_page(mm, start, write))) { + spin_unlock(&mm->page_table_lock); + switch (handle_mm_fault(mm, vma, start, write)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + if (i) return i; + return -EFAULT; + default: + if (i) return i; + return -ENOMEM; + } + spin_lock(&mm->page_table_lock); + } + if (pages) { + pages[i] = get_page_map(map); + /* FIXME: call the correct function, + * depending on the type of the found page + */ + if (pages[i]) + page_cache_get(pages[i]); + } + if (vmas) + vmas[i] = vma; + i++; + start += PAGE_SIZE; + len--; + } while(len && start < vma->vm_end); + spin_unlock(&mm->page_table_lock); + } while(len); + return i; +} + /* * Force in an entire range of pages from the current process's user VA, * and pin them in physical memory. */ - #define dprintk(x...) + int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) { - unsigned long ptr, end; - int err; + int pgcount, err; struct mm_struct * mm; - struct vm_area_struct * vma = 0; - struct page * map; - int i; - int datain = (rw == READ); /* Make sure the iobuf is not already mapped somewhere. */ if (iobuf->nr_pages) @@ -466,79 +518,37 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) mm = current->mm; dprintk ("map_user_kiobuf: begin\n"); - ptr = va & PAGE_MASK; - end = (va + len + PAGE_SIZE - 1) & PAGE_MASK; - err = expand_kiobuf(iobuf, (end - ptr) >> PAGE_SHIFT); + pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE; + /* mapping 0 bytes is not permitted */ + if (!pgcount) BUG(); + err = expand_kiobuf(iobuf, pgcount); if (err) return err; - down_read(&mm->mmap_sem); - - err = -EFAULT; iobuf->locked = 0; - iobuf->offset = va & ~PAGE_MASK; + iobuf->offset = va & (PAGE_SIZE-1); iobuf->length = len; - i = 0; - - /* - * First of all, try to fault in all of the necessary pages - */ - while (ptr < end) { - if (!vma || ptr >= vma->vm_end) { - vma = find_vma(current->mm, ptr); - if (!vma) - goto out_unlock; - if (vma->vm_start > ptr) { - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto out_unlock; - if (expand_stack(vma, ptr)) - goto out_unlock; - } - if (((datain) && (!(vma->vm_flags & VM_WRITE))) || - (!(vma->vm_flags & VM_READ))) { - err = -EACCES; - goto out_unlock; - } - } - spin_lock(&mm->page_table_lock); - while (!(map = follow_page(ptr, datain))) { - int ret; - - spin_unlock(&mm->page_table_lock); - ret = handle_mm_fault(current->mm, vma, ptr, datain); - if (ret <= 0) { - if (!ret) - goto out_unlock; - else { - err = -ENOMEM; - goto out_unlock; - } - } - spin_lock(&mm->page_table_lock); - } - map = get_page_map(map); - if (map) { - flush_dcache_page(map); - page_cache_get(map); - } else - printk (KERN_INFO "Mapped page missing [%d]\n", i); - spin_unlock(&mm->page_table_lock); - iobuf->maplist[i] = map; - iobuf->nr_pages = ++i; - - ptr += PAGE_SIZE; - } - + /* Try to fault in all of the necessary pages */ + down_read(&mm->mmap_sem); + /* rw==READ means read from disk, write into memory area */ + err = get_user_pages(current, mm, va, pgcount, + (rw==READ), 0, iobuf->maplist, NULL); up_read(&mm->mmap_sem); + if (err < 0) { + unmap_kiobuf(iobuf); + dprintk ("map_user_kiobuf: end %d\n", err); + return err; + } + iobuf->nr_pages = err; + while (pgcount--) { + /* FIXME: flush superflous for rw==READ, + * probably wrong function for rw==WRITE + */ + flush_dcache_page(iobuf->maplist[pgcount]); + } dprintk ("map_user_kiobuf: end OK\n"); return 0; - - out_unlock: - up_read(&mm->mmap_sem); - unmap_kiobuf(iobuf); - dprintk ("map_user_kiobuf: end %d\n", err); - return err; } /* @@ -588,6 +598,9 @@ void unmap_kiobuf (struct kiobuf *iobuf) if (map) { if (iobuf->locked) UnlockPage(map); + /* FIXME: cache flush missing for rw==READ + * FIXME: call the correct reference counting function + */ page_cache_release(map); } } @@ -1409,23 +1422,19 @@ out: return pte_offset(pmd, address); } -/* - * Simplistic page force-in.. - */ int make_pages_present(unsigned long addr, unsigned long end) { - int write; - struct mm_struct *mm = current->mm; + int ret, len, write; struct vm_area_struct * vma; - vma = find_vma(mm, addr); + vma = find_vma(current->mm, addr); write = (vma->vm_flags & VM_WRITE) != 0; if (addr >= end) BUG(); - do { - if (handle_mm_fault(mm, vma, addr, write) < 0) - return -1; - addr += PAGE_SIZE; - } while (addr < end); - return 0; + if (end > vma->vm_end) + BUG(); + len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE; + ret = get_user_pages(current, current->mm, addr, + len, write, 0, NULL, NULL); + return ret == len ? 0 : -1; } diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 87fd3e0ed..b743e432e 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -6,6 +6,7 @@ * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000 */ +#include <linux/config.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/spinlock.h> @@ -282,3 +283,40 @@ finished: read_unlock(&vmlist_lock); return buf - buf_start; } + +long vwrite(char *buf, char *addr, unsigned long count) +{ + struct vm_struct *tmp; + char *vaddr, *buf_start = buf; + unsigned long n; + + /* Don't allow overflow */ + if ((unsigned long) addr + count < count) + count = -(unsigned long) addr; + + read_lock(&vmlist_lock); + for (tmp = vmlist; tmp; tmp = tmp->next) { + vaddr = (char *) tmp->addr; + if (addr >= vaddr + tmp->size - PAGE_SIZE) + continue; + while (addr < vaddr) { + if (count == 0) + goto finished; + buf++; + addr++; + count--; + } + n = vaddr + tmp->size - PAGE_SIZE - addr; + do { + if (count == 0) + goto finished; + *addr = *buf; + buf++; + addr++; + count--; + } while (--n > 0); + } +finished: + read_unlock(&vmlist_lock); + return buf - buf_start; +} |