Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.osdl.org>2003-10-16 07:49:17 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-10-16 07:49:17 -0700
commit0068306ff7243e3499b6190740555693313e409b (patch)
tree1e0c3e220904890bed755763c78b6a4463c728fa
parent0c13346efe1032ea13d9f21d28af815b63302c8d (diff)
parentbd2fdafae60e2dc7add363539aeb859175a5fbab (diff)
Merge http://mdomsch.bkbits.net/linux-2.5-edd
into home.osdl.org:/home/torvalds/v2.5/linux
-rw-r--r--Documentation/ia64/fsys.txt57
-rw-r--r--arch/arm/Makefile2
-rw-r--r--arch/arm/boot/Makefile20
-rw-r--r--arch/arm/boot/bootp/bootp.lds4
-rw-r--r--arch/arm/kernel/armksyms.c1
-rw-r--r--arch/arm/lib/div64.S2
-rw-r--r--arch/h8300/Kconfig2
-rw-r--r--arch/h8300/README18
-rw-r--r--arch/h8300/lib/romfs.S6
-rw-r--r--arch/h8300/platform/h8s/ints.c5
-rw-r--r--arch/i386/kernel/apic.c19
-rw-r--r--arch/i386/kernel/irq.c2
-rw-r--r--arch/i386/kernel/microcode.c537
-rw-r--r--arch/i386/kernel/mpparse.c10
-rw-r--r--arch/i386/kernel/traps.c8
-rw-r--r--arch/i386/mm/fault.c2
-rw-r--r--arch/ia64/Kconfig34
-rw-r--r--arch/ia64/Makefile2
-rw-r--r--arch/ia64/ia32/sys_ia32.c66
-rw-r--r--arch/ia64/kernel/acpi.c46
-rw-r--r--arch/ia64/kernel/asm-offsets.c18
-rw-r--r--arch/ia64/kernel/fsys.S208
-rw-r--r--arch/ia64/kernel/gate.S3
-rw-r--r--arch/ia64/kernel/head.S19
-rw-r--r--arch/ia64/kernel/mca.c30
-rw-r--r--arch/ia64/kernel/mca_asm.S288
-rw-r--r--arch/ia64/kernel/patch.c6
-rw-r--r--arch/ia64/kernel/perfmon.c573
-rw-r--r--arch/ia64/kernel/perfmon_itanium.h4
-rw-r--r--arch/ia64/kernel/perfmon_mckinley.h22
-rw-r--r--arch/ia64/kernel/setup.c74
-rw-r--r--arch/ia64/kernel/time.c13
-rw-r--r--arch/ia64/mm/contig.c134
-rw-r--r--arch/ia64/mm/discontig.c593
-rw-r--r--arch/ia64/mm/hugetlbpage.c66
-rw-r--r--arch/ia64/mm/init.c124
-rw-r--r--arch/ia64/sn/io/machvec/pci_bus_cvlink.c3
-rw-r--r--arch/ia64/sn/io/sn2/ml_SN_intr.c41
-rw-r--r--arch/ia64/sn/kernel/setup.c2
-rw-r--r--arch/ia64/sn/kernel/sn2/io.c4
-rw-r--r--arch/m68k/lib/checksum.c1
-rw-r--r--arch/m68k/sun3/sbus.c1
-rw-r--r--arch/ppc/boot/of1275/map.c9
-rw-r--r--arch/ppc/boot/openfirmware/coffmain.c4
-rw-r--r--arch/ppc/kernel/head.S48
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c8
-rw-r--r--arch/ppc/kernel/process.c1
-rw-r--r--arch/ppc/mm/hashtable.S15
-rw-r--r--arch/ppc/mm/ppc_mmu.c24
-rw-r--r--arch/ppc/platforms/pmac_smp.c102
-rw-r--r--arch/ppc/platforms/pmac_time.c8
-rw-r--r--arch/ppc/syslib/of_device.c12
-rw-r--r--arch/ppc64/kernel/head.S2
-rw-r--r--arch/ppc64/kernel/idle.c3
-rw-r--r--arch/ppc64/kernel/irq.c46
-rw-r--r--arch/ppc64/kernel/misc.S8
-rw-r--r--arch/ppc64/kernel/pacaData.c2
-rw-r--r--arch/ppc64/kernel/pci_dma.c8
-rw-r--r--arch/ppc64/kernel/ppc_ksyms.c7
-rw-r--r--arch/ppc64/kernel/sys_ppc32.c26
-rw-r--r--arch/ppc64/mm/hugetlbpage.c7
-rw-r--r--arch/ppc64/mm/init.c19
-rw-r--r--arch/ppc64/mm/numa.c20
-rw-r--r--arch/sparc64/defconfig1
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/initrd.c100
-rw-r--r--drivers/cdrom/sjcd.c22
-rw-r--r--drivers/char/agp/ali-agp.c4
-rw-r--r--drivers/char/agp/amd-k7-agp.c6
-rw-r--r--drivers/char/agp/amd64-agp.c10
-rw-r--r--drivers/char/agp/ati-agp.c6
-rw-r--r--drivers/char/agp/i460-agp.c4
-rw-r--r--drivers/char/agp/intel-agp.c4
-rw-r--r--drivers/char/agp/nvidia-agp.c4
-rw-r--r--drivers/char/agp/sis-agp.c6
-rw-r--r--drivers/char/agp/sworks-agp.c4
-rw-r--r--drivers/char/agp/uninorth-agp.c6
-rw-r--r--drivers/char/agp/via-agp.c6
-rw-r--r--drivers/char/applicom.c12
-rw-r--r--drivers/char/ite_gpio.c9
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/synclinkmp.c4
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c7
-rw-r--r--drivers/i2c/chips/w83781d.c24
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/pci/aec62xx.c4
-rw-r--r--drivers/ide/pci/cmd64x.c4
-rw-r--r--drivers/ide/pci/hpt34x.c12
-rw-r--r--drivers/ide/pci/hpt366.c4
-rw-r--r--drivers/ide/pci/it8172.c4
-rw-r--r--drivers/ide/pci/pdc202xx_new.c4
-rw-r--r--drivers/ide/pci/pdc202xx_old.c4
-rw-r--r--drivers/ide/pci/piix.c4
-rw-r--r--drivers/ide/pci/serverworks.c4
-rw-r--r--drivers/ide/pci/siimage.c4
-rw-r--r--drivers/ide/pci/sis5513.c4
-rw-r--r--drivers/ide/pci/slc90e66.c4
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c25
-rw-r--r--drivers/macintosh/adbhid.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c36
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c2
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/Space.c10
-rwxr-xr-xdrivers/net/amd8111e.c6
-rwxr-xr-xdrivers/net/amd8111e.h2
-rw-r--r--drivers/net/b44.c15
-rw-r--r--drivers/net/defxx.c4
-rw-r--r--drivers/net/e1000/e1000_main.c35
-rw-r--r--drivers/net/hamradio/bpqether.c6
-rw-r--r--drivers/net/hamradio/scc.c4
-rw-r--r--drivers/net/hp100.c10
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/net_init.c3
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c23
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/tulip/tulip_core.c1
-rw-r--r--drivers/net/tulip/xircom_cb.c35
-rw-r--r--drivers/net/wan/sealevel.c2
-rw-r--r--drivers/net/wan/syncppp.c3
-rw-r--r--drivers/net/wireless/atmel.c1
-rw-r--r--drivers/net/wireless/atmel_cs.c11
-rw-r--r--drivers/scsi/scsi_sysfs.c2
-rw-r--r--drivers/usb/host/ehci-dbg.c10
-rw-r--r--drivers/usb/host/ehci-q.c30
-rw-r--r--drivers/usb/host/ehci.h16
-rw-r--r--drivers/usb/host/ohci-hcd.c54
-rw-r--r--drivers/usb/host/ohci-hub.c2
-rw-r--r--drivers/usb/host/ohci-pci.c44
-rw-r--r--drivers/usb/host/ohci-q.c23
-rw-r--r--drivers/usb/host/ohci.h5
-rw-r--r--drivers/usb/input/Kconfig1
-rw-r--r--drivers/usb/serial/keyspan_usa90msg.h16
-rw-r--r--drivers/usb/serial/visor.c3
-rw-r--r--drivers/video/imsttfb.c14
-rw-r--r--fs/Kconfig4
-rw-r--r--fs/ext2/acl.c2
-rw-r--r--fs/ext3/acl.c2
-rw-r--r--fs/ext3/inode.c17
-rw-r--r--fs/inode.c2
-rw-r--r--fs/jffs2/background.c48
-rw-r--r--fs/jffs2/build.c61
-rw-r--r--fs/jffs2/compr.c4
-rw-r--r--fs/jffs2/compr_rtime.c4
-rw-r--r--fs/jffs2/compr_zlib.c6
-rw-r--r--fs/jffs2/dir.c100
-rw-r--r--fs/jffs2/erase.c9
-rw-r--r--fs/jffs2/file.c171
-rw-r--r--fs/jffs2/fs.c212
-rw-r--r--fs/jffs2/gc.c197
-rw-r--r--fs/jffs2/ioctl.c4
-rw-r--r--fs/jffs2/malloc.c6
-rw-r--r--fs/jffs2/nodelist.c6
-rw-r--r--fs/jffs2/nodelist.h63
-rw-r--r--fs/jffs2/nodemgmt.c93
-rw-r--r--fs/jffs2/os-linux.h28
-rw-r--r--fs/jffs2/pushpull.h4
-rw-r--r--fs/jffs2/read.c17
-rw-r--r--fs/jffs2/readinode.c6
-rw-r--r--fs/jffs2/scan.c32
-rw-r--r--fs/jffs2/super.c34
-rw-r--r--fs/jffs2/symlink.c4
-rw-r--r--fs/jffs2/wbuf.c709
-rw-r--r--fs/jffs2/write.c165
-rw-r--r--fs/jffs2/writev.c4
-rw-r--r--fs/proc/array.c10
-rw-r--r--fs/reiserfs/procfs.c7
-rw-r--r--include/asm-h8300/semaphore.h12
-rw-r--r--include/asm-i386/div64.h9
-rw-r--r--include/asm-i386/mach-numaq/mach_mpparse.h13
-rw-r--r--include/asm-i386/processor.h28
-rw-r--r--include/asm-ia64/asmmacro.h23
-rw-r--r--include/asm-ia64/delay.h7
-rw-r--r--include/asm-ia64/machvec_sn2.h2
-rw-r--r--include/asm-ia64/mca.h2
-rw-r--r--include/asm-ia64/mca_asm.h3
-rw-r--r--include/asm-ia64/meminit.h21
-rw-r--r--include/asm-ia64/mmzone.h160
-rw-r--r--include/asm-ia64/nodedata.h36
-rw-r--r--include/asm-ia64/numa.h15
-rw-r--r--include/asm-ia64/page.h18
-rw-r--r--include/asm-ia64/pal.h12
-rw-r--r--include/asm-ia64/percpu.h2
-rw-r--r--include/asm-ia64/perfmon.h11
-rw-r--r--include/asm-ia64/pgtable.h4
-rw-r--r--include/asm-ia64/posix_types.h2
-rw-r--r--include/asm-ia64/serial.h106
-rw-r--r--include/asm-ia64/sn/nodepda.h2
-rw-r--r--include/asm-ia64/uaccess.h4
-rw-r--r--include/asm-ia64/unistd.h22
-rw-r--r--include/asm-ppc/reg.h8
-rw-r--r--include/asm-ppc/reg_booke.h8
-rw-r--r--include/asm-ppc64/cputable.h2
-rw-r--r--include/asm-ppc64/hardirq.h2
-rw-r--r--include/asm-ppc64/io.h8
-rw-r--r--include/asm-ppc64/memory.h2
-rw-r--r--include/asm-ppc64/pci.h13
-rw-r--r--include/asm-ppc64/pgalloc.h28
-rw-r--r--include/asm-ppc64/pgtable.h5
-rw-r--r--include/asm-ppc64/processor.h140
-rw-r--r--include/asm-ppc64/siginfo.h4
-rw-r--r--include/asm-ppc64/thread_info.h6
-rw-r--r--include/asm-ppc64/uaccess.h1
-rw-r--r--include/asm-sparc/atomic.h18
-rw-r--r--include/asm-sparc/bitops.h132
-rw-r--r--include/asm-sparc/checksum.h62
-rw-r--r--include/asm-sparc/io.h97
-rw-r--r--include/asm-sparc/irq.h47
-rw-r--r--include/asm-sparc/pgtsun4.h25
-rw-r--r--include/asm-sparc/pgtsun4c.h25
-rw-r--r--include/asm-sparc/processor.h8
-rw-r--r--include/asm-sparc/ross.h64
-rw-r--r--include/asm-sparc/swift.h60
-rw-r--r--include/asm-sparc/system.h5
-rw-r--r--include/asm-sparc/tsunami.h16
-rw-r--r--include/asm-sparc/turbosparc.h46
-rw-r--r--include/asm-sparc/vac-ops.h34
-rw-r--r--include/asm-sparc/viking.h97
-rw-r--r--include/asm-x86_64/suspend.h5
-rw-r--r--include/linux/ethtool.h11
-rw-r--r--include/linux/jffs2.h6
-rw-r--r--include/linux/jffs2_fs_sb.h24
-rw-r--r--include/linux/netdevice.h6
-rw-r--r--include/linux/netfilter_bridge/ebt_among.h65
-rw-r--r--include/linux/sched.h24
-rw-r--r--include/net/syncppp.h5
-rw-r--r--init/do_mounts_initrd.c28
-rw-r--r--init/initramfs.c103
-rw-r--r--kernel/exit.c21
-rw-r--r--kernel/sched.c2
-rw-r--r--kernel/timer.c49
-rw-r--r--mm/mlock.c6
-rw-r--r--mm/slab.c2
-rw-r--r--mm/swapfile.c4
-rw-r--r--net/bridge/netfilter/Kconfig10
-rw-r--r--net/bridge/netfilter/Makefile1
-rw-r--r--net/bridge/netfilter/ebt_among.c215
-rw-r--r--net/core/dev.c7
-rw-r--r--net/core/ethtool.c49
-rw-r--r--net/ipv4/ip_gre.c4
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/ipip.c14
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c33
-rw-r--r--net/ipv4/tcp_ipv4.c46
-rw-r--r--net/ipv6/ip6_tunnel.c3
-rw-r--r--net/ipv6/sit.c3
-rwxr-xr-xscripts/makeman108
-rwxr-xr-xscripts/split-man2
-rw-r--r--security/selinux/include/security.h1
-rw-r--r--security/selinux/selinuxfs.c44
-rw-r--r--security/selinux/ss/policydb.h1
-rw-r--r--sound/oss/Kconfig4
-rw-r--r--sound/oss/ad1889.c6
-rw-r--r--sound/oss/ali5455.c8
-rw-r--r--sound/oss/cs4281/cs4281m.c11
-rw-r--r--sound/oss/cs46xx.c6
-rw-r--r--sound/oss/i810_audio.c6
-rw-r--r--sound/oss/maestro3.c4
-rw-r--r--sound/oss/swarm_cs4297a.c8
-rw-r--r--sound/oss/trident.c4
-rw-r--r--sound/oss/via82cxxx_audio.c10
264 files changed, 5211 insertions, 3495 deletions
diff --git a/Documentation/ia64/fsys.txt b/Documentation/ia64/fsys.txt
index 33e1d31e5874..28da181f9966 100644
--- a/Documentation/ia64/fsys.txt
+++ b/Documentation/ia64/fsys.txt
@@ -4,7 +4,7 @@
-----------------------------------
Started: 13-Jan-2003
- Last update: 11-Feb-2003
+ Last update: 27-Sep-2003
David Mosberger-Tang
<davidm@hpl.hp.com>
@@ -146,6 +146,12 @@ speed comes a set of restrictions:
task pointer is not considered sensitive: it's already exposed
through ar.k6).
+ o Fsyscall-handlers MUST NOT access user-memory without first
+ validating access-permission (this can be done typically via
+ probe.r.fault and/or probe.w.fault) and without guarding against
+ memory access exceptions (this can be done with the EX() macros
+ defined by asmmacro.h).
+
The above restrictions may seem draconian, but remember that it's
possible to trade off some of the restrictions by paying a slightly
higher overhead. For example, if an fsyscall-handler could benefit
@@ -229,3 +235,52 @@ PSR.ed Unchanged. Note: This bit could only have an effect if an fsys-mode
PSR.bn Unchanged. Note: fsys-mode handlers may clear the bit, if needed.
Doing so requires clearing PSR.i and PSR.ic as well.
PSR.ia Unchanged. Note: the ia64 linux kernel never sets this bit.
+
+* Using fast system calls
+
+To use fast system calls, userspace applications need simply call
+__kernel_syscall_via_epc(). For example
+
+-- example fgettimeofday() call --
+-- fgettimeofday.S --
+
+#include <asm/asmmacro.h>
+
+GLOBAL_ENTRY(fgettimeofday)
+.prologue
+.save ar.pfs, r11
+mov r11 = ar.pfs
+.body
+
+mov r2 = 0xa000000000020660;; // gate address
+ // found by inspection of System.map for the
+ // __kernel_syscall_via_epc() function. See
+ // below for how to do this for real.
+
+mov b7 = r2
+mov r15 = 1087 // gettimeofday syscall
+;;
+br.call.sptk.many b6 = b7
+;;
+
+.restore sp
+
+mov ar.pfs = r11
+br.ret.sptk.many rp;; // return to caller
+END(fgettimeofday)
+
+-- end fgettimeofday.S --
+
+In reality, getting the gate address is accomplished by two extra
+values passed via the ELF auxiliary vector (include/asm-ia64/elf.h)
+
+ o AT_SYSINFO : is the address of __kernel_syscall_via_epc()
+ o AT_SYSINFO_EHDR : is the address of the kernel gate ELF DSO
+
+The ELF DSO is a pre-linked library that is mapped in by the kernel at
+the gate page. It is a proper ELF shared object so, with a dynamic
+loader that recognises the library, you should be able to make calls to
+the exported functions within it as with any other shared library.
+AT_SYSINFO points into the kernel DSO at the
+__kernel_syscall_via_epc() function for historical reasons (it was
+used before the kernel DSO) and as a convenience.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 5991263f6f62..dcdd353b0174 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -149,7 +149,7 @@ maketools: include/asm-arm/.arch \
bzImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/zImage
-zImage Image bootpImage: vmlinux
+zImage Image bootpImage uImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
zinstall install: vmlinux
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index e087b89bd594..08df95fe5e8f 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -8,6 +8,8 @@
# Copyright (C) 1995-2002 Russell King
#
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
# Note: the following conditions must always be true:
# ZRELADDR == virt_to_phys(TEXTADDR)
# PARAMS_PHYS must be with 4MB of ZRELADDR
@@ -42,12 +44,14 @@ initrd_phys-$(CONFIG_ARCH_CDB89712) := 0x00700000
ifeq ($(CONFIG_ARCH_SA1100),y)
zreladdr-$(CONFIG_SA1111) := 0xc0208000
endif
+params_phys-$(CONFIG_ARCH_SA1100) := 0xc0000100
+initrd_phys-$(CONFIG_ARCH_SA1100) := 0xc0800000
zreladdr-$(CONFIG_ARCH_PXA) := 0xa0008000
zreladdr-$(CONFIG_ARCH_ANAKIN) := 0x20008000
zreladdr-$(CONFIG_ARCH_IOP3XX) := 0xa0008000
-params-phys-$(CONFIG_ARCH_IOP3XX) := 0xa0000100
+params_phys-$(CONFIG_ARCH_IOP3XX) := 0xa0000100
zreladdr-$(CONFIG_ARCH_ADIFCC) := 0xc0008000
-params-phys-$(CONFIG_ARCH_ADIFCC) := 0xc0000100
+params_phys-$(CONFIG_ARCH_ADIFCC) := 0xc0000100
ZRELADDR := $(zreladdr-y)
ZTEXTADDR := $(ztextaddr-y)
@@ -78,6 +82,16 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
+quite_cmd_uimage = UIMAGE $@
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
+ -C none -a $(ZRELADDR) -e $(ZRELADDR) \
+ -n 'Linux-$(KERNELRELEASE)' -d $< $@
+
+targets += uImage
+$(obj)/uImage: $(obj)/zImage
+ $(call if_changed,uimage)
+ @echo ' Image $@ is ready'
+
$(obj)/bootpImage: $(obj)/bootp/bootp FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
@@ -86,7 +100,7 @@ $(obj)/compressed/vmlinux: vmlinux FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
$(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
- $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+ $(Q)$(MAKE) $(build)=$(obj)/bootp $@
.PHONY: initrd
initrd:
diff --git a/arch/arm/boot/bootp/bootp.lds b/arch/arm/boot/bootp/bootp.lds
index 6fbd9ce0bbeb..52e375e7e7fb 100644
--- a/arch/arm/boot/bootp/bootp.lds
+++ b/arch/arm/boot/bootp/bootp.lds
@@ -16,10 +16,10 @@ SECTIONS
.text : {
_stext = .;
*(.start)
- kernel.o
+ arch/arm/boot/bootp/kernel.o
. = ALIGN(32);
initrd_start = .;
- initrd.o
+ arch/arm/boot/bootp/initrd.o
initrd_len = . - initrd_start;
. = ALIGN(32);
_etext = .;
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 676a1f07dd3e..753e80ffeade 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -131,6 +131,7 @@ EXPORT_SYMBOL(fp_init);
EXPORT_SYMBOL(__machine_arch_type);
/* networking */
+EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_nocheck);
EXPORT_SYMBOL(__csum_ipv6_magic);
diff --git a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S
index b3f42097690d..0870b84c845b 100644
--- a/arch/arm/lib/div64.S
+++ b/arch/arm/lib/div64.S
@@ -30,6 +30,8 @@ ENTRY(do_div64)
moveq lr, #1 @ only divide low bits
moveq nh, onl
+ tst dh, #0x80000000
+ bne 2f
1: cmp nh, dh
bls 2f
add lr, lr, #1
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 769b98b63eaf..b22293926b34 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -341,8 +341,8 @@ config UNIX98_PTY_COUNT
endmenu
-#source drivers/misc/Config.in
source "drivers/media/Kconfig"
+source "sound/Kconfig"
source "fs/Kconfig"
diff --git a/arch/h8300/README b/arch/h8300/README
index 6455ad925119..2fd6f6d7a019 100644
--- a/arch/h8300/README
+++ b/arch/h8300/README
@@ -1,9 +1,8 @@
-uClinux-2.4 for H8/300 README
+linux-2.6 for H8/300 README
Yoshinori Sato <ysato@users.sourceforge.jp>
* Supported CPU
-H8/300H
-H8S is planning.
+H8/300H and H8S
* Supported Target
1.simulator of GDB
@@ -15,8 +14,11 @@ H8S is planning.
Akizuki Denshi Tsusho Ltd. <http://www.akizuki.ne.jp> (Japanese Only)
3.H8MAX
- Under development
- see http://www.strawberry-linux.com (Japanese Only)
+ see http://ip-sol.jp/h8max/ (Japanese Only)
+
+4.EDOSK2674
+ see http://www.eu.renesas.com/products/mpumcu/tool/edk/support/edosk2674.html
+ http://www.azpower.com/H8-uClinux/
* Toolchain Version
gcc-3.1 or higher and patch
@@ -26,10 +28,10 @@ gdb-5.2 or higher
The environment that can compile a h8300-elf binary is necessary.
* Userland Develop environment
-Tempolary used h8300-hms(h8300-coff) Toolchain.
-I prepare toolchain corresponding to h8300-elf.
+used h8300-elf toolchains.
+see http://www.uclinux.org/pub/uClinux/ports/h8/
* A few words of thanks
-Porting to H8/300H is support of Information-technology Promotion Agency, Japan.
+Porting to H8/300 serieses is support of Information-technology Promotion Agency, Japan.
I thank support.
and All developer/user.
diff --git a/arch/h8300/lib/romfs.S b/arch/h8300/lib/romfs.S
index 844f1169719e..b72f93a47e31 100644
--- a/arch/h8300/lib/romfs.S
+++ b/arch/h8300/lib/romfs.S
@@ -1,6 +1,7 @@
/* romfs move to __ebss */
#include <asm/linkage.h>
+#include <linux/config.h>
#if defined(__H8300H__)
.h8300h
@@ -9,6 +10,8 @@
.h8300s
#endif
+#define BLKOFFSET 512
+
.text
.globl __move_romfs
_romfs_sig_len = 8
@@ -31,6 +34,9 @@ __move_romfs:
add.l er0,er1 /* romfs image end */
mov.l #__ebss,er2
add.l er0,er2 /* distination address */
+#if defined(CONFIG_INTELFLASH)
+ add.l #BLKOFFSET,er2
+#endif
adds #2,er0
adds #1,er0
shlr er0
diff --git a/arch/h8300/platform/h8s/ints.c b/arch/h8300/platform/h8s/ints.c
index 727f965d28a1..84ab5adb946a 100644
--- a/arch/h8300/platform/h8s/ints.c
+++ b/arch/h8300/platform/h8s/ints.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/h8300/platform/h8sh/ints.c
+ * linux/arch/h8300/platform/h8s/ints.c
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
*
@@ -20,7 +20,6 @@
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/bootmem.h>
#include <linux/random.h>
@@ -75,7 +74,7 @@ const static struct irq_pins irq_assign_table1[16]={
{H8300_GPIO_P2,H8300_GPIO_B6},{H8300_GPIO_P2,H8300_GPIO_B7},
};
-static int use_kmalloc;
+static short use_kmalloc = 0;
extern unsigned long *interrupt_redirect_table;
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 2639c2026700..97ac569c8b5e 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -533,14 +533,19 @@ static int lapic_resume(struct sys_device *dev)
if (!apic_pm_state.active)
return 0;
- /* XXX: Pavel needs this for S3 resume, but can't explain why */
- set_fixmap_nocache(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
-
local_irq_save(flags);
+
+ /*
+ * Make sure the APICBASE points to the right address
+ *
+ * FIXME! This will be wrong if we ever support suspend on
+ * SMP! We'll need to do this as part of the CPU restore!
+ */
rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_BASE;
- l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+ l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
wrmsr(MSR_IA32_APICBASE, l, h);
+
apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
apic_write(APIC_ID, apic_pm_state.apic_id);
apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -680,6 +685,12 @@ static int __init detect_init_APIC (void)
}
set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+
+ /* The BIOS may have set up the APIC at some other address */
+ rdmsr(MSR_IA32_APICBASE, l, h);
+ if (l & MSR_IA32_APICBASE_ENABLE)
+ mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
+
if (nmi_watchdog != NMI_NONE)
nmi_watchdog = NMI_LOCAL_APIC;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index ec718b194847..1525cf779ecf 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -380,7 +380,7 @@ void enable_irq(unsigned int irq)
spin_lock_irqsave(&desc->lock, flags);
switch (desc->depth) {
case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
+ unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS);
desc->status = status;
if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
desc->status = status | IRQ_REPLAY;
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index a58ad2a9f4d2..cb82c3d398aa 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -55,10 +55,18 @@
* Tigran Aivazian <tigran@veritas.com>,
* Serialize updates as required on HT processors due to speculative
* nature of implementation.
- * 1.11 22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ * 1.11 22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
* Fix the panic when writing zero-length microcode chunk.
+ * 1.12 29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * Support for the microcode updates in the new format.
+ * 1.13 10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ * because we no longer hold a copy of applied microcode
+ * in kernel memory.
*/
+
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
@@ -72,264 +80,387 @@
#include <asm/uaccess.h>
#include <asm/processor.h>
-
-static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
-
-#define MICROCODE_VERSION "1.11"
-
MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
MODULE_LICENSE("GPL");
-#define MICRO_DEBUG 0
-
+#define MICROCODE_VERSION "1.13"
+#define MICRO_DEBUG 0
#if MICRO_DEBUG
-#define printf(x...) printk(##x)
+#define dprintk(x...) printk(KERN_INFO x)
#else
-#define printf(x...)
+#define dprintk(x...)
#endif
-/* read()/write()/ioctl() are serialized on this */
-static DECLARE_RWSEM(microcode_rwsem);
-
-static struct microcode *microcode; /* array of 2048byte microcode blocks */
-static unsigned int microcode_num; /* number of chunks in microcode */
-static char *mc_applied; /* array of applied microcode blocks */
-static unsigned int mc_fsize; /* file size of /dev/cpu/microcode */
+#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
+#define MC_HEADER_SIZE (sizeof (microcode_header_t)) /* 48 bytes */
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
+#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */
+#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */
+#define DWSIZE (sizeof (u32))
+#define get_totalsize(mc) \
+ (((microcode_t *)mc)->hdr.totalsize ? \
+ ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
+#define get_datasize(mc) \
+ (((microcode_t *)mc)->hdr.datasize ? \
+ ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+#define sigmatch(s1, s2, p1, p2) (((s1) == (s2)) && ((p1) & (p2)))
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
-static int microcode_open(struct inode *unused1, struct file *unused2)
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DECLARE_MUTEX(microcode_sem);
+
+static void *user_buffer; /* user area microcode data buffer */
+static unsigned int user_buffer_size; /* it's size */
+
+typedef enum mc_error_code {
+ MC_SUCCESS = 0,
+ MC_NOTFOUND = 1,
+ MC_MARKED = 2,
+ MC_ALLOCATED = 3,
+} mc_error_code_t;
+
+static struct ucode_cpu_info {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int rev;
+ unsigned int cksum;
+ mc_error_code_t err;
+ microcode_t *mc;
+} ucode_cpu_info[NR_CPUS];
+
+static int microcode_open (struct inode *unused1, struct file *unused2)
{
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
-/*
- * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
- * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
- */
-struct update_req {
- int err;
- int slot;
-} update_req[NR_CPUS];
-
-static void do_update_one(void *unused)
+static void collect_cpu_info (void *unused)
{
int cpu_num = smp_processor_id();
struct cpuinfo_x86 *c = cpu_data + cpu_num;
- struct update_req *req = update_req + cpu_num;
- unsigned int pf = 0, val[2], rev, sig;
- unsigned long flags;
- int i;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ unsigned int val[2];
- req->err = 1; /* assume update will fail on this cpu */
+ uci->sig = uci->pf = uci->rev = uci->cksum = 0;
+ uci->err = MC_NOTFOUND;
+ uci->mc = NULL;
if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
cpu_has(c, X86_FEATURE_IA64)) {
printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
return;
+ } else {
+ uci->sig = cpuid_eax(0x00000001);
+
+ if ((c->x86_model >= 5) || (c->x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ uci->pf = 1 << ((val[1] >> 18) & 7);
+ }
}
- sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
+ dprintk("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+ uci->sig, uci->pf, uci->rev);
+}
- if ((c->x86_model >= 5) || (c->x86 > 6)) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- pf = 1 << ((val[1] >> 18) & 7);
+static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_header, int sig, int pf, int cksum)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+
+ dprintk("Microcode Found.\n");
+ dprintk(" Header Revision 0x%x\n", mc_header->hdrver);
+ dprintk(" Loader Revision 0x%x\n", mc_header->ldrver);
+ dprintk(" Revision 0x%x \n", mc_header->rev);
+ dprintk(" Date %x/%x/%x\n",
+ ((mc_header->date >> 24 ) & 0xff),
+ ((mc_header->date >> 16 ) & 0xff),
+ (mc_header->date & 0xFFFF));
+ dprintk(" Signature 0x%x\n", sig);
+ dprintk(" Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
+ ((sig >> 12) & 0x3),
+ ((sig >> 8) & 0xf),
+ ((sig >> 4) & 0xf),
+ ((sig & 0xf)));
+ dprintk(" Processor Flags 0x%x\n", pf);
+ dprintk(" Checksum 0x%x\n", cksum);
+
+ if (mc_header->rev < uci->rev) {
+ printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision"
+ " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
+ goto out;
+ } else if (mc_header->rev == uci->rev) {
+ /* notify the caller of success on this cpu */
+ uci->err = MC_SUCCESS;
+ printk(KERN_ERR "microcode: CPU%d already at revision"
+ " 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
+ goto out;
}
- for (i=0; i<microcode_num; i++)
- if (microcode[i].sig == sig && microcode[i].pf == pf &&
- microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
- int sum = 0;
- struct microcode *m = &microcode[i];
- unsigned int *sump = (unsigned int *)(m+1);
-
- printf("Microcode\n");
- printf(" Header Revision %d\n",microcode[i].hdrver);
- printf(" Date %x/%x/%x\n",
- ((microcode[i].date >> 24 ) & 0xff),
- ((microcode[i].date >> 16 ) & 0xff),
- (microcode[i].date & 0xFFFF));
- printf(" Type %x Family %x Model %x Stepping %x\n",
- ((microcode[i].sig >> 12) & 0x3),
- ((microcode[i].sig >> 8) & 0xf),
- ((microcode[i].sig >> 4) & 0xf),
- ((microcode[i].sig & 0xf)));
- printf(" Checksum %x\n",microcode[i].cksum);
- printf(" Loader Revision %x\n",microcode[i].ldrver);
- printf(" Processor Flags %x\n\n",microcode[i].pf);
-
- req->slot = i;
-
- /* serialize access to update decision */
- spin_lock_irqsave(&microcode_update_lock, flags);
-
- /* trick, to work even if there was no prior update by the BIOS */
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
-
- /* get current (on-cpu) revision into rev (ignore val[0]) */
- rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
-
- if (microcode[i].rev < rev) {
- spin_unlock_irqrestore(&microcode_update_lock, flags);
- printk(KERN_INFO
- "microcode: CPU%d not 'upgrading' to earlier revision"
- " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
- return;
- } else if (microcode[i].rev == rev) {
- /* notify the caller of success on this cpu */
- req->err = 0;
- spin_unlock_irqrestore(&microcode_update_lock, flags);
- printk(KERN_INFO
- "microcode: CPU%d already at revision"
- " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
- return;
- }
+ dprintk("microcode: CPU%d found a matching microcode update with "
+ " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
+ uci->cksum = cksum;
+ uci->pf = pf; /* keep the original mc pf for cksum calculation */
+ uci->err = MC_MARKED; /* found the match */
+out:
+ return;
+}
+
+static int find_matching_ucodes (void)
+{
+ int cursor = 0;
+ int error = 0;
+
+ while (cursor + MC_HEADER_SIZE < user_buffer_size) {
+ microcode_header_t mc_header;
+ void *newmc = NULL;
+ int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size;
+
+ if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ error = -EFAULT;
+ goto out;
+ }
+
+ total_size = get_totalsize(&mc_header);
+ if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ error = -EINVAL;
+ goto out;
+ }
+
+ data_size = get_datasize(&mc_header);
+ if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ error = -EINVAL;
+ goto out;
+ }
- /* Verify the checksum */
- while (--sump >= (unsigned int *)m)
- sum += *sump;
- if (sum != 0) {
- req->err = 1;
- spin_unlock_irqrestore(&microcode_update_lock, flags);
- printk(KERN_ERR "microcode: CPU%d aborting, "
- "bad checksum\n", cpu_num);
- return;
+ if (mc_header.ldrver != 1 || mc_header.hdrver != 1) {
+ printk(KERN_ERR "microcode: error! Unknown microcode update format\n");
+ error = -EINVAL;
+ goto out;
+ }
+
+ for (cpu_num = 0; cpu_num < num_online_cpus(); cpu_num++) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
+ continue;
+
+ if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->pf))
+ mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum);
+ }
+
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ struct extended_sigtable ext_header;
+ struct extended_signature ext_sig;
+ int ext_sigcount;
+
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ error = -EINVAL;
+ goto out;
+ }
+ if (copy_from_user(&ext_header, user_buffer + cursor
+ + MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ error = -EFAULT;
+ goto out;
+ }
+ if (ext_table_size != exttable_size(&ext_header)) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ error = -EFAULT;
+ goto out;
}
+
+ ext_sigcount = ext_header.count;
- /* write microcode via MSR 0x79 */
- wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
-
- /* serialize */
- __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
-
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
- /* notify the caller of success on this cpu */
- req->err = 0;
- spin_unlock_irqrestore(&microcode_update_lock, flags);
- printk(KERN_INFO "microcode: CPU%d updated from revision "
- "%d to %d, date=%08x\n",
- cpu_num, rev, val[1], microcode[i].date);
- return;
+ for (i = 0; i < ext_sigcount; i++) {
+ if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE
+ + EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ error = -EFAULT;
+ goto out;
+ }
+ for (cpu_num = 0; cpu_num < num_online_cpus(); cpu_num++) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/
+ continue;
+ if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->pf)) {
+ mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);
+ }
+ }
+ }
}
-
- printk(KERN_ERR
- "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
- cpu_num, sig, pf);
+ /* now check if any cpu has matched */
+ for (cpu_num = 0, allocated_flag = 0, sum = 0; cpu_num < num_online_cpus(); cpu_num++) {
+ if (ucode_cpu_info[cpu_num].err == MC_MARKED) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+ if (!allocated_flag) {
+ allocated_flag = 1;
+ newmc = vmalloc(total_size);
+ if (!newmc) {
+ printk(KERN_ERR "microcode: error! Can not allocate memory\n");
+ error = -ENOMEM;
+ goto out;
+ }
+ if (copy_from_user(newmc + MC_HEADER_SIZE,
+ user_buffer + cursor + MC_HEADER_SIZE,
+ total_size - MC_HEADER_SIZE)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ vfree(newmc);
+ error = -EFAULT;
+ goto out;
+ }
+ memcpy(newmc, &mc_header, MC_HEADER_SIZE);
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ i = ext_table_size / DWSIZE;
+ int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);
+ while (i--) ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n");
+ vfree(newmc);
+ error = -EINVAL;
+ goto out;
+ }
+ }
+
+ /* calculate the checksum */
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--) sum += ((int *)newmc)[i];
+ sum -= (mc_header.sig + mc_header.pf + mc_header.cksum);
+ }
+ ucode_cpu_info[cpu_num].mc = newmc;
+ ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */
+ if (sum + uci->sig + uci->pf + uci->cksum != 0) {
+ printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num);
+ error = -EINVAL;
+ goto out;
+ }
+ }
+ }
+ cursor += total_size; /* goto the next update patch */
+ } /* end of while */
+out:
+ return error;
}
-
-static int do_microcode_update(void)
+static void do_update_one (void * unused)
{
- int i, error = 0, err;
- struct microcode *m;
+ unsigned long flags;
+ unsigned int val[2];
+ int cpu_num = smp_processor_id();
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) {
- printk(KERN_ERR "microcode: IPI timeout, giving up\n");
- return -EIO;
+ if (uci->mc == NULL) {
+ printk(KERN_INFO "microcode: No suitable data for cpu %d\n", cpu_num);
+ return;
}
- for (i=0; i<NR_CPUS; i++) {
- err = update_req[i].err;
- error += err;
- if (!err) {
- m = (struct microcode *)mc_applied + i;
- memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
- }
- }
- return error;
+ /* serialize access to the physical write to MSR 0x79 */
+ spin_lock_irqsave(&microcode_update_lock, flags);
+
+ /* write microcode via MSR 0x79 */
+ wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(uci->mc->bits), 0);
+ wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+ __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+ /* get the current revision from MSR 0x8B */
+ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+ /* notify the caller of success on this cpu */
+ uci->err = MC_SUCCESS;
+ spin_unlock_irqrestore(&microcode_update_lock, flags);
+ printk(KERN_INFO "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x, date = %08x \n",
+ cpu_num, uci->rev, val[1], uci->mc->hdr.date);
+ return;
}
-static ssize_t microcode_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
+static int do_microcode_update (void)
{
- ssize_t ret = 0;
+ int i, error;
- down_read(&microcode_rwsem);
- if (*ppos >= mc_fsize)
- goto out;
- if (*ppos + len > mc_fsize)
- len = mc_fsize - *ppos;
- ret = -EFAULT;
- if (copy_to_user(buf, mc_applied + *ppos, len))
+ if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) {
+ printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
+ error = -EIO;
goto out;
- *ppos += len;
- ret = len;
+ }
+
+ if ((error = find_matching_ucodes())) {
+ printk(KERN_ERR "microcode: Error in the microcode data\n");
+ goto out_free;
+ }
+
+ if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) {
+ printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
+ error = -EIO;
+ }
+
+out_free:
+ for (i = 0; i < num_online_cpus(); i++) {
+ if (ucode_cpu_info[i].mc) {
+ int j;
+ void *tmp = ucode_cpu_info[i].mc;
+ vfree(tmp);
+ for (j = i; j < num_online_cpus(); j++) {
+ if (ucode_cpu_info[j].mc == tmp)
+ ucode_cpu_info[j].mc = NULL;
+ }
+ }
+ }
out:
- up_read(&microcode_rwsem);
- return ret;
+ return error;
}
-static ssize_t microcode_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
+static ssize_t microcode_write (struct file *file, const char *buf, size_t len, loff_t *ppos)
{
ssize_t ret;
- if (!len || len % sizeof(struct microcode) != 0) {
- printk(KERN_ERR "microcode: can only write in N*%d bytes units\n",
- sizeof(struct microcode));
+ if (len < DEFAULT_UCODE_TOTALSIZE) {
+ printk(KERN_ERR "microcode: not enough data\n");
return -EINVAL;
}
+
if ((len >> PAGE_SHIFT) > num_physpages) {
printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
return -EINVAL;
}
- down_write(&microcode_rwsem);
- if (!mc_applied) {
- mc_applied = kmalloc(NR_CPUS*sizeof(struct microcode),
- GFP_KERNEL);
- if (!mc_applied) {
- up_write(&microcode_rwsem);
- printk(KERN_ERR "microcode: out of memory for saved microcode\n");
- return -ENOMEM;
- }
- }
-
- microcode_num = len/sizeof(struct microcode);
- microcode = vmalloc(len);
- if (!microcode) {
- ret = -ENOMEM;
- goto out_unlock;
- }
- if (copy_from_user(microcode, buf, len)) {
- ret = -EFAULT;
- goto out_fsize;
- }
+ down(&microcode_sem);
- if(do_microcode_update()) {
- ret = -EIO;
- goto out_fsize;
- } else {
- mc_fsize = NR_CPUS * sizeof(struct microcode);
+ user_buffer = (void *) buf;
+ user_buffer_size = (int) len;
+
+ ret = do_microcode_update();
+ if (!ret)
ret = (ssize_t)len;
- }
-out_fsize:
- vfree(microcode);
-out_unlock:
- up_write(&microcode_rwsem);
+
+ up(&microcode_sem);
+
return ret;
}
-static int microcode_ioctl(struct inode *inode, struct file *file,
+static int microcode_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- switch(cmd) {
+ switch (cmd) {
+ /*
+ * XXX: will be removed after microcode_ctl
+ * is updated to ignore failure of this ioctl()
+ */
case MICROCODE_IOCFREE:
- down_write(&microcode_rwsem);
- if (mc_applied) {
- int bytes = NR_CPUS * sizeof(struct microcode);
-
- kfree(mc_applied);
- mc_applied = NULL;
- printk(KERN_INFO "microcode: freed %d bytes\n", bytes);
- mc_fsize = 0;
- up_write(&microcode_rwsem);
- return 0;
- }
- up_write(&microcode_rwsem);
- return -ENODATA;
-
+ return 0;
default:
return -EINVAL;
}
@@ -338,7 +469,6 @@ static int microcode_ioctl(struct inode *inode, struct file *file,
static struct file_operations microcode_fops = {
.owner = THIS_MODULE,
- .read = microcode_read,
.write = microcode_write,
.ioctl = microcode_ioctl,
.open = microcode_open,
@@ -347,17 +477,20 @@ static struct file_operations microcode_fops = {
static struct miscdevice microcode_dev = {
.minor = MICROCODE_MINOR,
.name = "microcode",
- .devfs_name = "cpu/microcode",
.fops = &microcode_fops,
};
-static int __init microcode_init(void)
+static int __init microcode_init (void)
{
int error;
error = misc_register(&microcode_dev);
- if (error)
+ if (error) {
+ printk(KERN_ERR
+ "microcode: can't misc_register on minor=%d\n",
+ MICROCODE_MINOR);
return error;
+ }
printk(KERN_INFO
"IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n",
@@ -365,14 +498,12 @@ static int __init microcode_init(void)
return 0;
}
-static void __exit microcode_exit(void)
+static void __exit microcode_exit (void)
{
misc_deregister(&microcode_dev);
- kfree(mc_applied);
printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n",
MICROCODE_VERSION);
}
module_init(microcode_init)
module_exit(microcode_exit)
-
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index f33d06c3b89f..ac55df3baae0 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -337,6 +337,16 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \
}
}
}
+
+static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
+ char *productid)
+{
+ if (strncmp(oem, "IBM NUMA", 8))
+ printk("Warning! May not be a NUMA-Q system!\n");
+ if (mpc->mpc_oemptr)
+ smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr,
+ mpc->mpc_oemsize);
+}
#endif /* CONFIG_X86_NUMAQ */
/*
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index db4e89ef4cbc..f86037183b98 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -104,7 +104,7 @@ void show_trace(struct task_struct *task, unsigned long * stack)
#ifdef CONFIG_KALLSYMS
printk("\n");
#endif
- while (((long) stack & (THREAD_SIZE-1)) != 0) {
+ while (!kstack_end(stack)) {
addr = *stack++;
if (kernel_text_address(addr)) {
printk(" [<%08lx>] ", addr);
@@ -138,7 +138,7 @@ void show_stack(struct task_struct *task, unsigned long *esp)
stack = esp;
for(i = 0; i < kstack_depth_to_print; i++) {
- if (((long) stack & (THREAD_SIZE-1)) == 0)
+ if (kstack_end(stack))
break;
if (i && ((i % 8) == 0))
printk("\n ");
@@ -374,6 +374,9 @@ DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
+ if (regs->eflags & X86_EFLAGS_IF)
+ local_irq_enable();
+
if (regs->eflags & VM_MASK)
goto gp_in_vm86;
@@ -386,6 +389,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
return;
gp_in_vm86:
+ local_irq_enable();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
return;
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 6ad63aadfaf0..b05a10a9a69f 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -223,7 +223,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
__asm__("movl %%cr2,%0":"=r" (address));
/* It's safe to allow irq's after cr2 has been saved */
- if (regs->eflags & X86_EFLAGS_IF)
+ if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
local_irq_enable();
tsk = current;
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index cd15f8b01c18..2f76c036f01b 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -57,6 +57,10 @@ choice
config IA64_GENERIC
bool "generic"
+ select NUMA
+ select ACPI_NUMA
+ select VIRTUAL_MEM_MAP
+ select DISCONTIGMEM
---help---
This selects the system type of your hardware. A "generic" kernel
will run on any supported IA-64 system. However, if you configure
@@ -220,24 +224,8 @@ config NUMA
Access). This option is for configuring high-end multiprocessor
server systems. If in doubt, say N.
-choice
- prompt "Maximum Memory per NUMA Node" if NUMA && IA64_DIG
- depends on NUMA && IA64_DIG
- default IA64_NODESIZE_16GB
-
-config IA64_NODESIZE_16GB
- bool "16GB"
-
-config IA64_NODESIZE_64GB
- bool "64GB"
-
-config IA64_NODESIZE_256GB
- bool "256GB"
-
-endchoice
-
config DISCONTIGMEM
- bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA
+ bool "Discontiguous memory support" if (IA64_DIG || IA64_SGI_SN2 || IA64_GENERIC) && NUMA && VIRTUAL_MEM_MAP
default y if (IA64_SGI_SN2 || IA64_GENERIC) && NUMA
help
Say Y to support efficient handling of discontiguous physical memory,
@@ -250,14 +238,10 @@ config VIRTUAL_MEM_MAP
default y if !IA64_HP_SIM
help
Say Y to compile the kernel with support for a virtual mem map.
- This is an alternate method of supporting large holes in the
- physical address space on non NUMA machines. Since the DISCONTIGMEM
- option is not supported on machines with the ZX1 chipset, this is
- the only way of supporting more than 1 Gb of memory on those
- machines. This code also only takes effect if a memory hole of
- greater than 1 Gb is found during boot, so it is safe to enable
- unless you require the DISCONTIGMEM option for your machine. If you
- are unsure, say Y.
+ This code also only takes effect if a memory hole of greater than
+ 1 Gb is found during boot. You must turn this option on if you
+ require the DISCONTIGMEM option for your machine. If you are
+ unsure, say Y.
config IA64_MCA
bool "Enable IA-64 Machine Check Abort"
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index fbad6558252c..f1a491a43a65 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -64,7 +64,7 @@ core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
drivers-$(CONFIG_PCI) += arch/ia64/pci/
drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/
-drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/
+drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ arch/ia64/sn/
drivers-$(CONFIG_OPROFILE) += arch/ia64/oprofile/
boot := arch/ia64/hp/sim/boot
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 71cea1bb7513..95baf7ddd117 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -2486,11 +2486,14 @@ static int
putstat64 (struct stat64 *ubuf, struct kstat *kbuf)
{
int err;
+ u64 hdev;
if (clear_user(ubuf, sizeof(*ubuf)))
return -EFAULT;
- err = __put_user(huge_encode_dev(kbuf->dev), &ubuf->st_dev);
+ hdev = huge_encode_dev(kbuf->dev);
+ err = __put_user(hdev, (u32*)&ubuf->st_dev);
+ err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_dev) + 1);
err |= __put_user(kbuf->ino, &ubuf->__st_ino);
err |= __put_user(kbuf->ino, &ubuf->st_ino_lo);
err |= __put_user(kbuf->ino >> 32, &ubuf->st_ino_hi);
@@ -2498,7 +2501,9 @@ putstat64 (struct stat64 *ubuf, struct kstat *kbuf)
err |= __put_user(kbuf->nlink, &ubuf->st_nlink);
err |= __put_user(kbuf->uid, &ubuf->st_uid);
err |= __put_user(kbuf->gid, &ubuf->st_gid);
- err |= __put_user(huge_encode_dev(kbuf->rdev), &ubuf->st_rdev);
+ hdev = huge_encode_dev(kbuf->rdev);
+ err = __put_user(hdev, (u32*)&ubuf->st_rdev);
+ err |= __put_user(hdev >> 32, ((u32*)&ubuf->st_rdev) + 1);
err |= __put_user(kbuf->size, &ubuf->st_size_lo);
err |= __put_user((kbuf->size >> 32), &ubuf->st_size_hi);
err |= __put_user(kbuf->atime.tv_sec, &ubuf->st_atime);
@@ -2724,8 +2729,8 @@ out_error:
struct epoll_event32
{
u32 events;
- u64 data;
-} __attribute__((packed));
+ u32 data[2];
+};
asmlinkage long
sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event)
@@ -2740,10 +2745,10 @@ sys32_epoll_ctl(int epfd, int op, int fd, struct epoll_event32 *event)
return error;
__get_user(event64.events, &event->events);
- __get_user(data_halfword, (u32*)(&event->data));
+ __get_user(data_halfword, &event->data[0]);
event64.data = data_halfword;
- __get_user(data_halfword, ((u32*)(&event->data) + 1));
- event64.data |= ((u64)data_halfword) << 32;
+ __get_user(data_halfword, &event->data[1]);
+ event64.data |= (u64)data_halfword << 32;
set_fs(KERNEL_DS);
error = sys_epoll_ctl(epfd, op, fd, &event64);
@@ -2758,8 +2763,9 @@ sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents,
{
struct epoll_event *events64 = NULL;
mm_segment_t old_fs = get_fs();
- int error;
+ int error, numevents, size;
int evt_idx;
+ int do_free_pages = 0;
if (maxevents <= 0) {
return -EINVAL;
@@ -2770,43 +2776,45 @@ sys32_epoll_wait(int epfd, struct epoll_event32 *events, int maxevents,
maxevents * sizeof(struct epoll_event32))))
return error;
- /* Allocate the space needed for the intermediate copy */
- events64 = kmalloc(maxevents * sizeof(struct epoll_event), GFP_KERNEL);
+ /*
+ * Allocate space for the intermediate copy. If the space needed
+ * is large enough to cause kmalloc to fail, then try again with
+ * __get_free_pages.
+ */
+ size = maxevents * sizeof(struct epoll_event);
+ events64 = kmalloc(size, GFP_KERNEL);
if (events64 == NULL) {
- return -ENOMEM;
- }
-
- /* Expand the 32-bit structures into the 64-bit structures */
- for (evt_idx = 0; evt_idx < maxevents; evt_idx++) {
- u32 data_halfword;
- __get_user(events64[evt_idx].events, &events[evt_idx].events);
- __get_user(data_halfword, (u32*)(&events[evt_idx].data));
- events64[evt_idx].data = data_halfword;
- __get_user(data_halfword, ((u32*)(&events[evt_idx].data) + 1));
- events64[evt_idx].data |= ((u64)data_halfword) << 32;
+ events64 = (struct epoll_event *)
+ __get_free_pages(GFP_KERNEL, get_order(size));
+ if (events64 == NULL)
+ return -ENOMEM;
+ do_free_pages = 1;
}
/* Do the system call */
set_fs(KERNEL_DS); /* copy_to/from_user should work on kernel mem*/
- error = sys_epoll_wait(epfd, events64, maxevents, timeout);
+ numevents = sys_epoll_wait(epfd, events64, maxevents, timeout);
set_fs(old_fs);
/* Don't modify userspace memory if we're returning an error */
- if (!error) {
+ if (numevents > 0) {
/* Translate the 64-bit structures back into the 32-bit
structures */
- for (evt_idx = 0; evt_idx < maxevents; evt_idx++) {
+ for (evt_idx = 0; evt_idx < numevents; evt_idx++) {
__put_user(events64[evt_idx].events,
&events[evt_idx].events);
- __put_user((u32)(events64[evt_idx].data),
- (u32*)(&events[evt_idx].data));
+ __put_user((u32)events64[evt_idx].data,
+ &events[evt_idx].data[0]);
__put_user((u32)(events64[evt_idx].data >> 32),
- ((u32*)(&events[evt_idx].data) + 1));
+ &events[evt_idx].data[1]);
}
}
- kfree(events64);
- return error;
+ if (do_free_pages)
+ free_pages((unsigned long) events64, get_order(size));
+ else
+ kfree(events64);
+ return numevents;
}
#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index e0b1e00bf613..d757134a2175 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -56,6 +56,7 @@ void (*pm_idle) (void);
void (*pm_power_off) (void);
unsigned char acpi_kbd_controller_present = 1;
+unsigned char acpi_legacy_devices;
int acpi_disabled; /* XXX this shouldn't be needed---we can't boot without ACPI! */
@@ -380,7 +381,7 @@ acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa)
void __init
acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma)
{
- unsigned long paddr, size, hole_size, min_hole_size;
+ unsigned long paddr, size;
u8 pxm;
struct node_memblk_s *p, *q, *pend;
@@ -402,34 +403,6 @@ acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma)
if (!ma->flags.enabled)
return;
- /*
- * When the chunk is not the first one in the node, check distance
- * from the other chunks. When the hole is too huge ignore the chunk.
- * This restriction should be removed when multiple chunks per node
- * is supported.
- */
- pend = &node_memblk[num_memblks];
- min_hole_size = 0;
- for (p = &node_memblk[0]; p < pend; p++) {
- if (p->nid != pxm)
- continue;
- if (p->start_paddr < paddr)
- hole_size = paddr - (p->start_paddr + p->size);
- else
- hole_size = p->start_paddr - (paddr + size);
-
- if (!min_hole_size || hole_size < min_hole_size)
- min_hole_size = hole_size;
- }
-
- if (min_hole_size) {
- if (min_hole_size > size) {
- printk(KERN_ERR "Too huge memory hole. Ignoring %ld MBytes at %lx\n",
- size/(1024*1024), paddr);
- return;
- }
- }
-
/* record this node in proximity bitmap */
pxm_bit_set(pxm);
@@ -454,6 +427,12 @@ acpi_numa_arch_fixup (void)
{
int i, j, node_from, node_to;
+ /* If there's no SRAT, fix the phys_id */
+ if (srat_num_cpus == 0) {
+ node_cpuid[0].phys_id = hard_smp_processor_id();
+ return;
+ }
+
/* calculate total number of nodes in system from PXM bitmap */
numnodes = 0; /* init total nodes in system */
@@ -531,6 +510,9 @@ acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
acpi_kbd_controller_present = 0;
+ if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
+ acpi_legacy_devices = 1;
+
acpi_register_irq(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
return 0;
}
@@ -614,6 +596,12 @@ acpi_boot_init (void)
smp_build_cpu_map();
# ifdef CONFIG_NUMA
+ if (srat_num_cpus == 0) {
+ int cpu, i = 1;
+ for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++)
+ if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id())
+ node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu];
+ }
build_cpu_to_node_map();
# endif
#endif
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 49c464cd04fe..08224b372f4b 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -33,16 +33,30 @@ void foo(void)
BLANK();
+ DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked));
DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid));
DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader));
+ DEFINE(IA64_TASK_PENDING_OFFSET,offsetof (struct task_struct, pending));
DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid));
DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent));
+ DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand));
+ DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal));
DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid));
DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp));
DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack));
BLANK();
+ DEFINE(IA64_SIGHAND_SIGLOCK_OFFSET,offsetof (struct sighand_struct, siglock));
+
+ BLANK();
+
+ DEFINE(IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,offsetof (struct signal_struct,
+ group_stop_count));
+ DEFINE(IA64_SIGNAL_SHARED_PENDING_OFFSET,offsetof (struct signal_struct, shared_pending));
+
+ BLANK();
+
DEFINE(IA64_PT_REGS_B6_OFFSET, offsetof (struct pt_regs, b6));
DEFINE(IA64_PT_REGS_B7_OFFSET, offsetof (struct pt_regs, b7));
DEFINE(IA64_PT_REGS_AR_CSD_OFFSET, offsetof (struct pt_regs, ar_csd));
@@ -158,6 +172,10 @@ void foo(void)
BLANK();
+ DEFINE(IA64_SIGPENDING_SIGNAL_OFFSET, offsetof (struct sigpending, signal));
+
+ BLANK();
+
DEFINE(IA64_SIGFRAME_ARG0_OFFSET, offsetof (struct sigframe, arg0));
DEFINE(IA64_SIGFRAME_ARG1_OFFSET, offsetof (struct sigframe, arg1));
DEFINE(IA64_SIGFRAME_ARG2_OFFSET, offsetof (struct sigframe, arg2));
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index dafa9bcfac4a..b3f7c0d5b983 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -4,6 +4,7 @@
* Copyright (C) 2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
+ * 25-Sep-03 davidm Implement fsys_rt_sigprocmask().
* 18-Feb-03 louisk Implement fsys_gettimeofday().
* 28-Feb-03 davidm Fixed several bugs in fsys_gettimeofday(). Tuned it some more,
* probably broke it along the way... ;-)
@@ -15,6 +16,7 @@
#include <asm/percpu.h>
#include <asm/thread_info.h>
#include <asm/sal.h>
+#include <asm/signal.h>
#include <asm/system.h>
#include <asm/unistd.h>
@@ -48,8 +50,7 @@ ENTRY(fsys_ni_syscall)
.body
mov r8=ENOSYS
mov r10=-1
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6
+ FSYS_RETURN
END(fsys_ni_syscall)
ENTRY(fsys_getpid)
@@ -66,8 +67,7 @@ ENTRY(fsys_getpid)
;;
cmp.ne p8,p0=0,r9
(p8) br.spnt.many fsys_fallback_syscall
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6
+ FSYS_RETURN
END(fsys_getpid)
ENTRY(fsys_getppid)
@@ -114,8 +114,7 @@ ENTRY(fsys_getppid)
mov r18=0 // i must not leak kernel bits...
mov r19=0 // i must not leak kernel bits...
#endif
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6
+ FSYS_RETURN
END(fsys_getppid)
ENTRY(fsys_set_tid_address)
@@ -141,8 +140,7 @@ ENTRY(fsys_set_tid_address)
;;
mov r17=0 // i must not leak kernel bits...
mov r18=0 // i must not leak kernel bits...
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6
+ FSYS_RETURN
END(fsys_set_tid_address)
/*
@@ -199,7 +197,7 @@ ENTRY(fsys_gettimeofday)
adds r10=IA64_CPUINFO_ITM_DELTA_OFFSET, r10
(p7) tnat.nz p6,p0=r33
-(p6) br.cond.spnt.few .fail
+(p6) br.cond.spnt.few .fail_einval
adds r8=IA64_CPUINFO_NSEC_PER_CYC_OFFSET, r3
movl r24=2361183241434822607 // for division hack (only for / 1000)
@@ -225,8 +223,8 @@ ENTRY(fsys_gettimeofday)
* to store the result. That's OK as long as the stores are also
* protect by EX().
*/
-EX(.fail, probe.w.fault r32, 3) // this must come _after_ NaT-check
-EX(.fail, probe.w.fault r10, 3) // this must come _after_ NaT-check
+EX(.fail_efault, probe.w.fault r32, 3) // this must come _after_ NaT-check
+EX(.fail_efault, probe.w.fault r10, 3) // this must come _after_ NaT-check
nop 0
ldf8 f10=[r8] // f10 <- local_cpu_data->nsec_per_cyc value
@@ -311,14 +309,13 @@ EX(.fail, probe.w.fault r10, 3) // this must come _after_ NaT-check
(p7) br.spnt.many 1b
// finally: r2 = sec, r3 = usec
-EX(.fail, st8 [r32]=r2)
+EX(.fail_efault, st8 [r32]=r2)
adds r9=8, r32
mov r8=r0 // success
;;
-EX(.fail, st8 [r9]=r3) // store them in the timeval struct
+EX(.fail_efault, st8 [r9]=r3) // store them in the timeval struct
mov r10=0
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6 // return to caller
+ FSYS_RETURN
/*
* Note: We are NOT clearing the scratch registers here. Since the only things
* in those registers are time-related variables and some addresses (which
@@ -326,12 +323,183 @@ EX(.fail, st8 [r9]=r3) // store them in the timeval struct
* and we should be fine.
*/
-.fail: adds r8=EINVAL, r0 // r8 = EINVAL
- adds r10=-1, r0 // r10 = -1
- MCKINLEY_E9_WORKAROUND
- br.ret.spnt.many b6 // return with r8 set to EINVAL
+.fail_einval:
+ mov r8=EINVAL // r8 = EINVAL
+ mov r10=-1 // r10 = -1
+ FSYS_RETURN
+
+.fail_efault:
+ mov r8=EFAULT // r8 = EFAULT
+ mov r10=-1 // r10 = -1
+ FSYS_RETURN
END(fsys_gettimeofday)
+/*
+ * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
+ */
+#if _NSIG_WORDS != 1
+# error Sorry, fsys_rt_sigprocmask() needs to be updated for _NSIG_WORDS != 1.
+#endif
+ENTRY(fsys_rt_sigprocmask)
+ .prologue
+ .altrp b6
+ .body
+
+ mf // ensure reading of current->blocked is ordered
+ add r2=IA64_TASK_BLOCKED_OFFSET,r16
+ add r9=TI_FLAGS+IA64_TASK_SIZE,r16
+ ;;
+ /*
+ * Since we're only reading a single word, we can do it
+ * atomically without acquiring current->sighand->siglock. To
+ * be on the safe side, we need a fully-ordered load, though:
+ */
+ ld8.acq r3=[r2] // read/prefetch current->blocked
+ ld4 r9=[r9]
+ add r31=IA64_TASK_SIGHAND_OFFSET,r16
+ ;;
+#ifdef CONFIG_SMP
+ ld8 r31=[r31] // r31 <- current->sighand
+#endif
+ and r9=TIF_ALLWORK_MASK,r9
+ tnat.nz p6,p0=r32
+ ;;
+ cmp.ne p7,p0=0,r9
+ tnat.nz.or p6,p0=r35
+ tnat.nz p8,p0=r34
+ ;;
+ cmp.ne p15,p0=r0,r34 // oset != NULL?
+ cmp.ne.or p6,p0=_NSIG_WORDS*8,r35
+ tnat.nz.or p8,p0=r33
+
+(p6) br.spnt.few .fail_einval // fail with EINVAL
+(p7) br.spnt.many fsys_fallback_syscall // got pending kernel work...
+(p8) br.spnt.few .fail_efault // fail with EFAULT
+ ;;
+
+ cmp.eq p6,p7=r0,r33 // set == NULL?
+ add r31=IA64_SIGHAND_SIGLOCK_OFFSET,r31 // r31 <- current->sighand->siglock
+(p6) br.dpnt.many .store_mask // -> short-circuit to just reading the signal mask
+
+ /* Argh, we actually have to do some work and _update_ the signal mask: */
+
+EX(.fail_efault, probe.r.fault r33, 3) // verify user has read-access to *set
+EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set
+ mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
+ ;;
+
+ rsm psr.i // mask interrupt delivery
+ mov ar.ccv=0
+ andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP
+
+#ifdef CONFIG_SMP
+ mov r17=1
+ ;;
+ cmpxchg4.acq r18=[r31],r17,ar.ccv // try to acquire the lock
+ mov r8=EINVAL // default to EINVAL
+ ;;
+ ld8 r3=[r2] // re-read current->blocked now that we hold the lock
+ cmp4.ne p6,p0=r18,r0
+(p6) br.cond.spnt.many .lock_contention
+ ;;
+#else
+ ld8 r3=[r2] // re-read current->blocked now that we hold the lock
+ mov r8=EINVAL // default to EINVAL
+#endif
+ add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
+ add r19=IA64_TASK_SIGNAL_OFFSET,r16
+ cmp4.eq p6,p0=SIG_BLOCK,r32
+ ;;
+ ld8 r19=[r19] // r19 <- current->signal
+ cmp4.eq p7,p0=SIG_UNBLOCK,r32
+ cmp4.eq p8,p0=SIG_SETMASK,r32
+ ;;
+ ld8 r18=[r18] // r18 <- current->pending.signal
+ .pred.rel.mutex p6,p7,p8
+(p6) or r3=r3,r14 // SIG_BLOCK
+(p7) andcm r3=r3,r14 // SIG_UNBLOCK
+
+(p8) mov r3=r14 // SIG_SETMASK
+(p6) mov r8=0 // clear error code
+ // recalc_sigpending()
+ add r17=IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,r19
+
+ add r19=IA64_SIGNAL_SHARED_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r19
+ ;;
+ ld4 r17=[r17] // r17 <- current->signal->group_stop_count
+(p7) mov r8=0 // clear error code
+
+ ld8 r19=[r19] // r19 <- current->signal->shared_pending
+ ;;
+ cmp4.gt p6,p7=r17,r0 // p6/p7 <- (current->signal->group_stop_count > 0)?
+(p8) mov r8=0 // clear error code
+
+ or r18=r18,r19 // r18 <- current->pending | current->signal->shared_pending
+ ;;
+ // r18 <- (current->pending | current->signal->shared_pending) & ~current->blocked:
+ andcm r18=r18,r3
+ add r9=TI_FLAGS+IA64_TASK_SIZE,r16
+ ;;
+
+(p7) cmp.ne.or.andcm p6,p7=r18,r0 // p6/p7 <- signal pending
+ mov r19=0 // i must not leak kernel bits...
+(p6) br.cond.dpnt.many .sig_pending
+ ;;
+
+1: ld4 r17=[r9] // r17 <- current->thread_info->flags
+ ;;
+ mov ar.ccv=r17
+ and r18=~_TIF_SIGPENDING,r17 // r18 <- r17 & ~(1 << TIF_SIGPENDING)
+ ;;
+
+ st8 [r2]=r3 // update current->blocked with new mask
+ cmpxchg4.acq r14=[r9],r18,ar.ccv // current->thread_info->flags <- r18
+ ;;
+ cmp.ne p6,p0=r17,r14 // update failed?
+(p6) br.cond.spnt.few 1b // yes -> retry
+
+#ifdef CONFIG_SMP
+ st4.rel [r31]=r0 // release the lock
+#endif
+ ssm psr.i
+ cmp.ne p9,p0=r8,r0 // check for bad HOW value
+ ;;
+
+ srlz.d // ensure psr.i is set again
+ mov r18=0 // i must not leak kernel bits...
+(p9) br.spnt.few .fail_einval // bail out for bad HOW value
+
+.store_mask:
+EX(.fail_efault, (p15) probe.w.fault r34, 3) // verify user has write-access to *oset
+EX(.fail_efault, (p15) st8 [r34]=r3)
+ mov r2=0 // i must not leak kernel bits...
+ mov r3=0 // i must not leak kernel bits...
+ mov r8=0 // return 0
+ mov r9=0 // i must not leak kernel bits...
+ mov r14=0 // i must not leak kernel bits...
+ mov r17=0 // i must not leak kernel bits...
+ mov r31=0 // i must not leak kernel bits...
+ FSYS_RETURN
+
+.sig_pending:
+#ifdef CONFIG_SMP
+ st4.rel [r31]=r0 // release the lock
+#endif
+ ssm psr.i
+ ;;
+ srlz.d
+ br.sptk.many fsys_fallback_syscall // with signal pending, do the heavy-weight syscall
+
+#ifdef CONFIG_SMP
+.lock_contention:
+ /* Rather than spinning here, fall back on doing a heavy-weight syscall. */
+ ssm psr.i
+ ;;
+ srlz.d
+ br.sptk.many fsys_fallback_syscall
+#endif
+END(fsys_rt_sigprocmask)
+
ENTRY(fsys_fallback_syscall)
.prologue
.altrp b6
@@ -600,7 +768,7 @@ fsyscall_table:
data8 0 // sigaltstack
data8 0 // rt_sigaction
data8 0 // rt_sigpending
- data8 0 // rt_sigprocmask
+ data8 fsys_rt_sigprocmask // rt_sigprocmask
data8 0 // rt_sigqueueinfo // 1180
data8 0 // rt_sigreturn
data8 0 // rt_sigsuspend
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 4423a2a0f177..86d91995a4d5 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -118,8 +118,7 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
mov r10=-1
mov r8=ENOSYS
- MCKINLEY_E9_WORKAROUND
- br.ret.sptk.many b6
+ FSYS_RETURN
END(__kernel_syscall_via_epc)
# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET)
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 23a1864d16bb..db5f71d05bb5 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -797,6 +797,25 @@ GLOBAL_ENTRY(ia64_switch_mode_virt)
br.ret.sptk.many rp
END(ia64_switch_mode_virt)
+GLOBAL_ENTRY(ia64_delay_loop)
+ .prologue
+{ nop 0 // work around GAS unwind info generation bug...
+ .save ar.lc,r2
+ mov r2=ar.lc
+ .body
+ ;;
+ mov ar.lc=r32
+}
+ ;;
+ // force loop to be 32-byte aligned (GAS bug means we cannot use .align
+ // inside function body without corrupting unwind info).
+{ nop 0 }
+1: br.cloop.sptk.few 1b
+ ;;
+ mov ar.lc=r2
+ br.ret.sptk.many rp
+END(ia64_delay_loop)
+
#ifdef CONFIG_IA64_BRL_EMU
/*
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 7986b6d52b74..820691dc437f 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -81,8 +81,6 @@ u64 ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16)));
u64 ia64_mca_sal_data_area[1356];
u64 ia64_tlb_functional;
u64 ia64_os_mca_recovery_successful;
-/* TODO: need to assign min-state structure to UC memory */
-u64 ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
static void ia64_mca_wakeup_ipi_wait(void);
static void ia64_mca_wakeup(int cpu);
static void ia64_mca_wakeup_all(void);
@@ -466,26 +464,6 @@ ia64_mca_register_cpev (int cpev)
#endif /* PLATFORM_MCA_HANDLERS */
/*
- * routine to process and prepare to dump min_state_save
- * information for debugging purposes.
- */
-void
-ia64_process_min_state_save (pal_min_state_area_t *pmss)
-{
- int i, max = MIN_STATE_AREA_SIZE;
- u64 *tpmss_ptr = (u64 *)pmss;
- u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
-
- for (i=0;i<max;i++) {
-
- /* copy min-state register info for eventual return to PAL */
- *return_min_state_ptr++ = *tpmss_ptr;
-
- tpmss_ptr++; /* skip to next entry */
- }
-}
-
-/*
* ia64_mca_cmc_vector_setup
*
* Setup the corrected machine check vector register in the processor and
@@ -828,7 +806,7 @@ ia64_mca_wakeup_ipi_wait(void)
irr = ia64_getreg(_IA64_REG_CR_IRR3);
break;
}
- } while (!(irr & (1 << irr_bit))) ;
+ } while (!(irr & (1UL << irr_bit))) ;
}
/*
@@ -961,9 +939,8 @@ ia64_return_to_sal_check(void)
/* Default = tell SAL to return to same context */
ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
- /* Register pointer to new min state values */
ia64_os_to_sal_handoff_state.imots_new_min_state =
- ia64_mca_min_state_save_info;
+ (u64 *)ia64_sal_to_os_handoff_state.pal_min_state;
}
/*
@@ -2154,9 +2131,6 @@ ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi,
if (slpi->valid.psi_static_struct) {
spsi = (sal_processor_static_info_t *)p_data;
- /* copy interrupted context PAL min-state info */
- ia64_process_min_state_save(&spsi->min_state_area);
-
/* Print branch register contents if valid */
if (spsi->valid.br)
ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 0318d81ea611..de46bda5d6db 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -77,12 +77,11 @@
(p6) movl r10=IA64_MCA_SAME_CONTEXT; \
(p6) add _tmp=0x18,_tmp;; \
(p6) ld8 r9=[_tmp],0x10; \
-(p6) movl r22=ia64_mca_min_state_save_info;; \
+(p6) mov r22=r0;; \
(p7) ld8 r8=[_tmp],0x08;; \
(p7) ld8 r9=[_tmp],0x08;; \
(p7) ld8 r10=[_tmp],0x08;; \
-(p7) ld8 r22=[_tmp],0x08;; \
- DATA_VA_TO_PA(r22)
+(p7) ld8 r22=[_tmp],0x08;;
// now _tmp is pointing to SAL rtn save location
@@ -97,7 +96,6 @@
.global ia64_init_stack
.global ia64_mca_sal_data_area
.global ia64_tlb_functional
- .global ia64_mca_min_state_save_info
.text
.align 16
@@ -265,15 +263,15 @@ cSaveCRs:
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r4
- mov r3=cr0 // cr.dcr
- mov r5=cr1 // cr.itm
- mov r7=cr2;; // cr.iva
+ mov r3=cr.dcr
+ mov r5=cr.itm
+ mov r7=cr.iva;;
st8 [r2]=r3,8*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;; // 48 byte rements
- mov r3=cr8;; // cr.pta
+ mov r3=cr.pta;;
st8 [r2]=r3,8*8;; // 64 byte rements
// if PSR.ic=0, reading interruption registers causes an illegal operation fault
@@ -286,23 +284,23 @@ begin_skip_intr_regs:
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r6
- mov r3=cr16 // cr.ipsr
- mov r5=cr17 // cr.isr
- mov r7=r0;; // cr.ida => cr18 (reserved)
+ mov r3=cr.ipsr
+ mov r5=cr.isr
+ mov r7=r0;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
- mov r3=cr19 // cr.iip
- mov r5=cr20 // cr.idtr
- mov r7=cr21;; // cr.iitr
+ mov r3=cr.iip
+ mov r5=cr.ifa
+ mov r7=cr.itir;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
- mov r3=cr22 // cr.iipa
- mov r5=cr23 // cr.ifs
- mov r7=cr24;; // cr.iim
+ mov r3=cr.iipa
+ mov r5=cr.ifs
+ mov r7=cr.iim;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
@@ -311,104 +309,101 @@ begin_skip_intr_regs:
st8 [r2]=r3,160;; // 160 byte rement
SkipIntrRegs:
- st8 [r2]=r0,168 // another 168 byte .
+ st8 [r2]=r0,152;; // another 152 byte .
- mov r3=cr66;; // cr.lid
- st8 [r2]=r3,40 // 40 byte rement
+ add r4=8,r2 // duplicate r2 in r4
+ add r6=2*8,r2 // duplicate r2 in r6
- mov r3=cr71;; // cr.ivr
- st8 [r2]=r3,8
-
- mov r3=cr72;; // cr.tpr
- st8 [r2]=r3,24 // 24 byte increment
-
- mov r3=r0;; // cr.eoi => cr75
- st8 [r2]=r3,168 // 168 byte inc.
-
- mov r3=r0;; // cr.irr0 => cr96
- st8 [r2]=r3,16 // 16 byte inc.
-
- mov r3=r0;; // cr.irr1 => cr98
- st8 [r2]=r3,16 // 16 byte inc.
+ mov r3=cr.lid
+// mov r5=cr.ivr // cr.ivr, don't read it
+ mov r7=cr.tpr;;
+ st8 [r2]=r3,3*8
+ st8 [r4]=r5,3*8
+ st8 [r6]=r7,3*8;;
- mov r3=r0;; // cr.irr2 => cr100
- st8 [r2]=r3,16 // 16 byte inc
+ mov r3=r0 // cr.eoi => cr67
+ mov r5=r0 // cr.irr0 => cr68
+ mov r7=r0;; // cr.irr1 => cr69
+ st8 [r2]=r3,3*8
+ st8 [r4]=r5,3*8
+ st8 [r6]=r7,3*8;;
- mov r3=r0;; // cr.irr3 => cr100
- st8 [r2]=r3,16 // 16b inc.
+ mov r3=r0 // cr.irr2 => cr70
+ mov r5=r0 // cr.irr3 => cr71
+ mov r7=cr.itv;;
+ st8 [r2]=r3,3*8
+ st8 [r4]=r5,3*8
+ st8 [r6]=r7,3*8;;
- mov r3=r0;; // cr.itv => cr114
- st8 [r2]=r3,16 // 16 byte inc.
+ mov r3=cr.pmv
+ mov r5=cr.cmcv;;
+ st8 [r2]=r3,7*8
+ st8 [r4]=r5,7*8;;
- mov r3=r0;; // cr.pmv => cr116
- st8 [r2]=r3,8
+ mov r3=r0 // cr.lrr0 => cr80
+ mov r5=r0;; // cr.lrr1 => cr81
+ st8 [r2]=r3,23*8
+ st8 [r4]=r5,23*8;;
- mov r3=r0;; // cr.lrr0 => cr117
- st8 [r2]=r3,8
-
- mov r3=r0;; // cr.lrr1 => cr118
- st8 [r2]=r3,8
-
- mov r3=r0;; // cr.cmcv => cr119
- st8 [r2]=r3,8*10;;
+ adds r2=25*8,r2;;
cSaveARs:
// save ARs
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r6
- mov r3=ar0 // ar.kro
- mov r5=ar1 // ar.kr1
- mov r7=ar2;; // ar.kr2
+ mov r3=ar.k0
+ mov r5=ar.k1
+ mov r7=ar.k2;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
- mov r3=ar3 // ar.kr3
- mov r5=ar4 // ar.kr4
- mov r7=ar5;; // ar.kr5
+ mov r3=ar.k3
+ mov r5=ar.k4
+ mov r7=ar.k5;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
- mov r3=ar6 // ar.kr6
- mov r5=ar7 // ar.kr7
+ mov r3=ar.k6
+ mov r5=ar.k7
mov r7=r0;; // ar.kr8
st8 [r2]=r3,10*8
st8 [r4]=r5,10*8
st8 [r6]=r7,10*8;; // rement by 72 bytes
- mov r3=ar16 // ar.rsc
- mov ar16=r0 // put RSE in enforced lazy mode
- mov r5=ar17 // ar.bsp
+ mov r3=ar.rsc
+ mov ar.rsc=r0 // put RSE in enforced lazy mode
+ mov r5=ar.bsp
;;
- mov r7=ar18;; // ar.bspstore
+ mov r7=ar.bspstore;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
- mov r3=ar19;; // ar.rnat
+ mov r3=ar.rnat;;
st8 [r2]=r3,8*13 // increment by 13x8 bytes
- mov r3=ar32;; // ar.ccv
+ mov r3=ar.ccv;;
st8 [r2]=r3,8*4
- mov r3=ar36;; // ar.unat
+ mov r3=ar.unat;;
st8 [r2]=r3,8*4
- mov r3=ar40;; // ar.fpsr
+ mov r3=ar.fpsr;;
st8 [r2]=r3,8*4
- mov r3=ar44;; // ar.itc
+ mov r3=ar.itc;;
st8 [r2]=r3,160 // 160
- mov r3=ar64;; // ar.pfs
+ mov r3=ar.pfs;;
st8 [r2]=r3,8
- mov r3=ar65;; // ar.lc
+ mov r3=ar.lc;;
st8 [r2]=r3,8
- mov r3=ar66;; // ar.ec
+ mov r3=ar.ec;;
st8 [r2]=r3
add r2=8*62,r2 //padding
@@ -417,7 +412,8 @@ cSaveARs:
movl r4=0x00;;
cStRR:
- mov r3=rr[r4];;
+ dep.z r5=r4,61,3;;
+ mov r3=rr[r5];;
st8 [r2]=r3,8
add r4=1,r4
br.cloop.sptk.few cStRR
@@ -501,12 +497,12 @@ restore_CRs:
ld8 r3=[r2],8*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;; // 48 byte increments
- mov cr0=r3 // cr.dcr
- mov cr1=r5 // cr.itm
- mov cr2=r7;; // cr.iva
+ mov cr.dcr=r3
+ mov cr.itm=r5
+ mov cr.iva=r7;;
ld8 r3=[r2],8*8;; // 64 byte increments
-// mov cr8=r3 // cr.pta
+// mov cr.pta=r3
// if PSR.ic=1, reading interruption registers causes an illegal operation fault
@@ -523,64 +519,66 @@ begin_rskip_intr_regs:
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
- mov cr16=r3 // cr.ipsr
- mov cr17=r5 // cr.isr is read only
-// mov cr18=r7;; // cr.ida (reserved - don't restore)
+ mov cr.ipsr=r3
+// mov cr.isr=r5 // cr.isr is read only
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
- mov cr19=r3 // cr.iip
- mov cr20=r5 // cr.idtr
- mov cr21=r7;; // cr.iitr
+ mov cr.iip=r3
+ mov cr.ifa=r5
+ mov cr.itir=r7;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
- mov cr22=r3 // cr.iipa
- mov cr23=r5 // cr.ifs
- mov cr24=r7 // cr.iim
+ mov cr.iipa=r3
+ mov cr.ifs=r5
+ mov cr.iim=r7
ld8 r3=[r2],160;; // 160 byte increment
- mov cr25=r3 // cr.iha
+ mov cr.iha=r3
rSkipIntrRegs:
- ld8 r3=[r2],168;; // another 168 byte inc.
-
- ld8 r3=[r2],40;; // 40 byte increment
- mov cr66=r3 // cr.lid
-
- ld8 r3=[r2],8;;
-// mov cr71=r3 // cr.ivr is read only
- ld8 r3=[r2],24;; // 24 byte increment
- mov cr72=r3 // cr.tpr
-
- ld8 r3=[r2],168;; // 168 byte inc.
-// mov cr75=r3 // cr.eoi
-
- ld8 r3=[r2],16;; // 16 byte inc.
-// mov cr96=r3 // cr.irr0 is read only
-
- ld8 r3=[r2],16;; // 16 byte inc.
-// mov cr98=r3 // cr.irr1 is read only
-
- ld8 r3=[r2],16;; // 16 byte inc
-// mov cr100=r3 // cr.irr2 is read only
-
- ld8 r3=[r2],16;; // 16b inc.
-// mov cr102=r3 // cr.irr3 is read only
-
- ld8 r3=[r2],16;; // 16 byte inc.
-// mov cr114=r3 // cr.itv
-
- ld8 r3=[r2],8;;
-// mov cr116=r3 // cr.pmv
- ld8 r3=[r2],8;;
-// mov cr117=r3 // cr.lrr0
- ld8 r3=[r2],8;;
-// mov cr118=r3 // cr.lrr1
- ld8 r3=[r2],8*10;;
-// mov cr119=r3 // cr.cmcv
+ ld8 r3=[r2],152;; // another 152 byte inc.
+
+ add r4=8,r2 // duplicate r2 in r4
+ add r6=2*8,r2;; // duplicate r2 in r6
+
+ ld8 r3=[r2],8*3
+ ld8 r5=[r4],8*3
+ ld8 r7=[r6],8*3;;
+ mov cr.lid=r3
+// mov cr.ivr=r5 // cr.ivr is read only
+ mov cr.tpr=r7;;
+
+ ld8 r3=[r2],8*3
+ ld8 r5=[r4],8*3
+ ld8 r7=[r6],8*3;;
+// mov cr.eoi=r3
+// mov cr.irr0=r5 // cr.irr0 is read only
+// mov cr.irr1=r7;; // cr.irr1 is read only
+
+ ld8 r3=[r2],8*3
+ ld8 r5=[r4],8*3
+ ld8 r7=[r6],8*3;;
+// mov cr.irr2=r3 // cr.irr2 is read only
+// mov cr.irr3=r5 // cr.irr3 is read only
+ mov cr.itv=r7;;
+
+ ld8 r3=[r2],8*7
+ ld8 r5=[r4],8*7;;
+ mov cr.pmv=r3
+ mov cr.cmcv=r5;;
+
+ ld8 r3=[r2],8*23
+ ld8 r5=[r4],8*23;;
+ adds r2=8*23,r2
+ adds r4=8*23,r4;;
+// mov cr.lrr0=r3
+// mov cr.lrr1=r5
+
+ adds r2=8*2,r2;;
restore_ARs:
add r4=8,r2 // duplicate r2 in r4
@@ -589,67 +587,67 @@ restore_ARs:
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
- mov ar0=r3 // ar.kro
- mov ar1=r5 // ar.kr1
- mov ar2=r7;; // ar.kr2
+ mov ar.k0=r3
+ mov ar.k1=r5
+ mov ar.k2=r7;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
- mov ar3=r3 // ar.kr3
- mov ar4=r5 // ar.kr4
- mov ar5=r7;; // ar.kr5
+ mov ar.k3=r3
+ mov ar.k4=r5
+ mov ar.k5=r7;;
ld8 r3=[r2],10*8
ld8 r5=[r4],10*8
ld8 r7=[r6],10*8;;
- mov ar6=r3 // ar.kr6
- mov ar7=r5 // ar.kr7
-// mov ar8=r6 // ar.kr8
+ mov ar.k6=r3
+ mov ar.k7=r5
;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
-// mov ar16=r3 // ar.rsc
-// mov ar17=r5 // ar.bsp is read only
- mov ar16=r0 // make sure that RSE is in enforced lazy mode
+// mov ar.rsc=r3
+// mov ar.bsp=r5 // ar.bsp is read only
+ mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode
;;
- mov ar18=r7;; // ar.bspstore
+ mov ar.bspstore=r7;;
ld8 r9=[r2],8*13;;
- mov ar19=r9 // ar.rnat
+ mov ar.rnat=r9
- mov ar16=r3 // ar.rsc
+ mov ar.rsc=r3
ld8 r3=[r2],8*4;;
- mov ar32=r3 // ar.ccv
+ mov ar.ccv=r3
ld8 r3=[r2],8*4;;
- mov ar36=r3 // ar.unat
+ mov ar.unat=r3
ld8 r3=[r2],8*4;;
- mov ar40=r3 // ar.fpsr
+ mov ar.fpsr=r3
ld8 r3=[r2],160;; // 160
-// mov ar44=r3 // ar.itc
+// mov ar.itc=r3
ld8 r3=[r2],8;;
- mov ar64=r3 // ar.pfs
+ mov ar.pfs=r3
ld8 r3=[r2],8;;
- mov ar65=r3 // ar.lc
+ mov ar.lc=r3
ld8 r3=[r2];;
- mov ar66=r3 // ar.ec
+ mov ar.ec=r3
add r2=8*62,r2;; // padding
restore_RRs:
mov r5=ar.lc
mov ar.lc=0x08-1
- movl r4=0x00
+ movl r4=0x00;;
cStRRr:
+ dep.z r7=r4,61,3
ld8 r3=[r2],8;;
-// mov rr[r4]=r3 // what are its access previledges?
+ mov rr[r7]=r3 // what are its access previledges?
add r4=1,r4
br.cloop.sptk.few cStRRr
;;
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index 02470da36bcd..ca9b8a3f7dc8 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -130,9 +130,11 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
while (offp < (s32 *) end) {
wp = (u64 *) ia64_imva((char *) offp + *offp);
- wp[0] = 0x0000000100000000;
+ wp[0] = 0x0000000100000000; /* nop.m 0; nop.i 0; nop.i 0 */
wp[1] = 0x0004000000000200;
- ia64_fc(wp);
+ wp[2] = 0x0000000100000011; /* nop.m 0; nop.i 0; br.ret.sptk.many b6 */
+ wp[3] = 0x0084006880000200;
+ ia64_fc(wp); ia64_fc(wp + 2);
++offp;
}
ia64_sync_i();
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index c5d8dcb5ddf9..b4bfd6d7cbb2 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -140,7 +140,7 @@
* in UP:
* - we need to protect against PMU overflow interrupts (local_irq_disable)
*
- * spin_lock_irqsave()/spin_unlock_irqrestore():
+ * spin_lock_irqsave()/spin_lock_irqrestore():
* in SMP: local_irq_disable + spin_lock
* in UP : local_irq_disable
*
@@ -254,7 +254,6 @@ typedef struct {
unsigned long seed; /* seed for random-number generator */
unsigned long mask; /* mask for random-number generator */
unsigned int flags; /* notify/do not notify */
- int next_reset_type;/* PFM_PMD_NO_RESET, PFM_PMD_LONG_RESET, PFM_PMD_SHORT_RESET */
unsigned long eventid; /* overflow event identifier */
} pfm_counter_t;
@@ -267,10 +266,10 @@ typedef struct {
unsigned int using_dbreg:1; /* using range restrictions (debug registers) */
unsigned int is_sampling:1; /* true if using a custom format */
unsigned int excl_idle:1; /* exclude idle task in system wide session */
- unsigned int unsecure:1; /* exclude idle task in system wide session */
unsigned int going_zombie:1; /* context is zombie (MASKED+blocking) */
unsigned int trap_reason:2; /* reason for going into pfm_handle_work() */
unsigned int no_msg:1; /* no message sent on overflow */
+ unsigned int can_restart:1; /* allowed to issue a PFM_RESTART */
unsigned int reserved:22;
} pfm_context_flags_t;
@@ -356,10 +355,10 @@ typedef struct pfm_context {
#define ctx_fl_using_dbreg ctx_flags.using_dbreg
#define ctx_fl_is_sampling ctx_flags.is_sampling
#define ctx_fl_excl_idle ctx_flags.excl_idle
-#define ctx_fl_unsecure ctx_flags.unsecure
#define ctx_fl_going_zombie ctx_flags.going_zombie
#define ctx_fl_trap_reason ctx_flags.trap_reason
#define ctx_fl_no_msg ctx_flags.no_msg
+#define ctx_fl_can_restart ctx_flags.can_restart
#define PFM_SET_WORK_PENDING(t, v) do { (t)->thread.pfm_needs_checking = v; } while(0);
#define PFM_GET_WORK_PENDING(t) (t)->thread.pfm_needs_checking
@@ -493,12 +492,11 @@ typedef struct {
typedef struct {
unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */
+ unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */
unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
unsigned long pfm_ovfl_intr_cycles; /* cycles spent processing ovfl interrupts */
unsigned long pfm_ovfl_intr_cycles_min; /* min cycles spent processing ovfl interrupts */
unsigned long pfm_ovfl_intr_cycles_max; /* max cycles spent processing ovfl interrupts */
- unsigned long pfm_sysupdt_count;
- unsigned long pfm_sysupdt_cycles;
unsigned long pfm_smpl_handler_calls;
unsigned long pfm_smpl_handler_cycles;
char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
@@ -513,10 +511,8 @@ static pfm_session_t pfm_sessions; /* global sessions information */
static struct proc_dir_entry *perfmon_dir;
static pfm_uuid_t pfm_null_uuid = {0,};
-static spinlock_t pfm_smpl_fmt_lock;
-static pfm_buffer_fmt_t *pfm_buffer_fmt_list;
-#define LOCK_BUF_FMT_LIST() spin_lock(&pfm_smpl_fmt_lock)
-#define UNLOCK_BUF_FMT_LIST() spin_unlock(&pfm_smpl_fmt_lock)
+static spinlock_t pfm_buffer_fmt_lock;
+static LIST_HEAD(pfm_buffer_fmt_list);
/* sysctl() controls */
static pfm_sysctl_t pfm_sysctl;
@@ -544,14 +540,8 @@ static struct vm_operations_struct pfm_vm_ops={
close: pfm_vm_close
};
-#define pfm_wait_task_inactive(t) wait_task_inactive(t)
#define pfm_get_cpu_var(v) __ia64_per_cpu_var(v)
#define pfm_get_cpu_data(a,b) per_cpu(a, b)
-typedef irqreturn_t pfm_irq_handler_t;
-#define PFM_IRQ_HANDLER_RET(v) do { \
- put_cpu_no_resched(); \
- return IRQ_HANDLED; \
- } while(0);
static inline void
pfm_put_task(struct task_struct *task)
@@ -628,7 +618,6 @@ static struct file_system_type pfm_fs_type = {
.get_sb = pfmfs_get_sb,
.kill_sb = kill_anon_super,
};
-
DEFINE_PER_CPU(unsigned long, pfm_syst_info);
DEFINE_PER_CPU(struct task_struct *, pmu_owner);
DEFINE_PER_CPU(pfm_context_t *, pmu_ctx);
@@ -734,12 +723,14 @@ pfm_read_soft_counter(pfm_context_t *ctx, int i)
static inline void
pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
{
- ctx->ctx_pmds[i].val = val & ~pmu_conf.ovfl_val;
+ unsigned long ovfl_val = pmu_conf.ovfl_val;
+
+ ctx->ctx_pmds[i].val = val & ~ovfl_val;
/*
* writing to unimplemented part is ignore, so we do not need to
* mask off top part
*/
- ia64_set_pmd(i, val & pmu_conf.ovfl_val);
+ ia64_set_pmd(i, val & ovfl_val);
}
static pfm_msg_t *
@@ -870,11 +861,12 @@ pfm_mask_monitoring(struct task_struct *task)
{
pfm_context_t *ctx = PFM_GET_CTX(task);
struct thread_struct *th = &task->thread;
- unsigned long mask, val;
+ unsigned long mask, val, ovfl_mask;
int i;
- DPRINT(("[%d] masking monitoring for [%d]\n", current->pid, task->pid));
+ DPRINT_ovfl(("[%d] masking monitoring for [%d]\n", current->pid, task->pid));
+ ovfl_mask = pmu_conf.ovfl_val;
/*
* monitoring can only be masked as a result of a valid
* counter overflow. In UP, it means that the PMU still
@@ -904,14 +896,14 @@ pfm_mask_monitoring(struct task_struct *task)
/*
* we rebuild the full 64 bit value of the counter
*/
- ctx->ctx_pmds[i].val += (val & pmu_conf.ovfl_val);
+ ctx->ctx_pmds[i].val += (val & ovfl_mask);
} else {
ctx->ctx_pmds[i].val = val;
}
- DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n",
+ DPRINT_ovfl(("pmd[%d]=0x%lx hw_pmd=0x%lx\n",
i,
ctx->ctx_pmds[i].val,
- val & pmu_conf.ovfl_val));
+ val & ovfl_mask));
}
/*
* mask monitoring by setting the privilege level to 0
@@ -926,6 +918,7 @@ pfm_mask_monitoring(struct task_struct *task)
if ((mask & 0x1) == 0UL) continue;
ia64_set_pmc(i, th->pmcs[i] & ~0xfUL);
th->pmcs[i] &= ~0xfUL;
+ DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i]));
}
/*
* make all of this visible
@@ -943,11 +936,12 @@ pfm_restore_monitoring(struct task_struct *task)
{
pfm_context_t *ctx = PFM_GET_CTX(task);
struct thread_struct *th = &task->thread;
- unsigned long mask;
+ unsigned long mask, ovfl_mask;
unsigned long psr, val;
int i, is_system;
is_system = ctx->ctx_fl_system;
+ ovfl_mask = pmu_conf.ovfl_val;
if (task != current) {
printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task->pid, current->pid);
@@ -989,8 +983,8 @@ pfm_restore_monitoring(struct task_struct *task)
* we split the 64bit value according to
* counter width
*/
- val = ctx->ctx_pmds[i].val & pmu_conf.ovfl_val;
- ctx->ctx_pmds[i].val &= ~pmu_conf.ovfl_val;
+ val = ctx->ctx_pmds[i].val & ovfl_mask;
+ ctx->ctx_pmds[i].val &= ~ovfl_mask;
} else {
val = ctx->ctx_pmds[i].val;
}
@@ -1206,12 +1200,36 @@ pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_
return ret;
}
+static pfm_buffer_fmt_t *
+__pfm_find_buffer_fmt(pfm_uuid_t uuid)
+{
+ struct list_head * pos;
+ pfm_buffer_fmt_t * entry;
-
+ list_for_each(pos, &pfm_buffer_fmt_list) {
+ entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
+ if (pfm_uuid_cmp(uuid, entry->fmt_uuid) == 0)
+ return entry;
+ }
+ return NULL;
+}
+
+/*
+ * find a buffer format based on its uuid
+ */
+static pfm_buffer_fmt_t *
+pfm_find_buffer_fmt(pfm_uuid_t uuid)
+{
+ pfm_buffer_fmt_t * fmt;
+ spin_lock(&pfm_buffer_fmt_lock);
+ fmt = __pfm_find_buffer_fmt(uuid);
+ spin_unlock(&pfm_buffer_fmt_lock);
+ return fmt;
+}
+
int
pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt)
{
- pfm_buffer_fmt_t *p;
int ret = 0;
/* some sanity checks */
@@ -1224,80 +1242,44 @@ pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt)
* XXX: need check validity of fmt_arg_size
*/
- LOCK_BUF_FMT_LIST();
- p = pfm_buffer_fmt_list;
-
+ spin_lock(&pfm_buffer_fmt_lock);
- while (p) {
- if (pfm_uuid_cmp(fmt->fmt_uuid, p->fmt_uuid) == 0) break;
- p = p->fmt_next;
- }
-
- if (p) {
+ if (__pfm_find_buffer_fmt(fmt->fmt_uuid)) {
printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name);
ret = -EBUSY;
- } else {
- fmt->fmt_prev = NULL;
- fmt->fmt_next = pfm_buffer_fmt_list;
- pfm_buffer_fmt_list = fmt;
- printk(KERN_ERR "perfmon: added sampling format %s\n", fmt->fmt_name);
- }
- UNLOCK_BUF_FMT_LIST();
+ goto out;
+ }
+ list_add(&fmt->fmt_list, &pfm_buffer_fmt_list);
+ printk(KERN_INFO "perfmon: added sampling format %s\n", fmt->fmt_name);
- return ret;
+out:
+ spin_unlock(&pfm_buffer_fmt_lock);
+ return ret;
}
int
pfm_unregister_buffer_fmt(pfm_uuid_t uuid)
{
- pfm_buffer_fmt_t *p;
+ pfm_buffer_fmt_t *fmt;
int ret = 0;
- LOCK_BUF_FMT_LIST();
- p = pfm_buffer_fmt_list;
- while (p) {
- if (memcmp(uuid, p->fmt_uuid, sizeof(pfm_uuid_t)) == 0) break;
- p = p->fmt_next;
- }
- if (p) {
- if (p->fmt_prev)
- p->fmt_prev->fmt_next = p->fmt_next;
- else
- pfm_buffer_fmt_list = p->fmt_next;
-
- if (p->fmt_next)
- p->fmt_next->fmt_prev = p->fmt_prev;
+ spin_lock(&pfm_buffer_fmt_lock);
- printk(KERN_ERR "perfmon: removed sampling format: %s\n", p->fmt_name);
- p->fmt_next = p->fmt_prev = NULL;
- } else {
+ fmt = __pfm_find_buffer_fmt(uuid);
+ if (!fmt) {
printk(KERN_ERR "perfmon: cannot unregister format, not found\n");
ret = -EINVAL;
+ goto out;
}
- UNLOCK_BUF_FMT_LIST();
+ list_del_init(&fmt->fmt_list);
+ printk(KERN_INFO "perfmon: removed sampling format: %s\n", fmt->fmt_name);
+out:
+ spin_unlock(&pfm_buffer_fmt_lock);
return ret;
}
-/*
- * find a buffer format based on its uuid
- */
-static pfm_buffer_fmt_t *
-pfm_find_buffer_fmt(pfm_uuid_t uuid, int nolock)
-{
- pfm_buffer_fmt_t *p;
-
- LOCK_BUF_FMT_LIST();
- for (p = pfm_buffer_fmt_list; p ; p = p->fmt_next) {
- if (pfm_uuid_cmp(uuid, p->fmt_uuid) == 0) break;
- }
-
- UNLOCK_BUF_FMT_LIST();
-
- return p;
-}
-
static int
pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
{
@@ -2113,7 +2095,7 @@ pfmfs_delete_dentry(struct dentry *dentry)
return 1;
}
static struct dentry_operations pfmfs_dentry_operations = {
- .d_delete = pfmfs_delete_dentry,
+ .d_delete = pfmfs_delete_dentry,
};
@@ -2420,7 +2402,7 @@ pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int
#define PFM_CTXARG_BUF_ARG(a) (pfm_buffer_fmt_t *)(a+1)
/* invoke and lock buffer format, if found */
- fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id, 0);
+ fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id);
if (fmt == NULL) {
DPRINT(("[%d] cannot find buffer format\n", task->pid));
return -EINVAL;
@@ -2528,8 +2510,7 @@ pfm_ctx_getsize(void *arg, size_t *sz)
if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0;
- /* no buffer locking here, will be called again */
- fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id, 1);
+ fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id);
if (fmt == NULL) {
DPRINT(("cannot find buffer format\n"));
return -EINVAL;
@@ -2588,7 +2569,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task)
/*
* make sure the task is off any CPU
*/
- pfm_wait_task_inactive(task);
+ wait_task_inactive(task);
/* more to come... */
@@ -2679,7 +2660,6 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
*/
ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
- ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0;
ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */
ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
/*
@@ -2705,13 +2685,12 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
init_waitqueue_head(&ctx->ctx_msgq_wait);
init_waitqueue_head(&ctx->ctx_zombieq);
- DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d unsecure=%d no_msg=%d ctx_fd=%d \n",
+ DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
ctx,
ctx_flags,
ctx->ctx_fl_system,
ctx->ctx_fl_block,
ctx->ctx_fl_excl_idle,
- ctx->ctx_fl_unsecure,
ctx->ctx_fl_no_msg,
ctx->ctx_fd));
@@ -2755,14 +2734,12 @@ pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
}
static void
-pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
+pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
{
unsigned long mask = ovfl_regs[0];
unsigned long reset_others = 0UL;
unsigned long val;
- int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
-
- DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag));
+ int i;
/*
* now restore reset value on sampling overflowed counters
@@ -2793,19 +2770,17 @@ pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
}
static void
-pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
+pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
{
unsigned long mask = ovfl_regs[0];
unsigned long reset_others = 0UL;
unsigned long val;
- int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
-
- DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag));
+ int i;
- if (flag == PFM_PMD_NO_RESET) return;
+ DPRINT_ovfl(("ovfl_regs=0x%lx is_long_reset=%d\n", ovfl_regs[0], is_long_reset));
if (ctx->ctx_state == PFM_CTX_MASKED) {
- pfm_reset_regs_masked(ctx, ovfl_regs, flag);
+ pfm_reset_regs_masked(ctx, ovfl_regs, is_long_reset);
return;
}
@@ -3084,7 +3059,7 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
struct thread_struct *thread = NULL;
pfarg_reg_t *req = (pfarg_reg_t *)arg;
- unsigned long value, hw_value;
+ unsigned long value, hw_value, ovfl_mask;
unsigned int cnum;
int i, can_access_pmu = 0, state;
int is_counting, is_loaded, is_system;
@@ -3094,6 +3069,7 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
state = ctx->ctx_state;
is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
is_system = ctx->ctx_fl_system;
+ ovfl_mask = pmu_conf.ovfl_val;
if (state == PFM_CTX_TERMINATED || state == PFM_CTX_ZOMBIE) return -EINVAL;
@@ -3162,22 +3138,21 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
* when context is load we use the split value
*/
if (is_loaded) {
- hw_value = value & pmu_conf.ovfl_val;
- value = value & ~pmu_conf.ovfl_val;
+ hw_value = value & ovfl_mask;
+ value = value & ~ovfl_mask;
}
-
- /*
- * update sampling periods
- */
- ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset;
- ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset;
-
- /*
- * update randomization parameters
- */
- ctx->ctx_pmds[cnum].seed = req->reg_random_seed;
- ctx->ctx_pmds[cnum].mask = req->reg_random_mask;
}
+ /*
+ * update reset values (not just for counters)
+ */
+ ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset;
+ ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset;
+
+ /*
+ * update randomization parameters (not just for counters)
+ */
+ ctx->ctx_pmds[cnum].seed = req->reg_random_seed;
+ ctx->ctx_pmds[cnum].mask = req->reg_random_mask;
/*
* update context value
@@ -3284,7 +3259,7 @@ static int
pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
struct thread_struct *thread = NULL;
- unsigned long val = 0UL, lval ;
+ unsigned long val = 0UL, lval, ovfl_mask;
pfarg_reg_t *req = (pfarg_reg_t *)arg;
unsigned int cnum, reg_flags = 0;
int i, can_access_pmu = 0, state;
@@ -3299,6 +3274,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
state = ctx->ctx_state;
is_loaded = state == PFM_CTX_LOADED ? 1 : 0;
is_system = ctx->ctx_fl_system;
+ ovfl_mask = pmu_conf.ovfl_val;
if (state == PFM_CTX_ZOMBIE) return -EINVAL;
@@ -3368,7 +3344,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
/*
* XXX: need to check for overflow when loaded
*/
- val &= pmu_conf.ovfl_val;
+ val &= ovfl_mask;
val += ctx->ctx_pmds[cnum].val;
lval = ctx->ctx_pmds[cnum].lval;
@@ -3672,22 +3648,48 @@ pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
*/
ctx->ctx_state = PFM_CTX_LOADED;
+ /*
+ * XXX: not really useful for self monitoring
+ */
+ ctx->ctx_fl_can_restart = 0;
+
return 0;
}
- /* restart another task */
+
+ /*
+ * restart another task
+ */
+
+ /*
+ * When PFM_CTX_MASKED, we cannot issue a restart before the previous
+ * one is seen by the task.
+ */
+ if (state == PFM_CTX_MASKED) {
+ if (ctx->ctx_fl_can_restart == 0) return -EINVAL;
+ /*
+ * will prevent subsequent restart before this one is
+ * seen by other task
+ */
+ ctx->ctx_fl_can_restart = 0;
+ }
/*
- * if blocking, then post the semaphore.
+ * if blocking, then post the semaphore is PFM_CTX_MASKED, i.e.
+ * the task is blocked or on its way to block. That's the normal
+ * restart path. If the monitoring is not masked, then the task
+ * can be actively monitoring and we cannot directly intervene.
+ * Therefore we use the trap mechanism to catch the task and
+ * force it to reset the buffer/reset PMDs.
+ *
* if non-blocking, then we ensure that the task will go into
* pfm_handle_work() before returning to user mode.
+ *
* We cannot explicitely reset another task, it MUST always
* be done by the task itself. This works for system wide because
- * the tool that is controlling the session is doing "self-monitoring".
- *
- * XXX: what if the task never goes back to user?
- *
+ * the tool that is controlling the session is logically doing
+ * "self-monitoring".
*/
- if (CTX_OVFL_NOBLOCK(ctx) == 0) {
+ if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) {
DPRINT(("unblocking [%d] \n", task->pid));
up(&ctx->ctx_restart_sem);
} else {
@@ -3725,6 +3727,9 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
return 0;
}
+/*
+ * arg can be NULL and count can be zero for this function
+ */
static int
pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
@@ -3783,21 +3788,22 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_
/*
* check for debug registers in system wide mode
*
- * We make the reservation even when context is not loaded
- * to make sure we get our slot. Note that the PFM_LOAD_CONTEXT
- * may still fail if the task has DBG_VALID set.
+ * If though a check is done in pfm_context_load(),
+ * we must repeat it here, in case the registers are
+ * written after the context is loaded
*/
- LOCK_PFS();
+ if (is_loaded) {
+ LOCK_PFS();
- if (first_time && is_system) {
- if (pfm_sessions.pfs_ptrace_use_dbregs)
- ret = -EBUSY;
- else
- pfm_sessions.pfs_sys_use_dbregs++;
+ if (first_time && is_system) {
+ if (pfm_sessions.pfs_ptrace_use_dbregs)
+ ret = -EBUSY;
+ else
+ pfm_sessions.pfs_sys_use_dbregs++;
+ }
+ UNLOCK_PFS();
}
- UNLOCK_PFS();
-
if (ret != 0) return ret;
/*
@@ -4158,7 +4164,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
unsigned long *pmcs_source, *pmds_source;
int the_cpu;
int ret = 0;
- int state, is_system;
+ int state, is_system, set_dbregs = 0;
state = ctx->ctx_state;
is_system = ctx->ctx_fl_system;
@@ -4173,7 +4179,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
return -EINVAL;
}
- DPRINT(("load_pid [%d]\n", req->load_pid));
+ DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg));
if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) {
DPRINT(("cannot use blocking mode on self for [%d]\n", current->pid));
@@ -4200,15 +4206,33 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
thread = &task->thread;
- ret = -EBUSY;
-
+ ret = 0;
/*
* cannot load a context which is using range restrictions,
* into a task that is being debugged.
*/
- if (ctx->ctx_fl_using_dbreg && (thread->flags & IA64_THREAD_DBG_VALID)) {
- DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid));
- goto error;
+ if (ctx->ctx_fl_using_dbreg) {
+ if (thread->flags & IA64_THREAD_DBG_VALID) {
+ ret = -EBUSY;
+ DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid));
+ goto error;
+ }
+ LOCK_PFS();
+
+ if (is_system) {
+ if (pfm_sessions.pfs_ptrace_use_dbregs) {
+ DPRINT(("cannot load [%d] dbregs in use\n", task->pid));
+ ret = -EBUSY;
+ } else {
+ pfm_sessions.pfs_sys_use_dbregs++;
+ DPRINT(("load [%d] increased sys_use_dbreg=%lu\n", task->pid, pfm_sessions.pfs_sys_use_dbregs));
+ set_dbregs = 1;
+ }
+ }
+
+ UNLOCK_PFS();
+
+ if (ret) goto error;
}
/*
@@ -4228,13 +4252,13 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
*/
the_cpu = ctx->ctx_cpu = smp_processor_id();
+ ret = -EBUSY;
/*
* now reserve the session
*/
ret = pfm_reserve_session(current, is_system, the_cpu);
if (ret) goto error;
- ret = -EBUSY;
/*
* task is necessarily stopped at this point.
*
@@ -4342,11 +4366,6 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
/* initial saved psr (stopped) */
ctx->ctx_saved_psr_up = 0UL;
ia64_psr(regs)->up = ia64_psr(regs)->pp = 0;
-
- if (ctx->ctx_fl_unsecure) {
- ia64_psr(regs)->sp = 0;
- DPRINT(("context unsecured for [%d]\n", task->pid));
- }
}
ret = 0;
@@ -4355,6 +4374,14 @@ error_unres:
if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu);
error:
/*
+ * we must undo the dbregs setting (for system-wide)
+ */
+ if (ret && set_dbregs) {
+ LOCK_PFS();
+ pfm_sessions.pfs_sys_use_dbregs--;
+ UNLOCK_PFS();
+ }
+ /*
* release task, there is now a link with the context
*/
if (is_system == 0 && task != current) {
@@ -4455,7 +4482,7 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
*/
tregs = task == current ? regs : ia64_task_regs(task);
- if (task == current || ctx->ctx_fl_unsecure) {
+ if (task == current) {
/*
* cancel user level control
*/
@@ -4493,7 +4520,10 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
ctx->ctx_task = NULL;
PFM_SET_WORK_PENDING(task, 0);
- ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
+
+ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
+ ctx->ctx_fl_can_restart = 0;
+ ctx->ctx_fl_going_zombie = 0;
DPRINT(("disconnected [%d] from context\n", task->pid));
@@ -4686,7 +4716,7 @@ pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags)
UNPROTECT_CTX(ctx, flags);
- pfm_wait_task_inactive(task);
+ wait_task_inactive(task);
PROTECT_CTX(ctx, flags);
@@ -4725,7 +4755,8 @@ sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, lon
PFM_CMD_IDX(cmd),
PFM_CMD_IS_VALID(cmd),
PFM_CMD_NARG(cmd),
- PFM_CMD_ARG_SIZE(cmd), count));
+ PFM_CMD_ARG_SIZE(cmd),
+ count));
/*
* check if number of arguments matches what the command expects
@@ -4842,8 +4873,10 @@ pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_reg
{
pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt;
pfm_ovfl_ctrl_t rst_ctrl;
+ int state;
int ret = 0;
+ state = ctx->ctx_state;
/*
* Unlock sampling buffer and reset index atomically
* XXX: not really needed when blocking
@@ -4853,9 +4886,10 @@ pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_reg
rst_ctrl.bits.mask_monitoring = 0;
rst_ctrl.bits.reset_ovfl_pmds = 1;
- /* XXX: check return value */
- if (fmt->fmt_restart)
- ret = (*fmt->fmt_restart)(current, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
+ if (state == PFM_CTX_LOADED)
+ ret = pfm_buf_fmt_restart_active(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
+ else
+ ret = pfm_buf_fmt_restart(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs);
} else {
rst_ctrl.bits.mask_monitoring = 0;
rst_ctrl.bits.reset_ovfl_pmds = 1;
@@ -4876,7 +4910,6 @@ pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_reg
}
}
-
/*
* context MUST BE LOCKED when calling
* can only be called for current
@@ -4954,7 +4987,7 @@ pfm_handle_work(void)
reason = ctx->ctx_fl_trap_reason;
ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
- DPRINT(("[%d] reason=%d\n", current->pid, reason));
+ DPRINT(("[%d] reason=%d state=%d\n", current->pid, reason, ctx->ctx_state));
/*
* must be done before we check non-blocking mode
@@ -5085,7 +5118,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
{
pfm_ovfl_arg_t ovfl_arg;
unsigned long mask;
- unsigned long old_val;
+ unsigned long old_val, ovfl_val;
unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL;
unsigned long tstamp;
pfm_ovfl_ctrl_t ovfl_ctrl;
@@ -5101,7 +5134,8 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
tstamp = ia64_get_itc();
- mask = pmc0 >> PMU_FIRST_COUNTER;
+ mask = pmc0 >> PMU_FIRST_COUNTER;
+ ovfl_val = pmu_conf.ovfl_val;
DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s "
"used_pmds=0x%lx reload_pmcs=0x%lx\n",
@@ -5133,7 +5167,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
* pfm_read_pmds().
*/
old_val = ctx->ctx_pmds[i].val;
- ctx->ctx_pmds[i].val += 1 + pmu_conf.ovfl_val;
+ ctx->ctx_pmds[i].val += 1 + ovfl_val;
/*
* check for overflow condition
@@ -5145,7 +5179,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx smpl_pmds=0x%lx\n",
i, ctx->ctx_pmds[i].val, old_val,
- ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify, smpl_pmds));
+ ia64_get_pmd(i) & ovfl_val, ovfl_pmds, ovfl_notify, smpl_pmds));
}
/*
@@ -5196,6 +5230,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
for(j=0, k=0; smpl_pmds; j++, smpl_pmds >>=1) {
if ((smpl_pmds & 0x1) == 0) continue;
ovfl_arg.smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ? pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j);
+ DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg.smpl_pmds_values[k-1]));
}
}
@@ -5294,6 +5329,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str
if (ovfl_ctrl.bits.mask_monitoring) {
pfm_mask_monitoring(task);
ctx->ctx_state = PFM_CTX_MASKED;
+ ctx->ctx_fl_can_restart = 1;
}
/*
@@ -5376,12 +5412,10 @@ pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
*/
/* sanity check */
- if (!ctx) goto report_spurious;
+ if (!ctx) goto report_spurious1;
- if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) {
- printk("perfmon: current [%d] owner = [%d] PMVALID=0 state=%d\n", current->pid, task->pid, ctx->ctx_state);
- goto report_spurious;
- }
+ if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0)
+ goto report_spurious2;
PROTECT_CTX_NOPRINT(ctx, flags);
@@ -5400,14 +5434,20 @@ pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
return retval;
-report_spurious:
+report_spurious1:
printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n",
this_cpu, task->pid);
pfm_unfreeze_pmu();
return -1;
+report_spurious2:
+ printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d, invalid flag\n",
+ this_cpu,
+ task->pid);
+ pfm_unfreeze_pmu();
+ return -1;
}
-static pfm_irq_handler_t
+static irqreturn_t
pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
{
unsigned long start_cycles, total_cycles;
@@ -5436,7 +5476,8 @@ pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles;
}
- PFM_IRQ_HANDLER_RET();
+ put_cpu_no_resched();
+ return IRQ_HANDLED;
}
@@ -5445,10 +5486,13 @@ static int
pfm_proc_info(char *page)
{
char *p = page;
- pfm_buffer_fmt_t *b;
+ struct list_head * pos;
+ pfm_buffer_fmt_t * entry;
unsigned long psr;
+ int online_cpus = 0;
int i;
+ p += sprintf(p, "perfmon version : %u.%u\n", PFM_VERSION_MAJ, PFM_VERSION_MIN);
p += sprintf(p, "model : %s\n", pmu_conf.pmu_name);
p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val);
@@ -5462,17 +5506,17 @@ pfm_proc_info(char *page)
p += sprintf(p, "CPU%-2d smpl handler calls : %lu\n", i, pfm_stats[i].pfm_smpl_handler_calls);
p += sprintf(p, "CPU%-2d smpl handler cycles : %lu\n", i, pfm_stats[i].pfm_smpl_handler_cycles);
p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
- p += sprintf(p, "CPU%-2d sysupdt count : %lu\n", i, pfm_stats[i].pfm_sysupdt_count);
- p += sprintf(p, "CPU%-2d sysupdt cycles : %lu\n", i, pfm_stats[i].pfm_sysupdt_cycles);
+ p += sprintf(p, "CPU%-2d replay intrs : %lu\n", i, pfm_stats[i].pfm_replay_ovfl_intr_count);
p += sprintf(p, "CPU%-2d syst_wide : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_SYST_WIDE ? 1 : 0);
p += sprintf(p, "CPU%-2d dcr_pp : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_DCR_PP ? 1 : 0);
p += sprintf(p, "CPU%-2d exclude idle : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0);
p += sprintf(p, "CPU%-2d owner : %d\n" , i, pfm_get_cpu_data(pmu_owner, i) ? pfm_get_cpu_data(pmu_owner, i)->pid: -1);
p += sprintf(p, "CPU%-2d context : %p\n" , i, pfm_get_cpu_data(pmu_ctx, i));
p += sprintf(p, "CPU%-2d activations : %lu\n", i, pfm_get_cpu_data(pmu_activation_number,i));
+ online_cpus++;
}
- if (num_online_cpus() == 1)
+ if (online_cpus == 1)
{
psr = pfm_get_psr();
ia64_srlz_d();
@@ -5485,7 +5529,7 @@ pfm_proc_info(char *page)
}
LOCK_PFS();
- p += sprintf(p, "proc_sessions : %u\n"
+ p += sprintf(p, "proc_sessions : %u\n"
"sys_sessions : %u\n"
"sys_use_dbregs : %u\n"
"ptrace_use_dbregs : %u\n",
@@ -5495,29 +5539,30 @@ pfm_proc_info(char *page)
pfm_sessions.pfs_ptrace_use_dbregs);
UNLOCK_PFS();
- LOCK_BUF_FMT_LIST();
+ spin_lock(&pfm_buffer_fmt_lock);
- for (b = pfm_buffer_fmt_list; b ; b = b->fmt_next) {
+ list_for_each(pos, &pfm_buffer_fmt_list) {
+ entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
p += sprintf(p, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n",
- b->fmt_uuid[0],
- b->fmt_uuid[1],
- b->fmt_uuid[2],
- b->fmt_uuid[3],
- b->fmt_uuid[4],
- b->fmt_uuid[5],
- b->fmt_uuid[6],
- b->fmt_uuid[7],
- b->fmt_uuid[8],
- b->fmt_uuid[9],
- b->fmt_uuid[10],
- b->fmt_uuid[11],
- b->fmt_uuid[12],
- b->fmt_uuid[13],
- b->fmt_uuid[14],
- b->fmt_uuid[15],
- b->fmt_name);
- }
- UNLOCK_BUF_FMT_LIST();
+ entry->fmt_uuid[0],
+ entry->fmt_uuid[1],
+ entry->fmt_uuid[2],
+ entry->fmt_uuid[3],
+ entry->fmt_uuid[4],
+ entry->fmt_uuid[5],
+ entry->fmt_uuid[6],
+ entry->fmt_uuid[7],
+ entry->fmt_uuid[8],
+ entry->fmt_uuid[9],
+ entry->fmt_uuid[10],
+ entry->fmt_uuid[11],
+ entry->fmt_uuid[12],
+ entry->fmt_uuid[13],
+ entry->fmt_uuid[14],
+ entry->fmt_uuid[15],
+ entry->fmt_name);
+ }
+ spin_unlock(&pfm_buffer_fmt_lock);
return p - page;
}
@@ -5546,7 +5591,7 @@ perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
* local_cpu_data->pfm_syst_info
*/
void
-pfm_do_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
+pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
{
struct pt_regs *regs;
unsigned long dcr;
@@ -5591,21 +5636,10 @@ pfm_do_syst_wide_update_task(struct task_struct *task, unsigned long info, int i
}
}
-void
-pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
-{
- unsigned long start, end;
-
- pfm_stats[smp_processor_id()].pfm_sysupdt_count++;
- start = ia64_get_itc();
-
- pfm_do_syst_wide_update_task(task, info, is_ctxswin);
-
- end = ia64_get_itc();
- pfm_stats[smp_processor_id()].pfm_sysupdt_cycles += end-start;
-}
-
#ifdef CONFIG_SMP
+/*
+ * in 2.6, interrupts are masked when we come here and the runqueue lock is held
+ */
void
pfm_save_regs(struct task_struct *task)
{
@@ -5706,14 +5740,11 @@ pfm_save_regs(struct task_struct *task)
/*
* unfreeze PMU if had pending overflows
*/
- if (t->pmcs[0] & ~1UL) pfm_unfreeze_pmu();
+ if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
/*
- * finally, unmask interrupts and allow context
- * access.
- * Any pended overflow interrupt may be delivered
- * here and will be treated as spurious because we
- * have have no PMU owner anymore.
+ * finally, allow context access.
+ * interrupts will still be masked after this call.
*/
pfm_unprotect_ctx_ctxsw(ctx, flags);
@@ -5726,10 +5757,6 @@ save_error:
}
#else /* !CONFIG_SMP */
-
-/*
- * in 2.5, interrupts are masked when we come here
- */
void
pfm_save_regs(struct task_struct *task)
{
@@ -5836,6 +5863,9 @@ pfm_lazy_save_regs (struct task_struct *task)
#endif /* CONFIG_SMP */
#ifdef CONFIG_SMP
+/*
+ * in 2.6, interrupts are masked when we come here and the runqueue lock is held
+ */
void
pfm_load_regs (struct task_struct *task)
{
@@ -5959,20 +5989,24 @@ pfm_load_regs (struct task_struct *task)
* was saved.
*/
if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
- struct pt_regs *regs = ia64_task_regs(task);
- pfm_overflow_handler(task, ctx, t->pmcs[0], regs);
+ /*
+ * reload pmc0 with the overflow information
+ * On McKinley PMU, this will trigger a PMU interrupt
+ */
+ ia64_set_pmc(0, t->pmcs[0]);
+ ia64_srlz_d();
+ t->pmcs[0] = 0UL;
+#ifndef CONFIG_MCKINLEY
+ /*
+ * will replay the PMU interrupt
+ */
+ DPRINT(("perfmon: resend irq for [%d]\n", task->pid));
+ hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+#endif
+ pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
}
/*
- * we clear PMC0, to ensure that any in flight interrupt
- * will not be attributed to the new context we are installing
- * because the actual overflow has been processed above already.
- * No real effect until we unmask interrupts at the end of the
- * function.
- */
- pfm_unfreeze_pmu();
-
- /*
* we just did a reload, so we reset the partial reload fields
*/
ctx->ctx_reload_pmcs[0] = 0UL;
@@ -5990,13 +6024,15 @@ pfm_load_regs (struct task_struct *task)
SET_ACTIVATION(ctx);
/*
- * establish new ownership. Interrupts
- * are still masked at this point.
+ * establish new ownership.
*/
SET_PMU_OWNER(task, ctx);
/*
- * restore the psr.up bit
+ * restore the psr.up bit. measurement
+ * is active again.
+ * no PMU interrupt can happen at this point
+ * because we still have interrupts disabled.
*/
if (likely(psr_up)) pfm_set_psr_up();
@@ -6091,42 +6127,39 @@ pfm_load_regs (struct task_struct *task)
pfm_restore_pmcs(t->pmcs, pmc_mask);
/*
- * Check for pending overflow when state was last saved.
- * invoked handler is overflow status bits set.
- *
- * Any PMU overflow in flight at this point, will still
- * be treated as spurious because we have no declared
- * owner. Note that the first level interrupt handler
- * DOES NOT TOUCH any PMC except PMC0 for which we have
- * a copy already.
+ * check for pending overflow at the time the state
+ * was saved.
*/
if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
- struct pt_regs *regs = ia64_task_regs(task);
- pfm_overflow_handler(task, ctx, t->pmcs[0], regs);
- }
+ /*
+ * reload pmc0 with the overflow information
+ * On McKinley PMU, this will trigger a PMU interrupt
+ */
+ ia64_set_pmc(0, t->pmcs[0]);
+ ia64_srlz_d();
- /*
- * we clear PMC0, to ensure that any in flight interrupt
- * will not be attributed to the new context we are installing
- * because the actual overflow has been processed above already.
- *
- * This is an atomic operation.
- */
- pfm_unfreeze_pmu();
+ t->pmcs[0] = 0UL;
+
+#ifndef CONFIG_MCKINLEY
+ /*
+ * will replay the PMU interrupt
+ */
+ DPRINT(("perfmon: resend irq for [%d]\n", task->pid));
+ hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+#endif
+ pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
+ }
/*
- * establish new ownership. If there was an in-flight
- * overflow interrupt, it will be treated as spurious
- * before and after the call, because no overflow
- * status bit can possibly be set. No new overflow
- * can be generated because, at this point, psr.up
- * is still cleared.
+ * establish new ownership.
*/
SET_PMU_OWNER(task, ctx);
/*
- * restore the psr. This is the point at which
- * new overflow interrupts can be generated again.
+ * restore the psr.up bit. measurement
+ * is active again.
+ * no PMU interrupt can happen at this point
+ * because we still have interrupts disabled.
*/
if (likely(psr_up)) pfm_set_psr_up();
}
@@ -6139,7 +6172,7 @@ static void
pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
{
u64 pmc0;
- unsigned long mask2, val, pmd_val;
+ unsigned long mask2, val, pmd_val, ovfl_val;
int i, can_access_pmu = 0;
int is_self;
@@ -6187,7 +6220,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
*/
task->thread.pmcs[0] &= ~0x1;
}
-
+ ovfl_val = pmu_conf.ovfl_val;
/*
* we save all the used pmds
* we take care of overflows for counting PMDs
@@ -6210,12 +6243,12 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
task->pid,
i,
ctx->ctx_pmds[i].val,
- val & pmu_conf.ovfl_val));
+ val & ovfl_val));
/*
* we rebuild the full 64 bit value of the counter
*/
- val = ctx->ctx_pmds[i].val + (val & pmu_conf.ovfl_val);
+ val = ctx->ctx_pmds[i].val + (val & ovfl_val);
/*
* now everything is in ctx_pmds[] and we need
@@ -6228,7 +6261,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
* take care of overflow inline
*/
if (pmc0 & (1UL << i)) {
- val += 1 + pmu_conf.ovfl_val;
+ val += 1 + ovfl_val;
DPRINT(("[%d] pmd[%d] overflowed\n", task->pid, i));
}
}
@@ -6338,7 +6371,7 @@ pfm_init(void)
* initialize all our spinlocks
*/
spin_lock_init(&pfm_sessions.pfs_lock);
- spin_lock_init(&pfm_smpl_fmt_lock);
+ spin_lock_init(&pfm_buffer_fmt_lock);
init_pfm_fs();
@@ -6352,6 +6385,9 @@ pfm_init(void)
__initcall(pfm_init);
+/*
+ * this function is called before pfm_init()
+ */
void
pfm_init_percpu (void)
{
@@ -6364,7 +6400,6 @@ pfm_init_percpu (void)
pfm_clear_psr_pp();
pfm_clear_psr_up();
-
if (smp_processor_id() == 0)
register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
diff --git a/arch/ia64/kernel/perfmon_itanium.h b/arch/ia64/kernel/perfmon_itanium.h
index 05f927444110..af81ba44b280 100644
--- a/arch/ia64/kernel/perfmon_itanium.h
+++ b/arch/ia64/kernel/perfmon_itanium.h
@@ -81,6 +81,8 @@ pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnu
*/
if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) {
+ DPRINT(("pmc[%d]=0x%lx has active pmc13.ta cleared, clearing ibr\n", cnum, *val));
+
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
@@ -98,6 +100,8 @@ pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnu
*/
if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) {
+ DPRINT(("pmc[%d]=0x%lx has active pmc11.pt cleared, clearing dbr\n", cnum, *val));
+
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
diff --git a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h
index 2e67421055c0..28818def428b 100644
--- a/arch/ia64/kernel/perfmon_mckinley.h
+++ b/arch/ia64/kernel/perfmon_mckinley.h
@@ -109,10 +109,20 @@ pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnu
if (ctx == NULL) return -EINVAL;
/*
- * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled
- * before they are written (fl_using_dbreg==0) to avoid picking up stale information.
+ * we must clear the debug registers if pmc13 has a value which enable
+ * memory pipeline event constraints. In this case we need to clear the
+ * the debug registers if they have not yet been accessed. This is required
+ * to avoid picking stale state.
+ * PMC13 is "active" if:
+ * one of the pmc13.cfg_dbrpXX field is different from 0x3
+ * AND
+ * at the corresponding pmc13.ena_dbrpXX is set.
+ *
+ * For now, we just check on cfg_dbrXX != 0x3.
*/
- if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) {
+ if (cnum == 13 && ((*val & 0x18181818UL) != 0x18181818UL) && ctx->ctx_fl_using_dbreg == 0) {
+
+ DPRINT(("pmc[%d]=0x%lx has active pmc13 settings, clearing dbr\n", cnum, *val));
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
@@ -128,7 +138,9 @@ pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnu
* we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled
* before they are (fl_using_dbreg==0) to avoid picking up stale information.
*/
- if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) {
+ if (cnum == 14 && ((*val & 0x2222UL) != 0x2222UL) && ctx->ctx_fl_using_dbreg == 0) {
+
+ DPRINT(("pmc[%d]=0x%lx has active pmc14 settings, clearing ibr\n", cnum, *val));
/* don't mix debug with perfmon */
if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
@@ -170,7 +182,7 @@ pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnu
&& ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
- if (ret) printk("perfmon: failure check_case1\n");
+ if (ret) DPRINT((KERN_DEBUG "perfmon: failure check_case1\n"));
}
return ret ? -EINVAL : 0;
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 754df659765a..e23681b9dad5 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -30,6 +30,8 @@
#include <linux/string.h>
#include <linux/threads.h>
#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
#include <linux/efi.h>
#include <linux/initrd.h>
@@ -43,6 +45,7 @@
#include <asm/processor.h>
#include <asm/sal.h>
#include <asm/sections.h>
+#include <asm/serial.h>
#include <asm/smp.h>
#include <asm/system.h>
#include <asm/unistd.h>
@@ -101,7 +104,7 @@ int
filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
{
unsigned long range_start, range_end, prev_start;
- void (*func)(unsigned long, unsigned long);
+ void (*func)(unsigned long, unsigned long, int);
int i;
#if IGNORE_PFN0
@@ -122,11 +125,7 @@ filter_rsvd_memory (unsigned long start, unsigned long end, void *arg)
range_end = min(end, rsvd_region[i].start);
if (range_start < range_end)
-#ifdef CONFIG_DISCONTIGMEM
- call_pernode_memory(__pa(range_start), __pa(range_end), func);
-#else
- (*func)(__pa(range_start), range_end - range_start);
-#endif
+ call_pernode_memory(__pa(range_start), range_end - range_start, func);
/* nothing more available in this segment */
if (range_end == end) return 0;
@@ -225,6 +224,25 @@ find_initrd (void)
#endif
}
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static void __init
+setup_serial_legacy (void)
+{
+ struct uart_port port;
+ unsigned int i, iobase[] = {0x3f8, 0x2f8};
+
+ printk(KERN_INFO "Registering legacy COM ports for serial console\n");
+ memset(&port, 0, sizeof(port));
+ port.iotype = SERIAL_IO_PORT;
+ port.uartclk = BASE_BAUD * 16;
+ for (i = 0; i < ARRAY_SIZE(iobase); i++) {
+ port.line = i;
+ port.iobase = iobase[i];
+ early_serial_setup(&port);
+ }
+}
+#endif
+
void __init
setup_arch (char **cmdline_p)
{
@@ -239,7 +257,6 @@ setup_arch (char **cmdline_p)
strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
efi_init();
- find_memory();
#ifdef CONFIG_ACPI_BOOT
/* Initialize the ACPI boot-time table parser */
@@ -253,6 +270,8 @@ setup_arch (char **cmdline_p)
# endif
#endif /* CONFIG_APCI_BOOT */
+ find_memory();
+
/* process SAL system table: */
ia64_sal_init(efi.sal_systab);
@@ -297,11 +316,22 @@ setup_arch (char **cmdline_p)
#ifdef CONFIG_SERIAL_8250_HCDP
if (efi.hcdp) {
void setup_serial_hcdp(void *);
-
- /* Setup the serial ports described by HCDP */
setup_serial_hcdp(efi.hcdp);
}
#endif
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ /*
+ * Without HCDP, we won't discover any serial ports until the serial driver looks
+ * in the ACPI namespace. If ACPI claims there are some legacy devices, register
+ * the legacy COM ports so serial console works earlier. This is slightly dangerous
+ * because we don't *really* know whether there's anything there, but we hope that
+ * all new boxes will implement HCDP.
+ */
+ extern unsigned char acpi_legacy_devices;
+ if (!efi.hcdp && acpi_legacy_devices)
+ setup_serial_legacy();
+#endif
+
#ifdef CONFIG_VT
# if defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
@@ -544,28 +574,7 @@ cpu_init (void)
struct cpuinfo_ia64 *cpu_info;
void *cpu_data;
-#ifdef CONFIG_SMP
- int cpu;
-
- /*
- * get_free_pages() cannot be used before cpu_init() done. BSP allocates
- * "NR_CPUS" pages for all CPUs to avoid that AP calls get_zeroed_page().
- */
- if (smp_processor_id() == 0) {
- cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, PERCPU_PAGE_SIZE,
- __pa(MAX_DMA_ADDRESS));
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
- __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
- cpu_data += PERCPU_PAGE_SIZE;
-
- per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
- }
- }
- cpu_data = __per_cpu_start + __per_cpu_offset[smp_processor_id()];
-#else /* !CONFIG_SMP */
- cpu_data = __phys_per_cpu_start;
-#endif /* !CONFIG_SMP */
+ cpu_data = per_cpu_init();
get_max_cacheline_size();
@@ -576,9 +585,6 @@ cpu_init (void)
* accessing cpu_data() through the canonical per-CPU address.
*/
cpu_info = cpu_data + ((char *) &__ia64_per_cpu_var(cpu_info) - __per_cpu_start);
-#ifdef CONFIG_NUMA
- cpu_info->node_data = get_node_data_ptr();
-#endif
identify_cpu(cpu_info);
#ifdef CONFIG_MCKINLEY
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index d572f1a2073a..1396a3876ff3 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -65,8 +65,12 @@ itc_update (long delta_nsec)
}
/*
- * Return the number of nano-seconds that elapsed since the last update to jiffy. The
- * xtime_lock must be at least read-locked when calling this routine.
+ * Return the number of nano-seconds that elapsed since the last
+ * update to jiffy. It is quite possible that the timer interrupt
+ * will interrupt this and result in a race for any of jiffies,
+ * wall_jiffies or itm_next. Thus, the xtime_lock must be at least
+ * read synchronised when calling this routine (see do_gettimeofday()
+ * below for an example).
*/
unsigned long
itc_get_offset (void)
@@ -77,11 +81,6 @@ itc_get_offset (void)
last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next
- (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta);
- if (unlikely((long) (now - last_tick) < 0)) {
- printk(KERN_ERR "CPU %d: now < last_tick (now=0x%lx,last_tick=0x%lx)!\n",
- smp_processor_id(), now, last_tick);
- return last_nsec_offset;
- }
elapsed_cycles = now - last_tick;
return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT;
}
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index e9650c7ec667..c6c945059610 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -25,6 +25,10 @@
#include <asm/pgtable.h>
#include <asm/sections.h>
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+static unsigned long num_dma_physpages;
+#endif
+
/**
* show_mem - display a memory statistics summary
*
@@ -161,3 +165,133 @@ find_memory (void)
find_initrd();
}
+
+#ifdef CONFIG_SMP
+/**
+ * per_cpu_init - setup per-cpu variables
+ *
+ * Allocate and setup per-cpu data areas.
+ */
+void *
+per_cpu_init (void)
+{
+ void *cpu_data;
+ int cpu;
+
+ /*
+ * get_free_pages() cannot be used before cpu_init() done. BSP
+ * allocates "NR_CPUS" pages for all CPUs to avoid that AP calls
+ * get_zeroed_page().
+ */
+ if (smp_processor_id() == 0) {
+ cpu_data = __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS,
+ PERCPU_PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
+ __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start;
+ cpu_data += PERCPU_PAGE_SIZE;
+ per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
+ }
+ }
+ return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
+}
+#endif /* CONFIG_SMP */
+
+static int
+count_pages (u64 start, u64 end, void *arg)
+{
+ unsigned long *count = arg;
+
+ *count += (end - start) >> PAGE_SHIFT;
+ return 0;
+}
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+static int
+count_dma_pages (u64 start, u64 end, void *arg)
+{
+ unsigned long *count = arg;
+
+ if (end <= MAX_DMA_ADDRESS)
+ *count += (end - start) >> PAGE_SHIFT;
+ return 0;
+}
+#endif
+
+/*
+ * Set up the page tables.
+ */
+
+void
+paging_init (void)
+{
+ unsigned long max_dma;
+ unsigned long zones_size[MAX_NR_ZONES];
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+ unsigned long zholes_size[MAX_NR_ZONES];
+ unsigned long max_gap;
+#endif
+
+ /* initialize mem_map[] */
+
+ memset(zones_size, 0, sizeof(zones_size));
+
+ num_physpages = 0;
+ efi_memmap_walk(count_pages, &num_physpages);
+
+ max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+ memset(zholes_size, 0, sizeof(zholes_size));
+
+ num_dma_physpages = 0;
+ efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+
+ if (max_low_pfn < max_dma) {
+ zones_size[ZONE_DMA] = max_low_pfn;
+ zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+ } else {
+ zones_size[ZONE_DMA] = max_dma;
+ zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+ if (num_physpages > num_dma_physpages) {
+ zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+ zholes_size[ZONE_NORMAL] =
+ ((max_low_pfn - max_dma) -
+ (num_physpages - num_dma_physpages));
+ }
+ }
+
+ max_gap = 0;
+ efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
+ if (max_gap < LARGE_GAP) {
+ vmem_map = (struct page *) 0;
+ free_area_init_node(0, &contig_page_data, NULL, zones_size, 0,
+ zholes_size);
+ mem_map = contig_page_data.node_mem_map;
+ } else {
+ unsigned long map_size;
+
+ /* allocate virtual_mem_map */
+
+ map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+ vmalloc_end -= map_size;
+ vmem_map = (struct page *) vmalloc_end;
+ efi_memmap_walk(create_mem_map_page_table, 0);
+
+ free_area_init_node(0, &contig_page_data, vmem_map, zones_size,
+ 0, zholes_size);
+
+ mem_map = contig_page_data.node_mem_map;
+ printk("Virtual mem_map starts at 0x%p\n", mem_map);
+ }
+#else /* !CONFIG_VIRTUAL_MEM_MAP */
+ if (max_low_pfn < max_dma)
+ zones_size[ZONE_DMA] = max_low_pfn;
+ else {
+ zones_size[ZONE_DMA] = max_dma;
+ zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+ }
+ free_area_init(zones_size);
+#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+ zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
+}
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 2f1b7826caf1..25c8151d16d0 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -17,72 +17,57 @@
#include <linux/acpi.h>
#include <linux/efi.h>
#include <asm/pgalloc.h>
+#include <asm/tlb.h>
#include <asm/meminit.h>
+#include <asm/numa.h>
+#include <asm/sections.h>
-
-/*
- * Round an address upward to the next multiple of GRANULE size.
- */
-#define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
-
-static struct ia64_node_data *node_data[MAX_NUMNODES];
-static long boot_pg_data[8*MAX_NUMNODES+sizeof(pg_data_t)] __initdata;
-static pg_data_t *pg_data_ptr[MAX_NUMNODES] __initdata;
-static bootmem_data_t bdata[MAX_NUMNODES][NR_BANKS_PER_NODE+1] __initdata;
/*
- * Return the compact node number of this cpu. Used prior to
- * setting up the cpu_data area.
- * Note - not fast, intended for boot use only!!
+ * Track per-node information needed to setup the boot memory allocator, the
+ * per-node areas, and the real VM.
*/
-int
-boot_get_local_nodeid(void)
-{
- int i;
-
- for (i = 0; i < NR_CPUS; i++)
- if (node_cpuid[i].phys_id == hard_smp_processor_id())
- return node_cpuid[i].nid;
-
- /* node info missing, so nid should be 0.. */
- return 0;
-}
-
-/*
- * Return a pointer to the pg_data structure for a node.
- * This function is used ONLY in early boot before the cpu_data
- * structure is available.
- */
-pg_data_t* __init
-boot_get_pg_data_ptr(long node)
-{
- return pg_data_ptr[node];
-}
+struct early_node_data {
+ struct ia64_node_data *node_data;
+ pg_data_t *pgdat;
+ unsigned long pernode_addr;
+ unsigned long pernode_size;
+ struct bootmem_data bootmem_data;
+ unsigned long num_physpages;
+ unsigned long num_dma_physpages;
+ unsigned long min_pfn;
+ unsigned long max_pfn;
+};
+static struct early_node_data mem_data[NR_NODES] __initdata;
/*
- * Return a pointer to the node data for the current node.
- * (boottime initialization only)
+ * To prevent cache aliasing effects, align per-node structures so that they
+ * start at addresses that are strided by node number.
*/
-struct ia64_node_data *
-get_node_data_ptr(void)
-{
- return node_data[boot_get_local_nodeid()];
-}
-
-/*
- * We allocate one of the bootmem_data_t structs for each piece of memory
- * that we wish to treat as a contiguous block. Each such block must start
- * on a BANKSIZE boundary. Multiple banks per node is not supported.
+#define NODEDATA_ALIGN(addr, node) \
+ ((((addr) + 1024*1024-1) & ~(1024*1024-1)) + (node)*PERCPU_PAGE_SIZE)
+
+/**
+ * build_node_maps - callback to setup bootmem structs for each node
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * We allocate a struct bootmem_data for each piece of memory that we wish to
+ * treat as a virtually contiguous block (i.e. each node). Each such block
+ * must start on an %IA64_GRANULE_SIZE boundary, so we round the address down
+ * if necessary. Any non-existent pages will simply be part of the virtual
+ * memmap. We also update min_low_pfn and max_low_pfn here as we receive
+ * memory ranges from the caller.
*/
-static int __init
-build_maps(unsigned long pstart, unsigned long length, int node)
+static int __init build_node_maps(unsigned long start, unsigned long len,
+ int node)
{
- bootmem_data_t *bdp;
- unsigned long cstart, epfn;
+ unsigned long cstart, epfn, end = start + len;
+ struct bootmem_data *bdp = &mem_data[node].bootmem_data;
- bdp = pg_data_ptr[node]->bdata;
- epfn = GRANULEROUNDUP(pstart + length) >> PAGE_SHIFT;
- cstart = pstart & ~(BANKSIZE - 1);
+ epfn = GRANULEROUNDUP(end) >> PAGE_SHIFT;
+ cstart = GRANULEROUNDDOWN(start);
if (!bdp->node_low_pfn) {
bdp->node_boot_start = cstart;
@@ -98,34 +83,143 @@ build_maps(unsigned long pstart, unsigned long length, int node)
return 0;
}
-/*
- * Find space on each node for the bootmem map.
+/**
+ * early_nr_cpus_node - return number of cpus on a given node
+ * @node: node to check
+ *
+ * Count the number of cpus on @node. We can't use nr_cpus_node() yet because
+ * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
+ * called yet.
+ */
+static int early_nr_cpus_node(int node)
+{
+ int cpu, n = 0;
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ if (node == node_cpuid[cpu].nid)
+ n++;
+
+ return n;
+}
+
+/**
+ * find_pernode_space - allocate memory for memory map and per-node structures
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * This routine reserves space for the per-cpu data struct, the list of
+ * pg_data_ts and the per-node data struct. Each node will have something like
+ * the following in the first chunk of addr. space large enough to hold it.
+ *
+ * ________________________
+ * | |
+ * |~~~~~~~~~~~~~~~~~~~~~~~~| <-- NODEDATA_ALIGN(start, node) for the first
+ * | PERCPU_PAGE_SIZE * | start and length big enough
+ * | NR_CPUS |
+ * |------------------------|
+ * | local pg_data_t * |
+ * |------------------------|
+ * | local ia64_node_data |
+ * |------------------------|
+ * | ??? |
+ * |________________________|
*
- * Called by efi_memmap_walk to find boot memory on each node. Note that
- * only blocks that are free are passed to this routine (currently filtered by
- * free_available_memory).
+ * Once this space has been set aside, the bootmem maps are initialized. We
+ * could probably move the allocation of the per-cpu and ia64_node_data space
+ * outside of this function and use alloc_bootmem_node(), but doing it here
+ * is straightforward and we get the alignments we want so...
*/
-static int __init
-find_bootmap_space(unsigned long pstart, unsigned long length, int node)
+static int __init find_pernode_space(unsigned long start, unsigned long len,
+ int node)
{
- unsigned long mapsize, pages, epfn;
- bootmem_data_t *bdp;
+ unsigned long epfn, cpu, cpus;
+ unsigned long pernodesize = 0, pernode;
+ void *cpu_data;
+ struct bootmem_data *bdp = &mem_data[node].bootmem_data;
- epfn = (pstart + length) >> PAGE_SHIFT;
- bdp = &pg_data_ptr[node]->bdata[0];
+ epfn = (start + len) >> PAGE_SHIFT;
- if (pstart < bdp->node_boot_start || epfn > bdp->node_low_pfn)
+ /*
+ * Make sure this memory falls within this node's usable memory
+ * since we may have thrown some away in build_maps().
+ */
+ if (start < bdp->node_boot_start ||
+ epfn > bdp->node_low_pfn)
return 0;
- if (!bdp->node_bootmem_map) {
- pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
+ /* Don't setup this node's local space twice... */
+ if (!mem_data[node].pernode_addr) {
+ /*
+ * Calculate total size needed, incl. what's necessary
+ * for good alignment and alias prevention.
+ */
+ cpus = early_nr_cpus_node(node);
+ pernodesize += PERCPU_PAGE_SIZE * cpus;
+ pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
+ pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+ pernodesize = PAGE_ALIGN(pernodesize);
+ pernode = NODEDATA_ALIGN(start, node);
+
+ /* Is this range big enough for what we want to store here? */
+ if (start + len > (pernode + pernodesize)) {
+ mem_data[node].pernode_addr = pernode;
+ mem_data[node].pernode_size = pernodesize;
+ memset(__va(pernode), 0, pernodesize);
+
+ cpu_data = (void *)pernode;
+ pernode += PERCPU_PAGE_SIZE * cpus;
+
+ mem_data[node].pgdat = __va(pernode);
+ pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+ mem_data[node].node_data = __va(pernode);
+ pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+
+ mem_data[node].pgdat->bdata = bdp;
+ pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+ /*
+ * Copy the static per-cpu data into the region we
+ * just set aside and then setup __per_cpu_offset
+ * for each CPU on this node.
+ */
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ if (node == node_cpuid[cpu].nid) {
+ memcpy(cpu_data, __phys_per_cpu_start,
+ __per_cpu_end-__per_cpu_start);
+ __per_cpu_offset[cpu] =
+ (char*)__va(cpu_data) -
+ __per_cpu_start;
+ cpu_data += PERCPU_PAGE_SIZE;
+ }
+ }
+ }
+ }
+
+ pernode = mem_data[node].pernode_addr;
+ pernodesize = mem_data[node].pernode_size;
+ if (pernode && !bdp->node_bootmem_map) {
+ unsigned long pages, mapsize, map = 0;
+
+ pages = bdp->node_low_pfn -
+ (bdp->node_boot_start >> PAGE_SHIFT);
mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
- if (length > mapsize) {
- init_bootmem_node(
- BOOT_NODE_DATA(node),
- pstart>>PAGE_SHIFT,
- bdp->node_boot_start>>PAGE_SHIFT,
- bdp->node_low_pfn);
+
+ /*
+ * The map will either contain the pernode area or begin
+ * after it.
+ */
+ if (pernode - start > mapsize)
+ map = start;
+ else if (start + len - pernode - pernodesize > mapsize)
+ map = pernode + pernodesize;
+
+ if (map) {
+ init_bootmem_node(mem_data[node].pgdat,
+ map>>PAGE_SHIFT,
+ bdp->node_boot_start>>PAGE_SHIFT,
+ bdp->node_low_pfn);
}
}
@@ -133,85 +227,93 @@ find_bootmap_space(unsigned long pstart, unsigned long length, int node)
return 0;
}
-
-/*
- * Free available memory to the bootmem allocator.
- *
- * Note that only blocks that are free are passed to this routine (currently
- * filtered by free_available_memory).
+/**
+ * free_node_bootmem - free bootmem allocator memory for use
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
*
+ * Simply calls the bootmem allocator to free the specified ranged from
+ * the given pg_data_t's bdata struct. After this function has been called
+ * for all the entries in the EFI memory map, the bootmem allocator will
+ * be ready to service allocation requests.
*/
-static int __init
-discontig_free_bootmem_node(unsigned long pstart, unsigned long length, int node)
+static int __init free_node_bootmem(unsigned long start, unsigned long len,
+ int node)
{
- free_bootmem_node(BOOT_NODE_DATA(node), pstart, length);
+ free_bootmem_node(mem_data[node].pgdat, start, len);
return 0;
}
-
-/*
- * Reserve the space used by the bootmem maps.
+/**
+ * reserve_pernode_space - reserve memory for per-node space
+ *
+ * Reserve the space used by the bootmem maps & per-node space in the boot
+ * allocator so that when we actually create the real mem maps we don't
+ * use their memory.
*/
-static void __init
-discontig_reserve_bootmem(void)
+static void __init reserve_pernode_space(void)
{
- int node;
- unsigned long mapbase, mapsize, pages;
- bootmem_data_t *bdp;
+ unsigned long base, size, pages;
+ struct bootmem_data *bdp;
+ int node;
for (node = 0; node < numnodes; node++) {
- bdp = BOOT_NODE_DATA(node)->bdata;
+ pg_data_t *pdp = mem_data[node].pgdat;
+ bdp = pdp->bdata;
+
+ /* First the bootmem_map itself */
pages = bdp->node_low_pfn - (bdp->node_boot_start>>PAGE_SHIFT);
- mapsize = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
- mapbase = __pa(bdp->node_bootmem_map);
- reserve_bootmem_node(BOOT_NODE_DATA(node), mapbase, mapsize);
+ size = bootmem_bootmap_pages(pages) << PAGE_SHIFT;
+ base = __pa(bdp->node_bootmem_map);
+ reserve_bootmem_node(pdp, base, size);
+
+ /* Now the per-node space */
+ size = mem_data[node].pernode_size;
+ base = __pa(mem_data[node].pernode_addr);
+ reserve_bootmem_node(pdp, base, size);
}
}
-/*
- * Allocate per node tables.
- * - the pg_data structure is allocated on each node. This minimizes offnode
- * memory references
- * - the node data is allocated & initialized. Portions of this structure is read-only (after
- * boot) and contains node-local pointers to usefuls data structures located on
- * other nodes.
+/**
+ * initialize_pernode_data - fixup per-cpu & per-node pointers
*
- * We also switch to using the "real" pg_data structures at this point. Earlier in boot, we
- * use a different structure. The only use for pg_data prior to the point in boot is to get
- * the pointer to the bdata for the node.
+ * Each node's per-node area has a copy of the global pg_data_t list, so
+ * we copy that to each node here, as well as setting the per-cpu pointer
+ * to the local node data structure. The active_cpus field of the per-node
+ * structure gets setup by the platform_cpu_init() function later.
*/
-static void __init
-allocate_pernode_structures(void)
+static void __init initialize_pernode_data(void)
{
- pg_data_t *pgdat=0, *new_pgdat_list=0;
- int node, mynode;
-
- mynode = boot_get_local_nodeid();
- for (node = numnodes - 1; node >= 0 ; node--) {
- node_data[node] = alloc_bootmem_node(BOOT_NODE_DATA(node), sizeof (struct ia64_node_data));
- pgdat = __alloc_bootmem_node(BOOT_NODE_DATA(node), sizeof(pg_data_t), SMP_CACHE_BYTES, 0);
- pgdat->bdata = &(bdata[node][0]);
- pg_data_ptr[node] = pgdat;
- pgdat->pgdat_next = new_pgdat_list;
- new_pgdat_list = pgdat;
- }
+ int cpu, node;
+ pg_data_t *pgdat_list[NR_NODES];
+
+ for (node = 0; node < numnodes; node++)
+ pgdat_list[node] = mem_data[node].pgdat;
- memcpy(node_data[mynode]->pg_data_ptrs, pg_data_ptr, sizeof(pg_data_ptr));
- memcpy(node_data[mynode]->node_data_ptrs, node_data, sizeof(node_data));
+ /* Copy the pg_data_t list to each node and init the node field */
+ for (node = 0; node < numnodes; node++) {
+ memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
+ sizeof(pgdat_list));
+ }
- pgdat_list = new_pgdat_list;
+ /* Set the node_data pointer for each per-cpu struct */
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ node = node_cpuid[cpu].nid;
+ per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data;
+ }
}
-/*
- * Called early in boot to setup the boot memory allocator, and to
- * allocate the node-local pg_data & node-directory data structures..
+/**
+ * find_memory - walk the EFI memory map and setup the bootmem allocator
+ *
+ * Called early in boot to setup the bootmem allocator, and to
+ * allocate the per-cpu and per-node structures.
*/
void __init find_memory(void)
{
- int node;
-
reserve_memory();
if (numnodes == 0) {
@@ -219,94 +321,48 @@ void __init find_memory(void)
numnodes = 1;
}
- for (node = 0; node < numnodes; node++) {
- pg_data_ptr[node] = (pg_data_t*) &boot_pg_data[node];
- pg_data_ptr[node]->bdata = &bdata[node][0];
- }
-
min_low_pfn = -1;
max_low_pfn = 0;
- efi_memmap_walk(filter_rsvd_memory, build_maps);
- efi_memmap_walk(filter_rsvd_memory, find_bootmap_space);
- efi_memmap_walk(filter_rsvd_memory, discontig_free_bootmem_node);
- discontig_reserve_bootmem();
- allocate_pernode_structures();
+ /* These actually end up getting called by call_pernode_memory() */
+ efi_memmap_walk(filter_rsvd_memory, build_node_maps);
+ efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
+ efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
+
+ reserve_pernode_space();
+ initialize_pernode_data();
+
+ max_pfn = max_low_pfn;
find_initrd();
}
-/*
- * Initialize the paging system.
- * - determine sizes of each node
- * - initialize the paging system for the node
- * - build the nodedir for the node. This contains pointers to
- * the per-bank mem_map entries.
- * - fix the page struct "virtual" pointers. These are bank specific
- * values that the paging system doesn't understand.
- * - replicate the nodedir structure to other nodes
+/**
+ * per_cpu_init - setup per-cpu variables
+ *
+ * find_pernode_space() does most of this already, we just need to set
+ * local_per_cpu_offset
*/
-
-void __init
-discontig_paging_init(void)
+void *per_cpu_init(void)
{
- int node, mynode;
- unsigned long max_dma, zones_size[MAX_NR_ZONES];
- unsigned long kaddr, ekaddr, bid;
- struct page *page;
- bootmem_data_t *bdp;
-
- max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
- mynode = boot_get_local_nodeid();
- for (node = 0; node < numnodes; node++) {
- long pfn, startpfn;
-
- memset(zones_size, 0, sizeof(zones_size));
+ int cpu;
- startpfn = -1;
- bdp = BOOT_NODE_DATA(node)->bdata;
- pfn = bdp->node_boot_start >> PAGE_SHIFT;
- if (startpfn == -1)
- startpfn = pfn;
- if (pfn > max_dma)
- zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - pfn);
- else if (bdp->node_low_pfn < max_dma)
- zones_size[ZONE_DMA] += (bdp->node_low_pfn - pfn);
- else {
- zones_size[ZONE_DMA] += (max_dma - pfn);
- zones_size[ZONE_NORMAL] += (bdp->node_low_pfn - max_dma);
- }
-
- free_area_init_node(node, NODE_DATA(node), NULL, zones_size, startpfn, 0);
-
- page = NODE_DATA(node)->node_mem_map;
-
- bdp = BOOT_NODE_DATA(node)->bdata;
-
- kaddr = (unsigned long)__va(bdp->node_boot_start);
- ekaddr = (unsigned long)__va(bdp->node_low_pfn << PAGE_SHIFT);
- while (kaddr < ekaddr) {
- if (paddr_to_nid(__pa(kaddr)) == node) {
- bid = BANK_MEM_MAP_INDEX(kaddr);
- node_data[mynode]->node_id_map[bid] = node;
- node_data[mynode]->bank_mem_map_base[bid] = page;
- }
- kaddr += BANKSIZE;
- page += BANKSIZE/PAGE_SIZE;
+ if (smp_processor_id() == 0) {
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ per_cpu(local_per_cpu_offset, cpu) =
+ __per_cpu_offset[cpu];
}
}
- /*
- * Finish setting up the node data for this node, then copy it to the other nodes.
- */
- for (node=0; node < numnodes; node++)
- if (mynode != node) {
- memcpy(node_data[node], node_data[mynode], sizeof(struct ia64_node_data));
- node_data[node]->node = node;
- }
+ return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
}
+/**
+ * show_mem - give short summary of memory stats
+ *
+ * Shows a simple page count of reserved and used pages in the system.
+ * For discontig machines, it does this on a per-pgdat basis.
+ */
void show_mem(void)
{
int i, reserved = 0;
@@ -335,7 +391,12 @@ void show_mem(void)
printk("%d free buffer pages\n", nr_free_buffer_pages());
}
-/*
+/**
+ * call_pernode_memory - use SRAT to call callback functions with node info
+ * @start: physical start of range
+ * @len: length of range
+ * @arg: function to call for each range
+ *
* efi_memmap_walk() knows nothing about layout of memory across nodes. Find
* out to which node a block of memory belongs. Ignore memory that we cannot
* identify, and split blocks that run across multiple nodes.
@@ -343,10 +404,10 @@ void show_mem(void)
* Take this opportunity to round the start address up and the end address
* down to page boundaries.
*/
-void call_pernode_memory(unsigned long start, unsigned long end, void *arg)
+void call_pernode_memory(unsigned long start, unsigned long len, void *arg)
{
- unsigned long rs, re;
- void (*func)(unsigned long, unsigned long, int, int);
+ unsigned long rs, re, end = start + len;
+ void (*func)(unsigned long, unsigned long, int);
int i;
start = PAGE_ALIGN(start);
@@ -357,21 +418,127 @@ void call_pernode_memory(unsigned long start, unsigned long end, void *arg)
func = arg;
if (!num_memblks) {
- /*
- * This machine doesn't have SRAT, so call func with
- * nid=0, bank=0.
- */
+ /* No SRAT table, to assume one node (node 0) */
if (start < end)
- (*func)(start, end - start, 0, 0);
+ (*func)(start, len, 0);
return;
}
for (i = 0; i < num_memblks; i++) {
rs = max(start, node_memblk[i].start_paddr);
- re = min(end, node_memblk[i].start_paddr+node_memblk[i].size);
+ re = min(end, node_memblk[i].start_paddr +
+ node_memblk[i].size);
if (rs < re)
- (*func)(rs, re-rs, node_memblk[i].nid,
- node_memblk[i].bank);
+ (*func)(rs, re - rs, node_memblk[i].nid);
+
+ if (re == end)
+ break;
}
}
+
+/**
+ * count_node_pages - callback to build per-node memory info structures
+ * @start: physical start of range
+ * @len: length of range
+ * @node: node where this range resides
+ *
+ * Each node has it's own number of physical pages, DMAable pages, start, and
+ * end page frame number. This routine will be called by call_pernode_memory()
+ * for each piece of usable memory and will setup these values for each node.
+ * Very similar to build_maps().
+ */
+static int count_node_pages(unsigned long start, unsigned long len, int node)
+{
+ unsigned long end = start + len;
+
+ mem_data[node].num_physpages += len >> PAGE_SHIFT;
+ if (start <= __pa(MAX_DMA_ADDRESS))
+ mem_data[node].num_dma_physpages +=
+ (min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT;
+ start = GRANULEROUNDDOWN(start);
+ start = ORDERROUNDDOWN(start);
+ end = GRANULEROUNDUP(end);
+ mem_data[node].max_pfn = max(mem_data[node].max_pfn,
+ end >> PAGE_SHIFT);
+ mem_data[node].min_pfn = min(mem_data[node].min_pfn,
+ start >> PAGE_SHIFT);
+
+ return 0;
+}
+
+/**
+ * paging_init - setup page tables
+ *
+ * paging_init() sets up the page tables for each node of the system and frees
+ * the bootmem allocator memory for general use.
+ */
+void paging_init(void)
+{
+ unsigned long max_dma;
+ unsigned long zones_size[MAX_NR_ZONES];
+ unsigned long zholes_size[MAX_NR_ZONES];
+ unsigned long max_gap, pfn_offset = 0;
+ int node;
+
+ max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ max_gap = 0;
+ efi_memmap_walk(find_largest_hole, &max_gap);
+
+ /* so min() will work in count_node_pages */
+ for (node = 0; node < numnodes; node++)
+ mem_data[node].min_pfn = ~0UL;
+
+ efi_memmap_walk(filter_rsvd_memory, count_node_pages);
+
+ for (node = 0; node < numnodes; node++) {
+ memset(zones_size, 0, sizeof(zones_size));
+ memset(zholes_size, 0, sizeof(zholes_size));
+
+ num_physpages += mem_data[node].num_physpages;
+
+ if (mem_data[node].min_pfn >= max_dma) {
+ /* All of this node's memory is above ZONE_DMA */
+ zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+ mem_data[node].min_pfn;
+ zholes_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+ mem_data[node].min_pfn -
+ mem_data[node].num_physpages;
+ } else if (mem_data[node].max_pfn < max_dma) {
+ /* All of this node's memory is in ZONE_DMA */
+ zones_size[ZONE_DMA] = mem_data[node].max_pfn -
+ mem_data[node].min_pfn;
+ zholes_size[ZONE_DMA] = mem_data[node].max_pfn -
+ mem_data[node].min_pfn -
+ mem_data[node].num_dma_physpages;
+ } else {
+ /* This node has memory in both zones */
+ zones_size[ZONE_DMA] = max_dma -
+ mem_data[node].min_pfn;
+ zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
+ mem_data[node].num_dma_physpages;
+ zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
+ max_dma;
+ zholes_size[ZONE_NORMAL] = zones_size[ZONE_NORMAL] -
+ (mem_data[node].num_physpages -
+ mem_data[node].num_dma_physpages);
+ }
+
+ if (node == 0) {
+ vmalloc_end -=
+ PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+ vmem_map = (struct page *) vmalloc_end;
+
+ efi_memmap_walk(create_mem_map_page_table, 0);
+ printk("Virtual mem_map starts at 0x%p\n", vmem_map);
+ }
+
+ pfn_offset = mem_data[node].min_pfn;
+
+ free_area_init_node(node, NODE_DATA(node),
+ vmem_map + pfn_offset, zones_size,
+ pfn_offset, zholes_size);
+ }
+
+ zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
+}
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 6a2e5a23f87d..9e366cb10297 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -20,13 +20,46 @@
#define TASK_HPAGE_BASE (REGION_HPAGE << REGION_SHIFT)
-static long htlbpagemem;
-int htlbpage_max;
-static long htlbzone_pages;
+static long htlbpagemem;
+int htlbpage_max;
+static long htlbzone_pages;
-static LIST_HEAD(htlbpage_freelist);
+static struct list_head hugepage_freelists[MAX_NUMNODES];
static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
+static void enqueue_huge_page(struct page *page)
+{
+ list_add(&page->list,
+ &hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
+}
+
+static struct page *dequeue_huge_page(void)
+{
+ int nid = numa_node_id();
+ struct page *page = NULL;
+
+ if (list_empty(&hugepage_freelists[nid])) {
+ for (nid = 0; nid < MAX_NUMNODES; ++nid)
+ if (!list_empty(&hugepage_freelists[nid]))
+ break;
+ }
+ if (nid >= 0 && nid < MAX_NUMNODES &&
+ !list_empty(&hugepage_freelists[nid])) {
+ page = list_entry(hugepage_freelists[nid].next, struct page, list);
+ list_del(&page->list);
+ }
+ return page;
+}
+
+static struct page *alloc_fresh_huge_page(void)
+{
+ static int nid = 0;
+ struct page *page;
+ page = alloc_pages_node(nid, GFP_HIGHUSER, HUGETLB_PAGE_ORDER);
+ nid = (nid + 1) % numnodes;
+ return page;
+}
+
void free_huge_page(struct page *page);
static struct page *alloc_hugetlb_page(void)
@@ -35,13 +68,11 @@ static struct page *alloc_hugetlb_page(void)
struct page *page;
spin_lock(&htlbpage_lock);
- if (list_empty(&htlbpage_freelist)) {
+ page = dequeue_huge_page();
+ if (!page) {
spin_unlock(&htlbpage_lock);
return NULL;
}
-
- page = list_entry(htlbpage_freelist.next, struct page, list);
- list_del(&page->list);
htlbpagemem--;
spin_unlock(&htlbpage_lock);
set_page_count(page, 1);
@@ -228,7 +259,7 @@ void free_huge_page(struct page *page)
INIT_LIST_HEAD(&page->list);
spin_lock(&htlbpage_lock);
- list_add(&page->list, &htlbpage_freelist);
+ enqueue_huge_page(page);
htlbpagemem++;
spin_unlock(&htlbpage_lock);
}
@@ -371,7 +402,7 @@ int try_to_free_low(int count)
map = NULL;
spin_lock(&htlbpage_lock);
- list_for_each(p, &htlbpage_freelist) {
+ list_for_each(p, &hugepage_freelists[0]) {
if (map) {
list_del(&map->list);
update_and_free_page(map);
@@ -408,11 +439,11 @@ int set_hugetlb_mem_size(int count)
return (int)htlbzone_pages;
if (lcount > 0) { /* Increase the mem size. */
while (lcount--) {
- page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
+ page = alloc_fresh_huge_page();
if (page == NULL)
break;
spin_lock(&htlbpage_lock);
- list_add(&page->list, &htlbpage_freelist);
+ enqueue_huge_page(page);
htlbpagemem++;
htlbzone_pages++;
spin_unlock(&htlbpage_lock);
@@ -449,17 +480,18 @@ __setup("hugepages=", hugetlb_setup);
static int __init hugetlb_init(void)
{
- int i, j;
+ int i;
struct page *page;
+ for (i = 0; i < MAX_NUMNODES; ++i)
+ INIT_LIST_HEAD(&hugepage_freelists[i]);
+
for (i = 0; i < htlbpage_max; ++i) {
- page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
+ page = alloc_fresh_huge_page();
if (!page)
break;
- for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j)
- SetPageReserved(&page[j]);
spin_lock(&htlbpage_lock);
- list_add(&page->list, &htlbpage_freelist);
+ enqueue_huge_page(page);
spin_unlock(&htlbpage_lock);
}
htlbpage_max = htlbpagemem = htlbzone_pages = i;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 05dc179d45d6..0616dcb73698 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -24,6 +24,7 @@
#include <asm/ia32.h>
#include <asm/io.h>
#include <asm/machvec.h>
+#include <asm/numa.h>
#include <asm/patch.h>
#include <asm/pgalloc.h>
#include <asm/sal.h>
@@ -40,10 +41,8 @@ extern void ia64_tlb_init (void);
unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
#ifdef CONFIG_VIRTUAL_MEM_MAP
-# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */
unsigned long vmalloc_end = VMALLOC_END_INIT;
- static struct page *vmem_map;
- static unsigned long num_dma_physpages;
+ struct page *vmem_map;
#endif
static int pgt_cache_water[2] = { 25, 50 };
@@ -337,11 +336,12 @@ ia64_mmu_init (void *my_cpu_data)
#ifdef CONFIG_VIRTUAL_MEM_MAP
-static int
+int
create_mem_map_page_table (u64 start, u64 end, void *arg)
{
unsigned long address, start_page, end_page;
struct page *map_start, *map_end;
+ int node;
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
@@ -351,19 +351,20 @@ create_mem_map_page_table (u64 start, u64 end, void *arg)
start_page = (unsigned long) map_start & PAGE_MASK;
end_page = PAGE_ALIGN((unsigned long) map_end);
+ node = paddr_to_nid(__pa(start));
for (address = start_page; address < end_page; address += PAGE_SIZE) {
pgd = pgd_offset_k(address);
if (pgd_none(*pgd))
- pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE));
+ pgd_populate(&init_mm, pgd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE));
pmd = pmd_offset(pgd, address);
if (pmd_none(*pmd))
- pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE));
+ pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE));
pte = pte_offset_kernel(pmd, address);
if (pte_none(*pte))
- set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages(PAGE_SIZE)) >> PAGE_SHIFT,
+ set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages_node(NODE_DATA(node), PAGE_SIZE)) >> PAGE_SHIFT,
PAGE_KERNEL));
}
return 0;
@@ -433,17 +434,7 @@ ia64_pfn_valid (unsigned long pfn)
return __get_user(byte, (char *) pfn_to_page(pfn)) == 0;
}
-static int
-count_dma_pages (u64 start, u64 end, void *arg)
-{
- unsigned long *count = arg;
-
- if (end <= MAX_DMA_ADDRESS)
- *count += (end - start) >> PAGE_SHIFT;
- return 0;
-}
-
-static int
+int
find_largest_hole (u64 start, u64 end, void *arg)
{
u64 *max_gap = arg;
@@ -460,103 +451,6 @@ find_largest_hole (u64 start, u64 end, void *arg)
#endif /* CONFIG_VIRTUAL_MEM_MAP */
static int
-count_pages (u64 start, u64 end, void *arg)
-{
- unsigned long *count = arg;
-
- *count += (end - start) >> PAGE_SHIFT;
- return 0;
-}
-
-/*
- * Set up the page tables.
- */
-
-#ifdef CONFIG_DISCONTIGMEM
-void
-paging_init (void)
-{
- extern void discontig_paging_init(void);
-
- discontig_paging_init();
- efi_memmap_walk(count_pages, &num_physpages);
- zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
-}
-#else /* !CONFIG_DISCONTIGMEM */
-void
-paging_init (void)
-{
- unsigned long max_dma;
- unsigned long zones_size[MAX_NR_ZONES];
-# ifdef CONFIG_VIRTUAL_MEM_MAP
- unsigned long zholes_size[MAX_NR_ZONES];
- unsigned long max_gap;
-# endif
-
- /* initialize mem_map[] */
-
- memset(zones_size, 0, sizeof(zones_size));
-
- num_physpages = 0;
- efi_memmap_walk(count_pages, &num_physpages);
-
- max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
-# ifdef CONFIG_VIRTUAL_MEM_MAP
- memset(zholes_size, 0, sizeof(zholes_size));
-
- num_dma_physpages = 0;
- efi_memmap_walk(count_dma_pages, &num_dma_physpages);
-
- if (max_low_pfn < max_dma) {
- zones_size[ZONE_DMA] = max_low_pfn;
- zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
- } else {
- zones_size[ZONE_DMA] = max_dma;
- zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
- if (num_physpages > num_dma_physpages) {
- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
- zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
- - (num_physpages - num_dma_physpages));
- }
- }
-
- max_gap = 0;
- efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
- if (max_gap < LARGE_GAP) {
- vmem_map = (struct page *) 0;
- free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, zholes_size);
- mem_map = contig_page_data.node_mem_map;
- }
- else {
- unsigned long map_size;
-
- /* allocate virtual_mem_map */
-
- map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
- vmalloc_end -= map_size;
- vmem_map = (struct page *) vmalloc_end;
- efi_memmap_walk(create_mem_map_page_table, 0);
-
- free_area_init_node(0, &contig_page_data, vmem_map, zones_size, 0, zholes_size);
-
- mem_map = contig_page_data.node_mem_map;
- printk("Virtual mem_map starts at 0x%p\n", mem_map);
- }
-# else /* !CONFIG_VIRTUAL_MEM_MAP */
- if (max_low_pfn < max_dma)
- zones_size[ZONE_DMA] = max_low_pfn;
- else {
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
- }
- free_area_init(zones_size);
-# endif /* !CONFIG_VIRTUAL_MEM_MAP */
- zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
-}
-#endif /* !CONFIG_DISCONTIGMEM */
-
-static int
count_reserved_pages (u64 start, u64 end, void *arg)
{
unsigned long num_reserved = 0;
diff --git a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c
index e07fc54ead92..33c3f4b5a858 100644
--- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c
+++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c
@@ -867,6 +867,9 @@ sn_pci_init (void)
int i = 0;
struct pci_controller *controller;
+ if (!ia64_platform_is("sn2"))
+ return 0;
+
/*
* set pci_raw_ops, etc.
*/
diff --git a/arch/ia64/sn/io/sn2/ml_SN_intr.c b/arch/ia64/sn/io/sn2/ml_SN_intr.c
index 9d1441419418..9249633fa7fa 100644
--- a/arch/ia64/sn/io/sn2/ml_SN_intr.c
+++ b/arch/ia64/sn/io/sn2/ml_SN_intr.c
@@ -285,7 +285,6 @@ static cpuid_t intr_cpu_choose_node(void)
cpuid_t intr_heuristic(vertex_hdl_t dev, int req_bit, int *resp_bit)
{
cpuid_t cpuid;
- cpuid_t candidate = CPU_NONE;
vertex_hdl_t pconn_vhdl;
pcibr_soft_t pcibr_soft;
int bit;
@@ -293,30 +292,32 @@ cpuid_t intr_heuristic(vertex_hdl_t dev, int req_bit, int *resp_bit)
/* XXX: gross layering violation.. */
if (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) {
pcibr_soft = pcibr_soft_get(pconn_vhdl);
- if (pcibr_soft && pcibr_soft->bsi_err_intr)
- candidate = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
- }
-
- if (candidate != CPU_NONE) {
- /*
- * The cpu was chosen already when we assigned
- * the error interrupt.
- */
- bit = intr_reserve_level(candidate, req_bit);
- if (bit >= 0) {
- *resp_bit = bit;
- return candidate;
+ if (pcibr_soft && pcibr_soft->bsi_err_intr) {
+ /*
+ * The cpu was chosen already when we assigned
+ * the error interrupt.
+ */
+ cpuid = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
+ goto done;
}
-
- printk("Cannot target interrupt to target node (%ld).\n",candidate);
- return CPU_NONE;
}
/*
* Need to choose one. Try the controlling c-brick first.
*/
cpuid = intr_cpu_choose_from_node(master_node_get(dev));
- if (cpuid != CPU_NONE)
- return cpuid;
- return intr_cpu_choose_node();
+ if (cpuid == CPU_NONE)
+ cpuid = intr_cpu_choose_node();
+
+ done:
+ if (cpuid != CPU_NONE) {
+ bit = intr_reserve_level(cpuid, req_bit);
+ if (bit >= 0) {
+ *resp_bit = bit;
+ return cpuid;
+ }
+ }
+
+ printk("Cannot target interrupt to target cpu (%ld).\n", cpuid);
+ return CPU_NONE;
}
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 5e28754ca51b..5a8b566c8677 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -147,7 +147,6 @@ char drive_info[4*16];
* Sets up an initial console to aid debugging. Intended primarily
* for bringup. See start_kernel() in init/main.c.
*/
-#if defined(CONFIG_IA64_EARLY_PRINTK_SGI_SN) || defined(CONFIG_IA64_SGI_SN_SIM)
void __init
early_sn_setup(void)
@@ -189,7 +188,6 @@ early_sn_setup(void)
printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address);
}
}
-#endif /* CONFIG_IA64_EARLY_PRINTK_SGI_SN */
#ifdef CONFIG_IA64_MCA
extern int platform_intr_list[];
diff --git a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c
index 92764186fd06..f1f96bd651a4 100644
--- a/arch/ia64/sn/kernel/sn2/io.c
+++ b/arch/ia64/sn/kernel/sn2/io.c
@@ -11,6 +11,8 @@
#include <asm/sn/sn2/io.h>
+#ifdef CONFIG_IA64_GENERIC
+
#undef __sn_inb
#undef __sn_inw
#undef __sn_inl
@@ -81,3 +83,5 @@ __sn_readq (void *addr)
{
return ___sn_readq (addr);
}
+
+#endif
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
index de88091e4646..4e0e312fc3ae 100644
--- a/arch/m68k/lib/checksum.c
+++ b/arch/m68k/lib/checksum.c
@@ -125,6 +125,7 @@ csum_partial (const unsigned char *buff, int len, unsigned int sum)
return(sum);
}
+EXPORT_SYMBOL(csum_partial);
/*
diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c
index 52a39cb28b97..babdbfa3cda7 100644
--- a/arch/m68k/sun3/sbus.c
+++ b/arch/m68k/sun3/sbus.c
@@ -10,6 +10,7 @@
*/
#include <linux/types.h>
+#include <linux/compiler.h>
#include <linux/init.h>
int __init sbus_init(void)
diff --git a/arch/ppc/boot/of1275/map.c b/arch/ppc/boot/of1275/map.c
index 5a21702dc8ca..443256c6f6d6 100644
--- a/arch/ppc/boot/of1275/map.c
+++ b/arch/ppc/boot/of1275/map.c
@@ -23,11 +23,10 @@ map(unsigned int phys, unsigned int virt, unsigned int size)
char *method;
ihandle mmu_ihandle;
int misc;
- unsigned int phys;
- unsigned int virt;
unsigned int size;
+ unsigned int virt;
+ unsigned int phys;
int ret0;
- int ret1;
} args;
if (of_prom_mmu == 0) {
@@ -36,10 +35,10 @@ map(unsigned int phys, unsigned int virt, unsigned int size)
}
args.service = "call-method";
args.nargs = 6;
- args.nret = 2;
+ args.nret = 1;
args.method = "map";
args.mmu_ihandle = of_prom_mmu;
- args.misc = -1;
+ args.misc = 0;
args.phys = phys;
args.virt = virt;
args.size = size;
diff --git a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c
index 6813af9a753c..94c23c0c954b 100644
--- a/arch/ppc/boot/openfirmware/coffmain.c
+++ b/arch/ppc/boot/openfirmware/coffmain.c
@@ -38,9 +38,9 @@ static char heap[SCRATCH_SIZE];
static unsigned long ram_start = 0;
static unsigned long ram_end = 0x1000000;
-static unsigned long prog_start = 0x800000;
-static unsigned long prog_size = 0x800000;
+static unsigned long prog_start = 0x900000;
+static unsigned long prog_size = 0x700000;
typedef void (*kernel_start_t)(int, int, void *);
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 9cdd59542400..4f4c12491d7a 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -181,26 +181,8 @@ __after_mmu_off:
bl setup_disp_bat
#endif
#else /* CONFIG_POWER4 */
-/*
- * Load up the SDR1 and segment register values now
- * since we don't have the BATs.
- * Also make sure we are running in 32-bit mode.
- */
bl reloc_offset
- addis r14,r3,_SDR1@ha /* get the value from _SDR1 */
- lwz r14,_SDR1@l(r14) /* assume hash table below 4GB */
- mtspr SDR1,r14
- slbia
- lis r4,0x2000 /* set pseudo-segment reg 12 */
- ori r5,r4,0x0ccc
- mtsr 12,r5
- ori r4,r4,0x0888 /* set pseudo-segment reg 8 */
- mtsr 8,r4 /* (for access to serial port) */
- mfmsr r0
- clrldi r0,r0,1
- sync
- mtmsr r0
- isync
+ bl initial_mm_power4
#endif /* CONFIG_POWER4 */
/*
@@ -1637,6 +1619,34 @@ setup_disp_bat:
#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
#else /* CONFIG_POWER4 */
+/*
+ * Load up the SDR1 and segment register values now
+ * since we don't have the BATs.
+ * Also make sure we are running in 32-bit mode.
+ */
+
+initial_mm_power4:
+ addis r14,r3,_SDR1@ha /* get the value from _SDR1 */
+ lwz r14,_SDR1@l(r14) /* assume hash table below 4GB */
+ mtspr SDR1,r14
+ slbia
+ lis r4,0x2000 /* set pseudo-segment reg 12 */
+ ori r5,r4,0x0ccc
+ mtsr 12,r5
+ ori r5,r4,0x0888 /* set pseudo-segment reg 8 */
+ mtsr 8,r5 /* (for access to serial port) */
+ ori r5,r4,0x0999 /* set pseudo-segment reg 8 */
+ mtsr 9,r5 /* (for access to screen) */
+ mfmsr r0
+ clrldi r0,r0,1
+ sync
+ mtmsr r0
+ isync
+ blr
+
+/*
+ * On 970 (G5), we pre-set a few bits in HID0 & HID1
+ */
ppc970_setup_hid:
li r0,0
sync
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 093bdc565c24..825fd2db1f87 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -367,11 +367,17 @@ EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context);
EXPORT_SYMBOL(handle_mm_fault); /* For MOL */
EXPORT_SYMBOL_NOVERS(disarm_decr);
+extern long mol_trampoline;
+EXPORT_SYMBOL(mol_trampoline); /* For MOL */
#ifdef CONFIG_PPC_STD_MMU
EXPORT_SYMBOL(flush_hash_pages); /* For MOL */
+#ifdef CONFIG_SMP
+extern int mmu_hash_lock;
+EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */
+#endif /* CONFIG_SMP */
extern long *intercept_table;
EXPORT_SYMBOL(intercept_table);
-#endif
+#endif /* CONFIG_PPC_STD_MMU */
EXPORT_SYMBOL(cur_cpu_spec);
#ifdef CONFIG_PPC_PMAC
extern unsigned long agp_special_page;
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 69d111262cbe..cc18be59baf0 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -56,6 +56,7 @@ static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
/* this is 8kB-aligned so we can get to the thread_info struct
at the base of it from the stack pointer with 1 integer instruction. */
diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
index e7732c4331ea..e79761e10ff0 100644
--- a/arch/ppc/mm/hashtable.S
+++ b/arch/ppc/mm/hashtable.S
@@ -417,6 +417,21 @@ _GLOBAL(hash_page_patch_C)
lwz r6,next_slot@l(r4)
addi r6,r6,PTE_SIZE
andi. r6,r6,7*PTE_SIZE
+#ifdef CONFIG_POWER4
+ /*
+ * Since we don't have BATs on POWER4, we rely on always having
+ * PTEs in the hash table to map the hash table and the code
+ * that manipulates it in virtual mode, namely flush_hash_page and
+ * flush_hash_segments. Otherwise we can get a DSI inside those
+ * routines which leads to a deadlock on the hash_table_lock on
+ * SMP machines. We avoid this by never overwriting the first
+ * PTE of each PTEG if it is already valid.
+ * -- paulus.
+ */
+ bne 102f
+ li r6,PTE_SIZE
+102:
+#endif /* CONFIG_POWER4 */
stw r6,next_slot@l(r4)
add r4,r3,r6
diff --git a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
index 3bb3c9a77ef5..c60064993417 100644
--- a/arch/ppc/mm/ppc_mmu.c
+++ b/arch/ppc/mm/ppc_mmu.c
@@ -211,6 +211,17 @@ void __init MMU_init_hw(void)
#define MIN_N_HPTEG 1024 /* min 64kB hash table */
#endif
+#ifdef CONFIG_POWER4
+ /* The hash table has already been allocated and initialized
+ in prom.c */
+ n_hpteg = Hash_size >> LG_HPTEG_SIZE;
+ lg_n_hpteg = __ilog2(n_hpteg);
+
+ /* Remove the hash table from the available memory */
+ if (Hash)
+ reserve_phys_mem(__pa(Hash), Hash_size);
+
+#else /* CONFIG_POWER4 */
/*
* Allow 1 HPTE (1/8 HPTEG) for each page of memory.
* This is less than the recommended amount, but then
@@ -224,13 +235,7 @@ void __init MMU_init_hw(void)
++lg_n_hpteg; /* round up if not power of 2 */
n_hpteg = 1 << lg_n_hpteg;
}
-
Hash_size = n_hpteg << LG_HPTEG_SIZE;
- Hash_mask = n_hpteg - 1;
- hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
- mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
- if (lg_n_hpteg > 16)
- mb2 = 16 - LG_HPTEG_SIZE;
/*
* Find some memory for the hash table.
@@ -240,6 +245,7 @@ void __init MMU_init_hw(void)
cacheable_memzero(Hash, Hash_size);
_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+#endif /* CONFIG_POWER4 */
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
total_memory >> 20, Hash_size >> 10, Hash);
@@ -249,6 +255,12 @@ void __init MMU_init_hw(void)
* Patch up the instructions in hashtable.S:create_hpte
*/
if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+ Hash_mask = n_hpteg - 1;
+ hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
+ mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
+ if (lg_n_hpteg > 16)
+ mb2 = 16 - LG_HPTEG_SIZE;
+
hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
| ((unsigned int)(Hash) >> 16);
hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
index 390b447218d5..d230b9890a05 100644
--- a/arch/ppc/platforms/pmac_smp.c
+++ b/arch/ppc/platforms/pmac_smp.c
@@ -51,6 +51,7 @@
#include <asm/time.h>
#include <asm/open_pic.h>
#include <asm/cacheflush.h>
+#include <asm/keylargo.h>
/*
* Powersurge (old powermac SMP) support.
@@ -108,9 +109,16 @@ static volatile u32 *psurge_start;
/* what sort of powersurge board we have */
static int psurge_type = PSURGE_NONE;
+/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
volatile static long int core99_l2_cache;
volatile static long int core99_l3_cache;
+/* Timebase freeze GPIO */
+static unsigned int core99_tb_gpio;
+
+/* Sync flag for HW tb sync */
+static volatile int sec_tb_reset = 0;
+
static void __init
core99_init_caches(int cpu)
{
@@ -380,7 +388,6 @@ static void __init smp_psurge_kick_cpu(int nr)
*/
static void __init psurge_dual_sync_tb(int cpu_nr)
{
- static volatile int sec_tb_reset = 0;
int t;
set_dec(tb_ticks_per_jiffy);
@@ -408,8 +415,15 @@ smp_psurge_setup_cpu(int cpu_nr)
{
if (cpu_nr == 0) {
- if (num_online_cpus() < 2)
+ /* If we failed to start the second CPU, we should still
+ * send it an IPI to start the timebase & DEC or we might
+ * have them stuck.
+ */
+ if (num_online_cpus() < 2) {
+ if (psurge_type == PSURGE_DUAL)
+ psurge_set_ipi(1);
return;
+ }
/* reset the entry point so if we get another intr we won't
* try to startup again */
out_be32(psurge_start, 0x100);
@@ -421,19 +435,42 @@ smp_psurge_setup_cpu(int cpu_nr)
psurge_dual_sync_tb(cpu_nr);
}
+void __init
+smp_psurge_take_timebase(void)
+{
+ /* Dummy implementation */
+}
+
+void __init
+smp_psurge_give_timebase(void)
+{
+ /* Dummy implementation */
+}
+
static int __init
smp_core99_probe(void)
{
+ extern int powersave_nap;
struct device_node *cpus;
int i, ncpus = 1;
- extern int powersave_nap;
+ u32 *tbprop;
if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
cpus = find_type_devices("cpu");
- if (cpus)
- while ((cpus = cpus->next) != NULL)
- ++ncpus;
+ if (cpus == NULL)
+ return 0;
+
+ tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL);
+ if (tbprop)
+ core99_tb_gpio = *tbprop;
+ else
+ core99_tb_gpio = KL_GPIO_TB_ENABLE;
+
+ while ((cpus = cpus->next) != NULL)
+ ++ncpus;
+
printk("smp_core99_probe: found %d cpus\n", ncpus);
+
if (ncpus > 1) {
openpic_request_IPIs();
for (i = 1; i < ncpus; ++i)
@@ -517,14 +554,59 @@ smp_core99_setup_cpu(int cpu_nr)
if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
}
+void __init
+smp_core99_take_timebase(void)
+{
+ /* Secondary processor "takes" the timebase by freezing
+ * it, resetting its local TB and telling CPU 0 to go on
+ */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
+ pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+ mb();
+
+ set_dec(tb_ticks_per_jiffy);
+ set_tb(0, 0);
+ last_jiffy_stamp(smp_processor_id()) = 0;
+
+ mb();
+ sec_tb_reset = 1;
+}
+
+void __init
+smp_core99_give_timebase(void)
+{
+ unsigned int t;
+
+ /* Primary processor waits for secondary to have frozen
+ * the timebase, resets local TB, and kick timebase again
+ */
+ /* wait for the secondary to have reset its TB before proceeding */
+ for (t = 1000; t > 0 && !sec_tb_reset; --t)
+ udelay(1000);
+ if (t == 0)
+ printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
+
+ set_dec(tb_ticks_per_jiffy);
+ set_tb(0, 0);
+ last_jiffy_stamp(smp_processor_id()) = 0;
+ mb();
+
+ /* Now, restart the timebase by leaving the GPIO to an open collector */
+ pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
+ pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
+
+ smp_tb_synchronized = 1;
+}
+
+
/* PowerSurge-style Macs */
struct smp_ops_t psurge_smp_ops __pmacdata = {
.message_pass = smp_psurge_message_pass,
.probe = smp_psurge_probe,
.kick_cpu = smp_psurge_kick_cpu,
.setup_cpu = smp_psurge_setup_cpu,
- .give_timebase = smp_generic_give_timebase,
- .take_timebase = smp_generic_take_timebase,
+ .give_timebase = smp_psurge_give_timebase,
+ .take_timebase = smp_psurge_take_timebase,
};
/* Core99 Macs (dual G4s) */
@@ -533,6 +615,6 @@ struct smp_ops_t core99_smp_ops __pmacdata = {
.probe = smp_core99_probe,
.kick_cpu = smp_core99_kick_cpu,
.setup_cpu = smp_core99_setup_cpu,
- .give_timebase = smp_generic_give_timebase,
- .take_timebase = smp_generic_take_timebase,
+ .give_timebase = smp_core99_give_timebase,
+ .take_timebase = smp_core99_take_timebase,
};
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
index 70e7408e43df..923afbdc7c56 100644
--- a/arch/ppc/platforms/pmac_time.c
+++ b/arch/ppc/platforms/pmac_time.c
@@ -166,7 +166,7 @@ via_calibrate_decr(void)
{
struct device_node *vias;
volatile unsigned char *via;
- int count = VIA_TIMER_FREQ_6 / HZ;
+ int count = VIA_TIMER_FREQ_6 / 100;
unsigned int dstart, dend;
vias = find_devices("via-cuda");
@@ -196,7 +196,7 @@ via_calibrate_decr(void)
;
dend = get_dec();
- tb_ticks_per_jiffy = (dstart - dend) / 6;
+ tb_ticks_per_jiffy = (dstart - dend) / (6 * (HZ/100));
tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
@@ -260,7 +260,9 @@ pmac_calibrate_decr(void)
* calibration. That's better since the VIA itself seems
* to be slightly off. --BenH
*/
- if (!machine_is_compatible("MacRISC2"))
+ if (!machine_is_compatible("MacRISC2") &&
+ !machine_is_compatible("MacRISC3") &&
+ !machine_is_compatible("MacRISC4"))
if (via_calibrate_decr())
return;
diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
index a8c2715bf78f..b27a75f1b986 100644
--- a/arch/ppc/syslib/of_device.c
+++ b/arch/ppc/syslib/of_device.c
@@ -97,9 +97,9 @@ static int of_device_probe(struct device *dev)
static int of_device_remove(struct device *dev)
{
struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- if (drv && drv->remove)
+ if (dev->driver && drv->remove)
drv->remove(of_dev);
return 0;
}
@@ -107,10 +107,10 @@ static int of_device_remove(struct device *dev)
static int of_device_suspend(struct device *dev, u32 state)
{
struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
- if (drv && drv->suspend)
+ if (dev->driver && drv->suspend)
error = drv->suspend(of_dev, state);
return error;
}
@@ -118,10 +118,10 @@ static int of_device_suspend(struct device *dev, u32 state)
static int of_device_resume(struct device * dev)
{
struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(of_dev->dev.driver);
+ struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
- if (drv && drv->resume)
+ if (dev->driver && drv->resume)
error = drv->resume(of_dev);
return error;
}
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 10e7a055a94c..ab2603589781 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -937,7 +937,6 @@ _GLOBAL(do_stab_bolted)
mfspr r20,SPRG2
mfspr r21,SPRG1
rfid
-_TRACEBACK(do_stab_bolted)
/*
* r20 points to the PACA, r21 to the exception frame,
@@ -1052,7 +1051,6 @@ SLB_NUM_ENTRIES = 64
mfspr r20,SPRG2
mfspr r21,SPRG1
rfid
-_TRACEBACK(do_slb_bolted)
_GLOBAL(do_stab_SI)
mflr r21 /* Save LR in r21 */
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index 8e4862d08de7..3577036e506b 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -84,8 +84,6 @@ int cpu_idle(void)
lpaca = get_paca();
while (1) {
- irq_stat[smp_processor_id()].idle_timestamp = jiffies;
-
if (lpaca->xLpPaca.xSharedProc) {
if (ItLpQueue_isLpIntPending(lpaca->lpQueuePtr))
process_iSeries_events();
@@ -125,7 +123,6 @@ int cpu_idle(void)
long oldval;
while (1) {
- irq_stat[smp_processor_id()].idle_timestamp = jiffies;
oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
if (!oldval) {
diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
index 869c27539f81..1d43005fbb19 100644
--- a/arch/ppc64/kernel/irq.c
+++ b/arch/ppc64/kernel/irq.c
@@ -55,9 +55,6 @@
#include <asm/machdep.h>
#include <asm/paca.h>
-void enable_irq(unsigned int irq_nr);
-void disable_irq(unsigned int irq_nr);
-
#ifdef CONFIG_SMP
extern void iSeries_smp_message_recv( struct pt_regs * );
#endif
@@ -123,7 +120,7 @@ setup_irq(unsigned int irq, struct irqaction * new)
if (!shared) {
desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+ desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
unmask_irq(irq);
}
spin_unlock_irqrestore(&desc->lock,flags);
@@ -140,6 +137,8 @@ inline void synchronize_irq(unsigned int irq)
cpu_relax();
}
+EXPORT_SYMBOL(synchronize_irq);
+
#endif /* CONFIG_SMP */
/* XXX Make this into free_irq() - Anton */
@@ -244,7 +243,7 @@ EXPORT_SYMBOL(free_irq);
* This function may be called from IRQ context.
*/
- void disable_irq_nosync(unsigned int irq)
+inline void disable_irq_nosync(unsigned int irq)
{
irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
@@ -258,6 +257,8 @@ EXPORT_SYMBOL(free_irq);
spin_unlock_irqrestore(&desc->lock, flags);
}
+EXPORT_SYMBOL(disable_irq_nosync);
+
/**
* disable_irq - disable an irq and wait for completion
* @irq: Interrupt to disable
@@ -273,10 +274,14 @@ EXPORT_SYMBOL(free_irq);
void disable_irq(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
disable_irq_nosync(irq);
- synchronize_irq(irq);
+ if (desc->action)
+ synchronize_irq(irq);
}
+EXPORT_SYMBOL(disable_irq);
+
/**
* enable_irq - enable interrupt handling on an irq
* @irq: Interrupt to enable
@@ -295,7 +300,7 @@ void enable_irq(unsigned int irq)
spin_lock_irqsave(&desc->lock, flags);
switch (desc->depth) {
case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
+ unsigned int status = desc->status & ~(IRQ_DISABLED | IRQ_INPROGRESS);
desc->status = status;
if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
desc->status = status | IRQ_REPLAY;
@@ -308,11 +313,14 @@ void enable_irq(unsigned int irq)
desc->depth--;
break;
case 0:
- printk("enable_irq(%u) unbalanced\n", irq);
+ printk("enable_irq(%u) unbalanced from %p\n", irq,
+ __builtin_return_address(0));
}
spin_unlock_irqrestore(&desc->lock, flags);
}
+EXPORT_SYMBOL(enable_irq);
+
int show_interrupts(struct seq_file *p, void *v)
{
int i, j;
@@ -668,7 +676,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off,
static unsigned int parse_hex_value (const char *buffer,
unsigned long count, cpumask_t *ret)
{
- unsigned char hexnum [HEX_DIGITS];
+ unsigned char hexnum[HEX_DIGITS];
cpumask_t value = CPU_MASK_NONE;
int i;
@@ -680,7 +688,7 @@ static unsigned int parse_hex_value (const char *buffer,
return -EFAULT;
/*
- * Parse the first 16 characters as a hex string, any non-hex char
+ * Parse the first HEX_DIGITS characters as a hex string, any non-hex char
* is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
*/
@@ -699,7 +707,6 @@ static unsigned int parse_hex_value (const char *buffer,
for (k = 0; k < 4; ++k)
if (test_bit(k, (unsigned long *)&c))
cpu_set(k, value);
-
}
out:
*ret = value;
@@ -716,6 +723,8 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
return -EIO;
err = parse_hex_value(buffer, count, &new_value);
+ if (err)
+ return err;
/*
* Do not allow disabling IRQs completely - it's a too easy
@@ -741,7 +750,7 @@ static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
return sprintf (page, "%08lx\n", *mask);
}
-static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
cpumask_t *mask = (cpumask_t *)data;
@@ -789,10 +798,12 @@ static void register_irq_proc (unsigned int irq)
/* create /proc/irq/1234/smp_affinity */
entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
- entry->nlink = 1;
- entry->data = (void *)(long)irq;
- entry->read_proc = irq_affinity_read_proc;
- entry->write_proc = irq_affinity_write_proc;
+ if (entry) {
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+ }
smp_affinity_entry[irq] = entry;
}
@@ -810,6 +821,9 @@ void init_irq_proc (void)
/* create /proc/irq/prof_cpu_mask */
entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+ if (!entry)
+ return;
+
entry->nlink = 1;
entry->data = (void *)&prof_cpu_mask;
entry->read_proc = prof_cpu_mask_read_proc;
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index 61746717aaec..a39ff1d9cca7 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -359,7 +359,7 @@ _GLOBAL(_outsl)
bdnz 00b
blr
-_GLOBAL(ide_insw)
+/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
_GLOBAL(_insw_ns)
cmpwi 0,r5,0
mtctr r5
@@ -371,7 +371,7 @@ _GLOBAL(_insw_ns)
bdnz 00b
blr
-_GLOBAL(ide_outsw)
+/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
_GLOBAL(_outsw_ns)
cmpwi 0,r5,0
mtctr r5
@@ -742,7 +742,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_getdents
.llong .ppc32_select
.llong .sys_flock
- .llong .sys32_msync
+ .llong .sys_msync
.llong .sys32_readv /* 145 */
.llong .sys32_writev
.llong .sys32_getsid
@@ -750,7 +750,7 @@ _GLOBAL(sys_call_table32)
.llong .sys32_sysctl
.llong .sys_mlock /* 150 */
.llong .sys_munlock
- .llong .sys32_mlockall
+ .llong .sys_mlockall
.llong .sys_munlockall
.llong .sys32_sched_setparam
.llong .sys32_sched_getparam /* 155 */
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
index 85b8a1621d34..1cc6e4d910e5 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -64,7 +64,7 @@ struct systemcfg *systemcfg;
(&paca[number].exception_stack[0]) - EXC_FRAME_SIZE, \
}
-struct paca_struct paca[NR_CPUS] __page_aligned = {
+struct paca_struct paca[] __page_aligned = {
#ifdef CONFIG_PPC_ISERIES
PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
#else
diff --git a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
index 92ea66bf5554..a25ade4f1473 100644
--- a/arch/ppc64/kernel/pci_dma.c
+++ b/arch/ppc64/kernel/pci_dma.c
@@ -98,7 +98,7 @@ void free_tce_range_nolock(struct TceTable *,
unsigned order );
/* allocates a range of tces and sets them to the pages */
-static inline dma_addr_t get_tces( struct TceTable *,
+inline dma_addr_t get_tces( struct TceTable *,
unsigned order,
void *page,
unsigned numPages,
@@ -210,7 +210,7 @@ static void tce_build_pSeries(struct TceTable *tbl, long tcenum,
* Build a TceTable structure. This contains a multi-level bit map which
* is used to manage allocation of the tce space.
*/
-static struct TceTable *build_tce_table( struct TceTable * tbl )
+struct TceTable *build_tce_table( struct TceTable * tbl )
{
unsigned long bits, bytes, totalBytes;
unsigned long numBits[NUM_TCE_LEVELS], numBytes[NUM_TCE_LEVELS];
@@ -518,7 +518,7 @@ static long test_tce_range( struct TceTable *tbl, long tcenum, unsigned order )
return retval;
}
-static inline dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int direction )
+inline dma_addr_t get_tces( struct TceTable *tbl, unsigned order, void *page, unsigned numPages, int direction )
{
long tcenum;
unsigned long uaddr;
@@ -581,7 +581,7 @@ static void tce_free_one_pSeries( struct TceTable *tbl, long tcenum )
}
#endif
-static void tce_free(struct TceTable *tbl, dma_addr_t dma_addr,
+void tce_free(struct TceTable *tbl, dma_addr_t dma_addr,
unsigned order, unsigned num_pages)
{
long tcenum, total_tces, free_tce;
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
index 38beeba3da4c..98893369e7f4 100644
--- a/arch/ppc64/kernel/ppc_ksyms.c
+++ b/arch/ppc64/kernel/ppc_ksyms.c
@@ -57,12 +57,6 @@ extern struct pci_dev * iSeries_vio_dev;
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(sys_ioctl);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(disable_irq_nosync);
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(synchronize_irq);
-#endif /* CONFIG_SMP */
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(pci_io_base);
@@ -227,3 +221,4 @@ EXPORT_SYMBOL(debugger_fault_handler);
#endif
EXPORT_SYMBOL(tb_ticks_per_usec);
+EXPORT_SYMBOL(paca);
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index dfd22649314e..167ff5158160 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -2340,32 +2340,6 @@ asmlinkage long sys32_mkdir(const char * pathname, u32 mode)
return sys_mkdir(pathname, (int)mode);
}
-
-extern asmlinkage long sys_mlockall(int flags);
-
-/* Note: it is necessary to treat flags as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_mlockall(u32 flags)
-{
- return sys_mlockall((int)flags);
-}
-
-
-extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
-
-/* Note: it is necessary to treat flags as an unsigned int,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_msync(unsigned long start, size_t len, u32 flags)
-{
- return sys_msync(start, len, (int)flags);
-}
-
extern asmlinkage long sys_nice(int increment);
long sys32_nice(u32 increment)
diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
index 9ff0d26fc38b..dac306c5343a 100644
--- a/arch/ppc64/mm/hugetlbpage.c
+++ b/arch/ppc64/mm/hugetlbpage.c
@@ -507,14 +507,21 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
page = find_get_page(mapping, idx);
if (!page) {
+ /* charge the fs quota first */
+ if (hugetlb_get_quota(mapping)) {
+ ret = -ENOMEM;
+ goto out;
+ }
page = alloc_hugetlb_page();
if (!page) {
+ hugetlb_put_quota(mapping);
ret = -ENOMEM;
goto out;
}
ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
unlock_page(page);
if (ret) {
+ hugetlb_put_quota(mapping);
free_huge_page(page);
goto out;
}
diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
index e20f1bf2a7b9..e238b2c7dddb 100644
--- a/arch/ppc64/mm/init.c
+++ b/arch/ppc64/mm/init.c
@@ -726,3 +726,22 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long ea,
__hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep,
0x300, local);
}
+
+kmem_cache_t *zero_cache;
+
+static void zero_ctor(void *pte, kmem_cache_t *cache, unsigned long flags)
+{
+ memset(pte, 0, PAGE_SIZE);
+}
+
+void pgtable_cache_init(void)
+{
+ zero_cache = kmem_cache_create("zero",
+ PAGE_SIZE,
+ 0,
+ SLAB_HWCACHE_ALIGN | SLAB_MUST_HWCACHE_ALIGN,
+ zero_ctor,
+ NULL);
+ if (!zero_cache)
+ panic("pgtable_cache_init(): could not create zero_cache!\n");
+}
diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
index a940b34ef7de..397985dae73e 100644
--- a/arch/ppc64/mm/numa.c
+++ b/arch/ppc64/mm/numa.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
+#include <linux/module.h>
#include <asm/lmb.h>
#if 1
@@ -306,6 +307,7 @@ void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES];
int i, nid;
+ struct page *node_mem_map;
for (i = 1; i < MAX_NR_ZONES; i++)
zones_size[i] = 0;
@@ -314,16 +316,24 @@ void __init paging_init(void)
unsigned long start_pfn;
unsigned long end_pfn;
- if (node_data[nid].node_spanned_pages == 0)
- continue;
-
start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
end_pfn = plat_node_bdata[nid].node_low_pfn;
zones_size[ZONE_DMA] = end_pfn - start_pfn;
dbg("free_area_init node %d %lx %lx\n", nid,
zones_size[ZONE_DMA], start_pfn);
- free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size,
- start_pfn, NULL);
+
+ /*
+ * Give this empty node a dummy struct page to avoid
+ * us from trying to allocate a node local mem_map
+ * in free_area_init_node (which will fail).
+ */
+ if (!node_data[nid].node_spanned_pages)
+ node_mem_map = alloc_bootmem(sizeof(struct page));
+ else
+ node_mem_map = NULL;
+
+ free_area_init_node(nid, NODE_DATA(nid), node_mem_map,
+ zones_size, start_pfn, NULL);
}
}
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 85525ddaedd4..11d67ea1fd28 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -570,6 +570,7 @@ CONFIG_BRIDGE_EBT_BROUTE=m
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
CONFIG_BRIDGE_EBT_ARP=m
CONFIG_BRIDGE_EBT_IP=m
CONFIG_BRIDGE_EBT_LIMIT=m
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index cf72f7cfb806..bc301c82e3a6 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -28,7 +28,6 @@ obj-$(CONFIG_ATARI_ACSI) += acsi.o
obj-$(CONFIG_ATARI_SLM) += acsi_slm.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_BLK_DEV_RAM) += rd.o
-obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o
obj-$(CONFIG_BLK_DEV_XD) += xd.o
diff --git a/drivers/block/initrd.c b/drivers/block/initrd.c
deleted file mode 100644
index 41a7725ea474..000000000000
--- a/drivers/block/initrd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-#include <linux/initrd.h>
-#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-
-
-unsigned long initrd_start, initrd_end;
-int initrd_below_start_ok;
-
-static int initrd_users;
-static spinlock_t initrd_users_lock = SPIN_LOCK_UNLOCKED;
-
-static struct gendisk *initrd_disk;
-
-static ssize_t initrd_read(struct file *file, char *buf,
- size_t count, loff_t *ppos)
-{
- int left = initrd_end - initrd_start - *ppos;
-
- if (count > left)
- count = left;
- if (count == 0)
- return 0;
- if (copy_to_user(buf, (char *)initrd_start + *ppos, count))
- return -EFAULT;
-
- *ppos += count;
- return count;
-}
-
-static int initrd_release(struct inode *inode,struct file *file)
-{
-
- blkdev_put(inode->i_bdev, BDEV_FILE);
-
- spin_lock(&initrd_users_lock);
- if (!--initrd_users) {
- spin_unlock(&initrd_users_lock);
- del_gendisk(initrd_disk);
- free_initrd_mem(initrd_start, initrd_end);
- initrd_start = 0;
- } else
- spin_unlock(&initrd_users_lock);
-
- return 0;
-}
-
-static struct file_operations initrd_fops = {
- .read = initrd_read,
- .release = initrd_release,
-};
-
-static int initrd_open(struct inode *inode, struct file *filp)
-{
- if (!initrd_start)
- return -ENODEV;
-
- spin_lock(&initrd_users_lock);
- initrd_users++;
- spin_unlock(&initrd_users_lock);
-
- filp->f_op = &initrd_fops;
- return 0;
-}
-
-static struct block_device_operations initrd_bdops = {
- .owner = THIS_MODULE,
- .open = initrd_open,
-};
-
-static int __init initrd_init(void)
-{
- initrd_disk = alloc_disk(1);
- if (!initrd_disk)
- return -ENOMEM;
-
- initrd_disk->major = RAMDISK_MAJOR;
- initrd_disk->first_minor = INITRD_MINOR;
- initrd_disk->fops = &initrd_bdops;
-
- sprintf(initrd_disk->disk_name, "initrd");
- sprintf(initrd_disk->devfs_name, "rd/initrd");
-
- set_capacity(initrd_disk, (initrd_end-initrd_start+511) >> 9);
- add_disk(initrd_disk);
- return 0;
-}
-
-static void __exit initrd_exit(void)
-{
- put_disk(initrd_disk);
-}
-
-module_init(initrd_init);
-module_exit(initrd_exit);
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 1c8362764e1a..77456e187718 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -842,8 +842,9 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp,
CDROM_AUDIO_NO_STATUS;
}
- copy_from_user(&sjcd_msf, (void *) arg,
- sizeof(sjcd_msf));
+ if (copy_from_user(&sjcd_msf, (void *) arg,
+ sizeof(sjcd_msf)))
+ return (-EFAULT);
sjcd_playing.start.min =
bin2bcd(sjcd_msf.cdmsf_min0);
@@ -893,9 +894,9 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp,
sizeof(toc_entry))) == 0) {
struct sjcd_hw_disk_info *tp;
- copy_from_user(&toc_entry, (void *) arg,
- sizeof(toc_entry));
-
+ if (copy_from_user(&toc_entry, (void *) arg,
+ sizeof(toc_entry)))
+ return (-EFAULT);
if (toc_entry.cdte_track == CDROM_LEADOUT)
tp = &sjcd_table_of_contents[0];
else if (toc_entry.cdte_track <
@@ -948,8 +949,10 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp,
sizeof(subchnl))) == 0) {
struct sjcd_hw_qinfo q_info;
- copy_from_user(&subchnl, (void *) arg,
- sizeof(subchnl));
+ if (copy_from_user(&subchnl, (void *) arg,
+ sizeof(subchnl)))
+ return (-EFAULT);
+
if (sjcd_get_q_info(&q_info) < 0)
return (-EIO);
@@ -1005,8 +1008,9 @@ static int sjcd_ioctl(struct inode *ip, struct file *fp,
sizeof(vol_ctrl))) == 0) {
unsigned char dummy[4];
- copy_from_user(&vol_ctrl, (void *) arg,
- sizeof(vol_ctrl));
+ if (copy_from_user(&vol_ctrl, (void *) arg,
+ sizeof(vol_ctrl)))
+ return (-EFAULT);
sjcd_send_4_cmd(SCMD_SET_VOLUME,
vol_ctrl.channel0, 0xFF,
vol_ctrl.channel1, 0xFF);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 5f9a0b9447c2..e907eea9d2b2 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -231,7 +231,7 @@ struct agp_bridge_driver ali_m1541_bridge = {
};
-static struct agp_device_ids ali_agp_device_ids[] __initdata =
+static struct agp_device_ids ali_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_AL_M1541,
@@ -272,7 +272,7 @@ static struct agp_device_ids ali_agp_device_ids[] __initdata =
{ }, /* dummy final entry, always present */
};
-static int __init agp_ali_probe(struct pci_dev *pdev,
+static int __devinit agp_ali_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct agp_device_ids *devs = ali_agp_device_ids;
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 28442f7dad51..ee40f2c1844a 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -365,7 +365,7 @@ struct agp_bridge_driver amd_irongate_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-static struct agp_device_ids amd_agp_device_ids[] __initdata =
+static struct agp_device_ids amd_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006,
@@ -382,8 +382,8 @@ static struct agp_device_ids amd_agp_device_ids[] __initdata =
{ }, /* dummy final entry, always present */
};
-static int __init agp_amdk7_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_device_ids *devs = amd_agp_device_ids;
struct agp_bridge_data *bridge;
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 1d4fca34e32f..fda92bd3c865 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -248,7 +248,7 @@ struct agp_bridge_driver amd_8151_driver = {
};
/* Some basic sanity checks for the aperture. */
-static int __init aperture_valid(u64 aper, u32 size)
+static int __devinit aperture_valid(u64 aper, u32 size)
{
static int not_first_call;
u32 pfn, c;
@@ -297,7 +297,7 @@ static int __init aperture_valid(u64 aper, u32 size)
* to allocate that much memory. But at least error out cleanly instead of
* crashing.
*/
-static __init int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
+static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
u16 cap)
{
u32 aper_low, aper_hi;
@@ -339,7 +339,7 @@ static __init int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
return 0;
}
-static __init int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
+static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
{
struct pci_dev *loop_dev = NULL;
int i = 0;
@@ -365,8 +365,8 @@ static __init int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
return i == 0 ? -1 : 0;
}
-static int __init agp_amd64_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_amd64_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_bridge_data *bridge;
u8 rev_id;
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index ecb2b0349d3e..92685b4a31cf 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -403,7 +403,7 @@ struct agp_bridge_driver ati_generic_bridge = {
};
-static struct agp_device_ids ati_agp_device_ids[] __initdata =
+static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_ATI_RS100,
@@ -436,8 +436,8 @@ static struct agp_device_ids ati_agp_device_ids[] __initdata =
{ }, /* dummy final entry, always present */
};
-static int __init agp_ati_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_ati_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_device_ids *devs = ati_agp_device_ids;
struct agp_bridge_data *bridge;
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 2f70f417f221..1751111edd31 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -560,8 +560,8 @@ struct agp_bridge_driver intel_i460_driver = {
.cant_use_aperture = 1,
};
-static int __init agp_intel_i460_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_intel_i460_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_bridge_data *bridge;
u8 cap_ptr;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index e65679a20e24..ba8ff10153bc 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -1232,8 +1232,8 @@ static int find_i830(u16 device)
return 1;
}
-static int __init agp_intel_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_intel_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_bridge_data *bridge;
char *name = "(unknown)";
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 48b5f21f4447..c934e62b3cd5 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -250,8 +250,8 @@ struct agp_bridge_driver nvidia_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-static int __init agp_nvidia_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_bridge_data *bridge;
u8 cap_ptr;
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 0d7e66316624..e370f9ac5344 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -95,7 +95,7 @@ struct agp_bridge_driver sis_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-static struct agp_device_ids sis_agp_device_ids[] __initdata =
+static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_SI_530,
@@ -164,8 +164,8 @@ static struct agp_device_ids sis_agp_device_ids[] __initdata =
{ }, /* dummy final entry, always present */
};
-static int __init agp_sis_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_sis_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_device_ids *devs = sis_agp_device_ids;
struct agp_bridge_data *bridge;
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 38de057e9e37..249c4e07d901 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -437,8 +437,8 @@ struct agp_bridge_driver sworks_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-static int __init agp_serverworks_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_bridge_data *bridge;
struct pci_dev *bridge_dev;
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 1fa77885c111..14dfb59ffa66 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -282,7 +282,7 @@ struct agp_bridge_driver uninorth_agp_driver = {
.cant_use_aperture = 1,
};
-static struct agp_device_ids uninorth_agp_device_ids[] __initdata = {
+static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
{
.device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
.chipset_name = "UniNorth",
@@ -301,8 +301,8 @@ static struct agp_device_ids uninorth_agp_device_ids[] __initdata = {
},
};
-static int __init agp_uninorth_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_device_ids *devs = uninorth_agp_device_ids;
struct agp_bridge_data *bridge;
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index e4cee0a8a578..24b80c78a426 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -211,7 +211,7 @@ struct agp_bridge_driver via_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-static struct agp_device_ids via_agp_device_ids[] __initdata =
+static struct agp_device_ids via_agp_device_ids[] __devinitdata =
{
{
.device_id = PCI_DEVICE_ID_VIA_82C597_0,
@@ -371,8 +371,8 @@ static void check_via_agp3 (struct agp_bridge_data *bridge)
}
-static int __init agp_via_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit agp_via_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct agp_device_ids *devs = via_agp_device_ids;
struct agp_bridge_data *bridge;
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 23e81fbe829d..3a084522e8fa 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -214,6 +214,7 @@ int __init applicom_init(void)
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", dev->resource[0].start);
+ pci_disable_device(dev);
return -EIO;
}
@@ -225,12 +226,14 @@ int __init applicom_init(void)
(unsigned long)RamIO,0))) {
printk(KERN_INFO "ac.o: PCI Applicom device doesn't have correct signature.\n");
iounmap(RamIO);
+ pci_disable_device(dev);
continue;
}
if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) {
printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
iounmap(RamIO);
+ pci_disable_device(dev);
apbs[boardno - 1].RamIO = 0;
continue;
}
@@ -257,12 +260,6 @@ int __init applicom_init(void)
/* Now try the specified ISA cards */
-#warning "LEAK"
- RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
-
- if (!RamIO)
- printk(KERN_INFO "ac.o: Failed to ioremap ISA memory space at 0x%lx\n", mem);
-
for (i = 0; i < MAX_ISA_BOARD; i++) {
RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
@@ -285,7 +282,8 @@ int __init applicom_init(void)
iounmap((void *) RamIO);
apbs[boardno - 1].RamIO = 0;
}
- apbs[boardno - 1].irq = irq;
+ else
+ apbs[boardno - 1].irq = irq;
}
else
apbs[boardno - 1].irq = 0;
diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
index f3a6c78bd322..1a4dfef7e46d 100644
--- a/drivers/char/ite_gpio.c
+++ b/drivers/char/ite_gpio.c
@@ -242,21 +242,12 @@ static int ite_gpio_open(struct inode *inode, struct file *file)
if (minor != GPIO_MINOR)
return -ENODEV;
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-
return 0;
}
static int ite_gpio_release(struct inode *inode, struct file *file)
{
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-
return 0;
}
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index aeaa4d9f2b4d..585196d778f9 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -8020,8 +8020,8 @@ int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
-static int __init synclink_init_one (struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit synclink_init_one (struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
struct mgsl_struct *info;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index ec4d3393f9e7..82c7afe29f92 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -5451,8 +5451,8 @@ void write_control_reg(SLMP_INFO * info)
}
-static int __init synclinkmp_init_one (struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit synclinkmp_init_one (struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
if (pci_enable_device(dev)) {
printk("error enabling pci device %p\n", dev);
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
index d8f601a31672..a1cafa3a66bb 100644
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -779,10 +779,6 @@ int i2c_iic_add_bus(struct i2c_adapter *adap)
adap->retries = 3; /* be replaced by defines */
adap->flags = 0;
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-
i2c_add_adapter(adap);
iic_init(iic_adap);
@@ -815,9 +811,6 @@ int i2c_iic_del_bus(struct i2c_adapter *adap)
return res;
DEB2(printk("i2c-algo-ite: adapter unregistered: %s\n",adap->name));
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
index 40f183f4f217..8be736ccfe2d 100644
--- a/drivers/i2c/chips/w83781d.c
+++ b/drivers/i2c/chips/w83781d.c
@@ -422,9 +422,11 @@ sysfs_in_offsets(7);
sysfs_in_offsets(8);
#define device_create_file_in(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_in_input##offset); \
device_create_file(&client->dev, &dev_attr_in_min##offset); \
-device_create_file(&client->dev, &dev_attr_in_max##offset);
+device_create_file(&client->dev, &dev_attr_in_max##offset); \
+} while (0)
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
@@ -482,8 +484,10 @@ sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
#define device_create_file_fan(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_fan_input##offset); \
device_create_file(&client->dev, &dev_attr_fan_min##offset); \
+} while (0)
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
@@ -566,9 +570,11 @@ sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
#define device_create_file_temp(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_temp_input##offset); \
device_create_file(&client->dev, &dev_attr_temp_max##offset); \
-device_create_file(&client->dev, &dev_attr_temp_min##offset);
+device_create_file(&client->dev, &dev_attr_temp_min##offset); \
+} while (0)
static ssize_t
show_vid_reg(struct device *dev, char *buf)
@@ -691,8 +697,10 @@ sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
#define device_create_file_beep(client) \
+do { \
device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask);
+device_create_file(&client->dev, &dev_attr_beep_mask); \
+} while (0)
/* w83697hf only has two fans */
static ssize_t
@@ -769,7 +777,9 @@ sysfs_fan_div(2);
sysfs_fan_div(3);
#define device_create_file_fan_div(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_fan_div##offset); \
+} while (0)
/* w83697hf only has two fans */
static ssize_t
@@ -881,10 +891,14 @@ sysfs_pwm(3);
sysfs_pwm(4);
#define device_create_file_pwm(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_pwm##offset); \
+} while (0)
#define device_create_file_pwmenable(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_pwm_enable##offset); \
+} while (0)
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
@@ -957,7 +971,9 @@ sysfs_sensor(2);
sysfs_sensor(3);
#define device_create_file_sensor(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_sensor##offset); \
+} while (0)
#ifdef W83781D_RT
static ssize_t
@@ -1016,7 +1032,9 @@ sysfs_rt(2);
sysfs_rt(3);
#define device_create_file_rt(client, offset) \
+do { \
device_create_file(&client->dev, &dev_attr_rt##offset); \
+} while (0)
#endif /* ifdef W83781D_RT */
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index b664be3904b6..55cef4b31d1c 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -1796,7 +1796,7 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
* we'll leave the limitation below for the 2.2.x tree.
*/
- if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) {
+ if (strstr(drive->id->model, "IOMEGA ZIP") != NULL) {
set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
/* This value will be visible in the /proc/ide/hdx/settings */
floppy->ticks = IDEFLOPPY_TICKS_DELAY;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 9b67e7897fc4..2b8fe041babe 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -355,13 +355,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
aec62xx_tune_drive(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
static int aec62xx_irq_timeout (ide_drive_t *drive)
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 4559feb89ebc..99a80803712b 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -484,13 +484,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive, 1);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
static int cmd64x_alt_dma_status (struct pci_dev *dev)
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index b43ed1a60630..f4da1f9a2bfd 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -215,17 +215,19 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+#ifndef CONFIG_HPT34X_AUTODMA
+ return hwif->ide_dma_off_quietly(drive);
+#else
+ return hwif->ide_dma_on(drive);
+#endif
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hpt34x_tune_drive(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
-
-#ifndef CONFIG_HPT34X_AUTODMA
- return hwif->ide_dma_off_quietly(drive);
-#endif /* CONFIG_HPT34X_AUTODMA */
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/*
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 6d36d39192dc..4924eebca1e7 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -538,13 +538,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hpt3xx_tune_drive(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/*
diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
index 6b86cd033822..525abe5f201d 100644
--- a/drivers/ide/pci/it8172.c
+++ b/drivers/ide/pci/it8172.c
@@ -227,13 +227,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
it8172_tune_drive(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 7c60301aa938..998c3f992971 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -414,13 +414,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hwif->tuneproc(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
static int pdcnew_quirkproc (ide_drive_t *drive)
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 3ab58903e6a0..51c59cec96b0 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -518,13 +518,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hwif->tuneproc(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
static int pdc202xx_quirkproc (ide_drive_t *drive)
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 3ed1a33ab88a..e8679d9cab46 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -588,13 +588,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hwif->tuneproc(drive, 255);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/**
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 513a0c5651d0..66b8d9b4f5fb 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -484,6 +484,7 @@ try_dma_modes:
} else {
goto no_dma_set;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
@@ -491,7 +492,8 @@ no_dma_set:
// hwif->tuneproc(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/* This can go soon */
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 7f59c39beea0..9f56898c23f1 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -515,13 +515,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive, 1);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/* returns 1 if dma irq issued, 0 otherwise */
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 654bad2ce4ee..3068287aefb6 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -696,13 +696,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
sis5513_tune_drive(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
/* initiates/aborts (U)DMA read/write operations on a drive. */
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index ae96a90fcc6f..1f01228f5bb5 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -301,13 +301,15 @@ try_dma_modes:
} else {
goto fast_ata_pio;
}
+ return hwif->ide_dma_on(drive);
} else if ((id->capability & 8) || (id->field_valid & 2)) {
fast_ata_pio:
no_dma_set:
hwif->tuneproc(drive, 5);
return hwif->ide_dma_off_quietly(drive);
}
- return hwif->ide_dma_on(drive);
+ /* IORDY not supported */
+ return 0;
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 31418d49301a..cb40533fa587 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -1,4 +1,4 @@
-/* $Id: divasmain.c,v 1.43 2003/09/22 08:57:31 schindler Exp $
+/* $Id: divasmain.c,v 1.46 2003/10/10 12:28:14 armin Exp $
*
* Low level driver for Eicon DIVA Server ISDN cards.
*
@@ -41,7 +41,7 @@
#include "diva_dma.h"
#include "diva_pci.h"
-static char *main_revision = "$Revision: 1.43 $";
+static char *main_revision = "$Revision: 1.46 $";
static int major;
@@ -69,7 +69,7 @@ extern int divasfunc_init(int dbgmask);
extern void divasfunc_exit(void);
typedef struct _diva_os_thread_dpc {
- struct tasklet_struct divas_task;
+ struct work_struct divas_task;
struct work_struct trap_script_task;
diva_os_soft_isr_t *psoft_isr;
int card_failed;
@@ -552,7 +552,7 @@ void diva_os_remove_irq(void *context, byte irq)
/* --------------------------------------------------------------------------
DPC framework implementation
-------------------------------------------------------------------------- */
-static void diva_os_dpc_proc(unsigned long context)
+static void diva_os_dpc_proc(void *context)
{
diva_os_thread_dpc_t *psoft_isr = (diva_os_thread_dpc_t *) context;
diva_os_soft_isr_t *pisr = psoft_isr->psoft_isr;
@@ -575,8 +575,7 @@ int diva_os_initialize_soft_isr(diva_os_soft_isr_t * psoft_isr,
psoft_isr->callback_context = callback_context;
pdpc->psoft_isr = psoft_isr;
INIT_WORK(&pdpc->trap_script_task, diva_adapter_trapped, pdpc);
- tasklet_init(&pdpc->divas_task, diva_os_dpc_proc,
- (unsigned long) pdpc);
+ INIT_WORK(&pdpc->divas_task, diva_os_dpc_proc, pdpc);
return (0);
}
@@ -587,7 +586,7 @@ int diva_os_schedule_soft_isr(diva_os_soft_isr_t * psoft_isr)
diva_os_thread_dpc_t *pdpc =
(diva_os_thread_dpc_t *) psoft_isr->object;
- tasklet_schedule(&pdpc->divas_task);
+ schedule_work(&pdpc->divas_task);
}
return (1);
@@ -595,26 +594,18 @@ int diva_os_schedule_soft_isr(diva_os_soft_isr_t * psoft_isr)
int diva_os_cancel_soft_isr(diva_os_soft_isr_t * psoft_isr)
{
- if (psoft_isr && psoft_isr->object) {
- diva_os_thread_dpc_t *pdpc =
- (diva_os_thread_dpc_t *) psoft_isr->object;
- tasklet_kill(&pdpc->divas_task);
- }
+ flush_scheduled_work();
return (0);
}
void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr)
{
if (psoft_isr && psoft_isr->object) {
- diva_os_thread_dpc_t *pdpc =
- (diva_os_thread_dpc_t *) psoft_isr->object;
void *mem;
- tasklet_kill(&pdpc->divas_task);
-
+ flush_scheduled_work();
mem = psoft_isr->object;
psoft_isr->object = 0;
- flush_scheduled_work();
diva_os_free(0, mem);
}
}
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 9fe903a5b249..409bf8140099 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -611,8 +611,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
/* HACK WARNING!! This should go away as soon there is an utility
* to control that for event devices.
*/
- adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */
- adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */
+ adbhid[id]->input.rep[REP_DELAY] = 500; /* input layer default: 250 */
+ adbhid[id]->input.rep[REP_PERIOD] = 66; /* input layer default: 33 */
}
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 73725594bb5b..013cd4de02e5 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -456,7 +456,7 @@ static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
}
-static int dvb_net_init_dev (struct net_device *dev)
+static void dvb_net_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -472,11 +472,8 @@ static int dvb_net_init_dev (struct net_device *dev)
dev->hard_header_cache = NULL;
dev->flags |= IFF_NOARP;
-
- return 0;
}
-
static int get_if(struct dvb_net *dvbnet)
{
int i;
@@ -496,7 +493,6 @@ static int get_if(struct dvb_net *dvbnet)
static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
{
struct net_device *net;
- struct dmx_demux *demux;
struct dvb_net_priv *priv;
int result;
int if_num;
@@ -504,25 +500,20 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
if ((if_num = get_if(dvbnet)) < 0)
return -EINVAL;
- net = &dvbnet->device[if_num];
- demux = dvbnet->demux;
+ net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb",
+ dvb_net_setup);
+ if (!net)
+ return -ENOMEM;
- memset(net, 0, sizeof(struct net_device));
+ sprintf(net->name, "dvb%d_%d", dvbnet->dvbdev->adapter->num, if_num);
- memcpy(net->name, "dvb0_0", 7);
- net->name[3] = dvbnet->dvbdev->adapter->num + '0';
- net->name[5] = if_num + '0';
net->addr_len = 6;
memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
- net->next = NULL;
- net->init = dvb_net_init_dev;
- if (!(net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL)))
- return -ENOMEM;
+ dvbnet->device[if_num] = net;
priv = net->priv;
- memset(priv, 0, sizeof(struct dvb_net_priv));
- priv->demux = demux;
+ priv->demux = dvbnet->demux;
priv->pid = pid;
priv->rx_mode = RX_MODE_UNI;
@@ -532,6 +523,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
net->base_addr = pid;
if ((result = register_netdev(net)) < 0) {
+ kfree(net);
return result;
}
@@ -541,18 +533,20 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
static int dvb_net_remove_if(struct dvb_net *dvbnet, int num)
{
- struct dvb_net_priv *priv = dvbnet->device[num].priv;
+ struct net_device *net = dvbnet->device[num];
+ struct dvb_net_priv *priv = net->priv;
if (!dvbnet->state[num])
return -EINVAL;
if (priv->in_use)
return -EBUSY;
- dvb_net_stop(&dvbnet->device[num]);
+ dvb_net_stop(net);
flush_scheduled_work();
- kfree(priv);
- unregister_netdev(&dvbnet->device[num]);
+ unregister_netdev(net);
dvbnet->state[num]=0;
+ free_netdev(net);
+
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
index 93648d4d0de6..5b701efe8e4d 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.h
+++ b/drivers/media/dvb/dvb-core/dvb_net.h
@@ -34,7 +34,7 @@
struct dvb_net {
struct dvb_device *dvbdev;
- struct net_device device[DVB_NET_DEVICES_MAX];
+ struct net_device *device[DVB_NET_DEVICES_MAX];
int state[DVB_NET_DEVICES_MAX];
struct dmx_demux *demux;
};
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index d9b1352e6c24..63211afd820b 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2706,9 +2706,9 @@ static int tuner_set_tv_freq (struct saa7146_dev *dev, u32 freq)
buf[1] = div & 0xff;
buf[2] = 0x8e;
- if (freq < 16*168.25 )
+ if (freq < (u32) (16*168.25) )
config = 0xa0;
- else if (freq < 16*447.25)
+ else if (freq < (u32) (16*447.25))
config = 0x90;
else
config = 0x30;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 0fef080576c9..f1b1ae6b3c3c 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -95,7 +95,7 @@ struct list_head saa7134_devlist;
unsigned int saa7134_devcount;
#define dprintk(fmt, arg...) if (core_debug) \
- printk(KERN_DEBUG "%s/core: " fmt, dev->name, ## arg)
+ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
/* debug help functions */
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 6f2676d839bd..c805d4f727b3 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -248,6 +248,8 @@ static struct pci_device_id rtl8139_pci_tbl[] = {
{0x14ea, 0xab06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x14ea, 0xab07, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
+ {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
#ifdef CONFIG_SH_SECUREEDGE5410
/* Bogus 8139 silicon reports 8129 without external PROM :-( */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6c6ce2a743f0..0a10a0556771 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1616,7 +1616,7 @@ config SUNDANCE_MMIO
config TLAN
tristate "TI ThunderLAN support"
- depends on NET_PCI && (PCI || EISA)
+ depends on NET_PCI && (PCI || EISA) && !64BIT
---help---
If you have a PCI Ethernet network card based on the ThunderLAN chip
which is supported by this driver, say Y and read the
@@ -2412,7 +2412,7 @@ config IPHASE5526
config RCPCI
tristate "Red Creek Hardware VPN (EXPERIMENTAL)"
- depends on NETDEVICES && EXPERIMENTAL && PCI
+ depends on NETDEVICES && EXPERIMENTAL && PCI && !64BIT
help
This is a driver for hardware which provides a Virtual Private
Network (VPN). Say Y if you have it.
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 66c55fbf8c79..d07149409b99 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -433,17 +433,15 @@ void __init probe_old_netdevs(void)
#ifdef CONFIG_SBNI
for (num = 0; num < 8; ++num)
- if (sbni_probe(num))
- break;
+ sbni_probe(num);
#endif
#ifdef CONFIG_TR
for (num = 0; num < 8; ++num)
- if (trif_probe(num))
- break;
+ trif_probe(num);
#endif
for (num = 0; num < 8; ++num)
- if (ethif_probe(num))
- break;
+ ethif_probe(num);
+
#ifdef CONFIG_COPS
cops_probe(0);
cops_probe(1);
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index bc9e1bfc7220..33314f110535 100755
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1698,7 +1698,7 @@ static int amd8111e_resume(struct pci_dev *pci_dev)
/* Restart ipg timer */
if(lp->options & OPTION_DYN_IPG_ENABLE)
mod_timer(&lp->ipg_data.ipg_timer,
- jiffies + (IPG_CONVERGE_TIME * HZ));
+ jiffies + IPG_CONVERGE_JIFFIES);
spin_unlock_irq(&lp->lock);
return 0;
@@ -1772,7 +1772,7 @@ static void amd8111e_config_ipg(struct net_device* dev)
writew((u32)tmp_ipg, mmio + IPG);
writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1);
}
- mod_timer(&lp->ipg_data.ipg_timer, jiffies + (IPG_CONVERGE_TIME * HZ));
+ mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES);
return;
}
@@ -1909,7 +1909,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
lp->ipg_data.ipg_timer.data = (unsigned long) dev;
lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg;
lp->ipg_data.ipg_timer.expires = jiffies +
- IPG_CONVERGE_TIME * HZ;
+ IPG_CONVERGE_JIFFIES;
lp->ipg_data.ipg = DEFAULT_IPG;
lp->ipg_data.ipg_state = CSTATE;
};
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index d751dc8dd53d..836277399b8a 100755
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -606,7 +606,7 @@ typedef enum {
/* ipg parameters */
#define DEFAULT_IPG 0x60
#define IFS1_DELTA 36
-#define IPG_CONVERGE_TIME 0.5
+#define IPG_CONVERGE_JIFFIES (HZ / 2)
#define IPG_STABLE_TIME 5
#define MIN_IPG 96
#define MAX_IPG 255
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index ef10d16fd679..e87bb3ebb7db 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -25,8 +25,8 @@
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.9"
-#define DRV_MODULE_RELDATE "Jul 14, 2003"
+#define DRV_MODULE_VERSION "0.91"
+#define DRV_MODULE_RELDATE "Oct 3, 2003"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -80,15 +80,6 @@ MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */
-#ifndef PCI_DEVICE_ID_BCM4401
-#define PCI_DEVICE_ID_BCM4401 0x4401
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define IRQ_RETVAL(x)
-#define irqreturn_t void
-#endif
-
static struct pci_device_id b44_pci_tbl[] = {
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -870,6 +861,8 @@ static void b44_tx_timeout(struct net_device *dev)
spin_unlock_irq(&bp->lock);
+ b44_enable_ints(bp);
+
netif_wake_queue(dev);
}
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 52948d2cbad6..014df260b075 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -2664,8 +2664,8 @@ static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type)
static void my_skb_align(struct sk_buff *skb, int n)
{
- u32 x=(u32)skb->data; /* We only want the low bits .. */
- u32 v;
+ unsigned long x=(unsigned long)skb->data;
+ unsigned long v;
v=(x+n-1)&~(n-1); /* Where we want to be */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index b11e2efc8306..f39fa66cb684 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -30,7 +30,7 @@
/* Change Log
*
- * 5.2.18 9/13/03
+ * 5.2.20 9/30/03
* o Bug fix: SERDES devices might be connected to a back-plane
* switch that doesn't support auto-neg, so add the capability
* to force 1000/Full.
@@ -39,6 +39,9 @@
* Jumbo Frames or with the reduced FIFO in 82547.
* o Better propagation of error codes. [Janice Girouard
* (janiceg@us.ibm.com)].
+ * o Bug fix: hang under heavy Tx stress when running out of Tx
+ * descriptors; wasn't clearing context descriptor when backing
+ * out of send because of no-resource condition.
*
* 5.2.16 8/8/03
* o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1
@@ -61,7 +64,7 @@
char e1000_driver_name[] = "e1000";
char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.19-k1";
+char e1000_driver_version[] = "5.2.20-k1";
char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
@@ -1545,6 +1548,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
unsigned int first)
{
struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc;
struct e1000_buffer *buffer_info;
unsigned int len = skb->len, max_per_txd = E1000_MAX_DATA_PER_TXD;
unsigned int offset = 0, size, count = 0, i;
@@ -1640,17 +1644,29 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
}
}
- if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+ if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
/* There aren't enough descriptors available to queue up
- * this send, so undo the mapping and abort the send.
- * We could have done the check before we mapped the skb,
- * but because of all the workarounds (above), it's too
- * difficult to predict how many we're going to need.*/
- i = first;
+ * this send (need: count + 1 context desc + 1 desc gap
+ * to keep tail from touching head), so undo the mapping
+ * and abort the send. We could have done the check before
+ * we mapped the skb, but because of all the workarounds
+ * (above), it's too difficult to predict how many we're
+ * going to need.*/
+ i = adapter->tx_ring.next_to_use;
+
+ if(i == first) {
+ /* Cleanup after e1000_tx_[csum|tso] scribbling
+ * on descriptors. */
+ tx_desc = E1000_TX_DESC(*tx_ring, first);
+ tx_desc->buffer_addr = 0;
+ tx_desc->lower.data = 0;
+ tx_desc->upper.data = 0;
+ }
while(count--) {
buffer_info = &tx_ring->buffer_info[i];
+
if(buffer_info->dma) {
pci_unmap_page(adapter->pdev,
buffer_info->dma,
@@ -1658,9 +1674,12 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
PCI_DMA_TODEVICE);
buffer_info->dma = 0;
}
+
if(++i == tx_ring->count) i = 0;
}
+ adapter->tx_ring.next_to_use = first;
+
return 0;
}
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 39cd1e6e487a..93865624e621 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -196,12 +196,8 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
eth = (struct ethhdr *)skb->mac.raw;
if (!(bpq->acpt_addr[0] & 0x01) &&
- memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "bpqether: wrong dest %s\n",
- bpq_print_ethaddr(eth->h_source));
+ memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN))
goto drop_unlock;
- }
if (skb_cow(skb, sizeof(struct ethhdr)))
goto drop_unlock;
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index cee45d0cebbf..0eec5d3e8d8b 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1762,7 +1762,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
#ifndef SCC_DONT_CHECK
- if(request_region(scc->ctrl, 1, "scc-probe"))
+ if(request_region(hwcfg.ctrl_a, 1, "scc-probe"))
{
disable_irq(hwcfg.irq);
Outb(hwcfg.ctrl_a, 0);
@@ -1774,7 +1774,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (InReg(hwcfg.ctrl_a,R13) != 0x55)
found = 0;
enable_irq(hwcfg.irq);
- release_region(scc->ctrl, 1);
+ release_region(hwcfg.ctrl_a, 1);
}
else
found = 0;
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 3e7facd034d0..f92d5c9b5780 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1265,9 +1265,9 @@ static int hp100_init_rxpdl(struct net_device *dev,
{
/* pdlptr is starting address for this pdl */
- if (0 != (((unsigned) pdlptr) & 0xf))
- printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",
- dev->name, (unsigned) pdlptr);
+ if (0 != (((unsigned long) pdlptr) & 0xf))
+ printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%lx.\n",
+ dev->name, (unsigned long) pdlptr);
ringptr->pdl = pdlptr + 1;
ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
@@ -1292,8 +1292,8 @@ static int hp100_init_txpdl(struct net_device *dev,
register hp100_ring_t * ringptr,
register u32 * pdlptr)
{
- if (0 != (((unsigned) pdlptr) & 0xf))
- printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n", dev->name, (unsigned) pdlptr);
+ if (0 != (((unsigned long) pdlptr) & 0xf))
+ printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%lx.\n", dev->name, (unsigned long) pdlptr);
ringptr->pdl = pdlptr; /* +1; */
ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 14fbbef63fb6..47fa6b2b1690 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -1530,7 +1530,7 @@ static void drain_tx(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
if (np->tx_skbuff[i]) {
pci_unmap_single(np->pci_dev,
- np->rx_dma[i], np->rx_skbuff[i]->len,
+ np->tx_dma[i], np->tx_skbuff[i]->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(np->tx_skbuff[i]);
np->stats.tx_dropped++;
diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c
index 968af8bf1929..0a5706e6c41d 100644
--- a/drivers/net/net_init.c
+++ b/drivers/net/net_init.c
@@ -148,11 +148,14 @@ static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv,
if (dev->name[0] == '\0' || dev->name[0] == ' ') {
strcpy(dev->name, mask);
+ rtnl_lock();
if (dev_alloc_name(dev, mask)<0) {
+ rtnl_unlock();
if (new_device)
kfree(dev);
return NULL;
}
+ rtnl_unlock();
}
netdev_boot_setup_check(dev);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index d6bcac3b173e..c52f1c162710 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -681,10 +681,6 @@ static void pcnet_config(dev_link_t *link)
} else {
dev->if_port = 0;
}
- if (register_netdev(dev) != 0) {
- printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
- goto failed;
- }
hw_info = get_hwinfo(link);
if (hw_info == NULL)
@@ -699,7 +695,6 @@ static void pcnet_config(dev_link_t *link)
if (hw_info == NULL) {
printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
" address for io base %#3lx\n", dev->base_addr);
- unregister_netdev(dev);
goto failed;
}
@@ -733,8 +728,6 @@ static void pcnet_config(dev_link_t *link)
ei_status.word16 = 1;
ei_status.reset_8390 = &pcnet_reset_8390;
- strcpy(info->node.dev_name, dev->name);
- link->dev = &info->node;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
if (info->flags & (IS_DL10019|IS_DL10022)) {
@@ -743,6 +736,21 @@ static void pcnet_config(dev_link_t *link)
mii_phy_probe(dev);
if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
info->eth_phy = 0;
+ }
+
+ link->dev = &info->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ if (register_netdev(dev) != 0) {
+ printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+ link->dev = NULL;
+ goto failed;
+ }
+
+ strcpy(info->node.dev_name, dev->name);
+
+ if (info->flags & (IS_DL10019|IS_DL10022)) {
+ u_char id = inb(dev->base_addr + 0x1a);
printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
if (info->pna_phy)
@@ -758,7 +766,6 @@ static void pcnet_config(dev_link_t *link)
printk(" hw_addr ");
for (i = 0; i < 6; i++)
printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
- link->state &= ~DEV_CONFIG_PENDING;
return;
cs_failed:
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index e499df6accc8..d348c55a9a8a 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2996,7 +2996,7 @@ use_random:
dev_addr[0] = 0x08;
dev_addr[1] = 0x00;
dev_addr[2] = 0x20;
- get_random_bytes(dev_addr, 3);
+ get_random_bytes(&dev_addr[3], 3);
return;
}
#endif /* !(__sparc__) */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index daf5cea7612f..2aae8c5a0908 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -224,6 +224,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, /* ALi 1563 integrated ethernet */
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 2d835d645fe8..e30f3c157f08 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -230,7 +230,8 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
This way, we can fail gracefully if not enough memory
is available.
*/
- if ((dev = init_etherdev(NULL, sizeof(struct xircom_private))) == NULL) {
+ dev = alloc_etherdev(sizeof(struct xircom_private));
+ if (!dev) {
printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
goto device_fail;
}
@@ -250,7 +251,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
+
private->dev = dev;
private->pdev = pdev;
@@ -259,7 +260,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
dev->irq = pdev->irq;
dev->base_addr = private->io_port;
-
initialize_card(private);
read_mac_address(private);
setup_descriptors(private);
@@ -272,7 +272,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
pci_set_drvdata(pdev, dev);
-
+ if (register_netdev(dev)) {
+ printk(KERN_ERR "xircom_probe: netdevice registration failed.\n");
+ goto reg_fail;
+ }
+
+ printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
/* start the transmitter to get a heartbeat */
/* TODO: send 2 dummy packets here */
transceiver_voodoo(private);
@@ -287,10 +292,12 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
leave("xircom_probe");
return 0;
+reg_fail:
+ kfree(private->tx_buffer);
tx_buf_fail:
kfree(private->rx_buffer);
rx_buf_fail:
- kfree(dev);
+ free_netdev(dev);
device_fail:
return -ENODEV;
}
@@ -305,22 +312,16 @@ device_fail:
static void __devexit xircom_remove(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct xircom_private *card;
+ struct xircom_private *card = dev->priv;
+
enter("xircom_remove");
- if (dev!=NULL) {
- card=dev->priv;
- if (card!=NULL) {
- if (card->rx_buffer!=NULL)
- pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
- card->rx_buffer = NULL;
- if (card->tx_buffer!=NULL)
- pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
- card->tx_buffer = NULL;
- }
- }
+ pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
+ pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
+
release_region(dev->base_addr, 128);
unregister_netdev(dev);
free_netdev(dev);
+ pci_set_drvdata(pdev, NULL);
leave("xircom_remove");
}
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index fce2b7be1706..6d3c0e8ca0e9 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -31,6 +31,7 @@
struct slvl_device
{
+ void *if_ptr; /* General purpose pointer (used by SPPP) */
struct z8530_channel *chan;
struct ppp_device pppdev;
int channel;
@@ -238,6 +239,7 @@ static inline struct slvl_device *slvl_alloc(int iobase, int irq)
return NULL;
sv = d->priv;
+ sv->if_ptr = &sv->pppdev;
sv->pppdev.dev = d;
d->base_addr = iobase;
d->irq = irq;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 76ac55236929..8cceec11df55 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -1069,6 +1069,9 @@ void sppp_attach(struct ppp_device *pd)
struct sppp *sp = &pd->sppp;
unsigned long flags;
+ /* Make sure embedding is safe for sppp_of */
+ BUG_ON(sppp_of(dev) != sp);
+
spin_lock_irqsave(&spppq_lock, flags);
/* Initialize keepalive handler. */
if (! spppq)
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index c592df7c6a4f..87e8e8040a39 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -37,7 +37,6 @@
******************************************************************************/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 2e014c19e7b8..9d286ac66662 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -84,7 +84,7 @@ static u_int irq_mask = 0xdeb8;
static int irq_list[4] = { -1 };
MODULE_AUTHOR("Simon Kelley");
-MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethnet cards.");
+MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
MODULE_PARM(irq_mask, "i");
@@ -404,9 +404,12 @@ static void atmel_config(dev_link_t *link)
goto mismatch;
for (k = 0; k < j; k++) {
while ((*p != '\0') && (*p != '/')) p++;
- if (*p == '\0')
- goto mismatch;
- p++;
+ if (*p == '\0') {
+ if (*q != '\0')
+ goto mismatch;
+ } else {
+ p++;
+ }
}
while((*q != '\0') && (*p != '\0') &&
(*p != '/') && (*p == *q)) p++, q++;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index b70f007cf2de..a1bb65b10ab9 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -412,7 +412,7 @@ void scsi_remove_device(struct scsi_device *sdev)
set_bit(SDEV_DEL, &sdev->sdev_state);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
- if (atomic_read(&sdev->access_count))
+ if (!atomic_read(&sdev->access_count))
device_del(&sdev->sdev_gendev);
up_write(&class->subsys.rwsem);
}
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index ab7b4a53568a..ea90ffc0f16d 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -465,7 +465,7 @@ show_periodic (struct class_device *class_dev, char *buf)
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ehci->periodic_size; i++) {
p = ehci->pshadow [i];
- if (!p.ptr)
+ if (likely (!p.ptr))
continue;
tag = Q_NEXT_TYPE (ehci->periodic [i]);
@@ -495,7 +495,7 @@ show_periodic (struct class_device *class_dev, char *buf)
break;
}
/* show more info the first time around */
- if (temp == seen_count) {
+ if (temp == seen_count && p.ptr) {
u32 scratch = cpu_to_le32p (
&p.qh->hw_info1);
struct ehci_qtd *qtd;
@@ -528,8 +528,10 @@ show_periodic (struct class_device *class_dev, char *buf)
seen [seen_count++].qh = p.qh;
} else
temp = 0;
- tag = Q_NEXT_TYPE (p.qh->hw_next);
- p = p.qh->qh_next;
+ if (p.qh) {
+ tag = Q_NEXT_TYPE (p.qh->hw_next);
+ p = p.qh->qh_next;
+ }
break;
case Q_TYPE_FSTN:
temp = snprintf (next, size,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 93fedc024028..bafc981be5eb 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -184,7 +184,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
- if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
+ if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
@@ -224,7 +224,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
* Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did.
*/
-#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
{
@@ -377,10 +377,14 @@ halt:
return count;
}
-#undef HALT_BIT
/*-------------------------------------------------------------------------*/
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
/*
* reverse of qh_urb_transaction: free a list of TDs.
* used for cleanup after errors, before HC sees an URB's TDs.
@@ -461,7 +465,7 @@ qh_urb_transaction (
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
- maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
/*
* buffer gets wrapped in one or more qtds;
@@ -564,11 +568,6 @@ clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
// That'd mean updating how usbcore talks to HCDs. (2.5?)
-// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
-#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-// ... and packet size, for any kind of endpoint descriptor
-#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
-
/*
* Each QH holds a qtd list; a QH is used for everything except iso.
*
@@ -728,7 +727,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
- qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT);
+ qh->hw_token &= ~HALT_BIT;
/* splice right after start */
qh->qh_next = head->qh_next;
@@ -744,6 +743,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
+#define QH_ADDR_MASK __constant_le32_to_cpu(0x7f)
+
/*
* For control/bulk/interrupt, return QH with these TDs appended.
* Allocates and initializes the QH if necessary.
@@ -778,12 +779,13 @@ static struct ehci_qh *qh_append_tds (
/* control qh may need patching after enumeration */
if (unlikely (epnum == 0)) {
/* set_address changes the address */
- if (le32_to_cpu (qh->hw_info1 & 0x7f) == 0)
+ if ((qh->hw_info1 & QH_ADDR_MASK) == 0)
qh->hw_info1 |= cpu_to_le32 (
usb_pipedevice (urb->pipe));
/* for full speed, ep0 maxpacket can grow */
- else if (!(qh->hw_info1 & cpu_to_le32 (0x3 << 12))) {
+ else if (!(qh->hw_info1
+ & __constant_cpu_to_le32 (0x3 << 12))) {
u32 info, max;
info = le32_to_cpu (qh->hw_info1);
@@ -797,7 +799,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0)
- qh->hw_info1 &= cpu_to_le32(~0x7f);
+ qh->hw_info1 &= ~QH_ADDR_MASK;
}
/* usb_clear_halt() means qh data toggle gets reset */
@@ -833,7 +835,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2).
*/
token = qtd->hw_token;
- qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+ qtd->hw_token = HALT_BIT;
wmb ();
dummy = qh->dummy;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index ed23010d21a2..43415d2b054c 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -325,6 +325,7 @@ union ehci_shadow {
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
+ u32 *hw_next; /* (all types) */
void *ptr;
};
@@ -469,27 +470,12 @@ struct ehci_fstn {
/*-------------------------------------------------------------------------*/
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
-
-#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
-#define STUB_DEBUG_FILES
-
-static inline int hcd_register_root (struct usb_hcd *hcd)
-{
- return usb_new_device (hcd_to_bus (hcd)->root_hub);
-}
-
-#else /* LINUX_VERSION_CODE */
-
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
-#endif /* LINUX_VERSION_CODE */
-
/*-------------------------------------------------------------------------*/
#endif /* __LINUX_EHCI_HCD_H */
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f978d143e090..4372ea78d09b 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -102,14 +102,8 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-/*
- * TO DO:
- *
- * - "disabled" and "sleeping" should be in hcd->state
- * - lots more testing!!
- */
-#define DRIVER_VERSION "2003 Feb 24"
+#define DRIVER_VERSION "2003 Oct 13"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -131,7 +125,6 @@ static const char hcd_name [] = "ohci_hcd";
static inline void disable (struct ohci_hcd *ohci)
{
- ohci->disabled = 1;
ohci->hcd.state = USB_STATE_HALT;
}
@@ -222,7 +215,7 @@ static int ohci_urb_enqueue (
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
- if (ohci->disabled || ohci->sleeping) {
+ if (!HCD_IS_RUNNING(ohci->hcd.state)) {
retval = -ENODEV;
goto fail;
}
@@ -278,7 +271,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
#endif
spin_lock_irqsave (&ohci->lock, flags);
- if (!ohci->disabled) {
+ if (HCD_IS_RUNNING(ohci->hcd.state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@@ -287,7 +280,6 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
*/
urb_priv = urb->hcpriv;
if (urb_priv) {
- urb_priv->state = URB_DEL;
if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed);
}
@@ -334,7 +326,7 @@ rescan:
if (!ed)
goto done;
- if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled)
+ if (!HCD_IS_RUNNING (ohci->hcd.state))
ed->state = ED_IDLE;
switch (ed->state) {
case ED_UNLINK: /* wait for hw to finish? */
@@ -355,9 +347,9 @@ rescan:
/* caller was supposed to have unlinked any requests;
* that's not our job. can't recover; must leak ed.
*/
- ohci_err (ohci, "ed %p (#%d) state %d%s\n",
+ ohci_err (ohci, "leak ed %p (#%d) state %d%s\n",
ed, epnum, ed->state,
- list_empty (&ed->td_list) ? "" : "(has tds)");
+ list_empty (&ed->td_list) ? "" : " (has tds)");
td_free (ohci, ed->dummy);
break;
}
@@ -466,8 +458,7 @@ static int hc_start (struct ohci_hcd *ohci)
struct usb_bus *bus;
spin_lock_init (&ohci->lock);
- ohci->disabled = 1;
- ohci->sleeping = 0;
+ disable (ohci);
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
@@ -496,8 +487,8 @@ static int hc_start (struct ohci_hcd *ohci)
/* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci->disabled = 0;
writel (ohci->hc_control, &ohci->regs->control);
+ ohci->hcd.state = USB_STATE_RUNNING;
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
@@ -586,9 +577,11 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
}
if (ints & OHCI_INTR_WDH) {
- writel (OHCI_INTR_WDH, &regs->intrdisable);
+ if (HCD_IS_RUNNING(hcd->state))
+ writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
- writel (OHCI_INTR_WDH, &regs->intrenable);
+ if (HCD_IS_RUNNING(hcd->state))
+ writel (OHCI_INTR_WDH, &regs->intrenable);
}
/* could track INTR_SO to reduce available PCI/... bandwidth */
@@ -600,14 +593,17 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
ptregs);
- if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)
+ if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+ && HCD_IS_RUNNING(ohci->hcd.state))
writel (OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
- writel (ints, &regs->intrstatus);
- writel (OHCI_INTR_MIE, &regs->intrenable);
- // flush those pci writes
- (void) readl (&ohci->regs->control);
+ if (HCD_IS_RUNNING(ohci->hcd.state)) {
+ writel (ints, &regs->intrstatus);
+ writel (OHCI_INTR_MIE, &regs->intrenable);
+ // flush those pci writes
+ (void) readl (&ohci->regs->control);
+ }
}
/*-------------------------------------------------------------------------*/
@@ -616,13 +612,12 @@ static void ohci_stop (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci_dbg (ohci, "stop %s controller%s\n",
+ ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
- ohci->disabled ? " (disabled)" : ""
- );
+ ohci->hcd.state);
ohci_dump (ohci, 1);
- if (!ohci->disabled)
+ if (HCD_IS_RUNNING(ohci->hcd.state))
hc_reset (ohci);
remove_debug_files (ohci);
@@ -649,8 +644,7 @@ static int hc_restart (struct ohci_hcd *ohci)
int temp;
int i;
- ohci->disabled = 1;
- ohci->sleeping = 0;
+ disable (ohci);
if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index a7584a499af0..4f8260c91ba4 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -73,7 +73,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) {
- if (ohci->disabled)
+ if (!HCD_IS_RUNNING(ohci->hcd.state))
return -ESHUTDOWN;
ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a0820ee9f178..431795328c26 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -117,7 +117,6 @@ ohci_pci_start (struct usb_hcd *hcd)
static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- unsigned long flags;
u16 cmd;
u32 tmp;
@@ -129,16 +128,15 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
/* act as if usb suspend can always be used */
ohci_dbg (ohci, "suspend to %d\n", state);
- ohci->sleeping = 1;
-
+
/* First stop processing */
- spin_lock_irqsave (&ohci->lock, flags);
+ spin_lock_irq (&ohci->lock);
ohci->hc_control &=
~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
writel (ohci->hc_control, &ohci->regs->control);
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
(void) readl (&ohci->regs->intrstatus);
- spin_unlock_irqrestore (&ohci->lock, flags);
+ spin_unlock_irq (&ohci->lock);
/* Wait a frame or two */
mdelay (1);
@@ -156,10 +154,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
&ohci->regs->intrenable);
/* Suspend chip and let things settle down a bit */
+ spin_lock_irq (&ohci->lock);
ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
- mdelay (500); /* No schedule here ! */
+ spin_unlock_irq (&ohci->lock);
+
+ set_current_state (TASK_UNINTERRUPTIBLE);
+ schedule_timeout (HZ/2);
tmp = readl (&ohci->regs->control) | OHCI_CTRL_HCFS;
switch (tmp) {
@@ -199,7 +201,6 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int temp;
int retval = 0;
- unsigned long flags;
#ifdef CONFIG_PMAC_PBOOK
{
@@ -226,6 +227,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
switch (temp) {
case OHCI_USB_RESET: // lost power
+restart:
ohci_info (ohci, "USB restart\n");
retval = hc_restart (ohci);
break;
@@ -235,31 +237,28 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
ohci_info (ohci, "USB continue from %s wakeup\n",
(temp == OHCI_USB_SUSPEND)
? "host" : "remote");
+
+ /* we "should" only need RESUME if we're SUSPENDed ... */
ohci->hc_control = OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
- mdelay (20); /* no schedule here ! */
- /* Some controllers (lucent) need a longer delay here */
- mdelay (15);
+ /* Some controllers (lucent) need extra-long delays */
+ mdelay (35); /* no schedule here ! */
temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) {
ohci_err (ohci, "controller won't resume\n");
- ohci->disabled = 1;
- retval = -EIO;
- break;
+ /* maybe we can reset */
+ goto restart;
}
- /* Some chips likes being resumed first */
+ /* Then re-enable operations */
writel (OHCI_USB_OPER, &ohci->regs->control);
(void) readl (&ohci->regs->control);
mdelay (3);
- /* Then re-enable operations */
- spin_lock_irqsave (&ohci->lock, flags);
- ohci->disabled = 0;
- ohci->sleeping = 0;
+ spin_lock_irq (&ohci->lock);
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
if (!ohci->ed_rm_list) {
if (ohci->ed_controltail)
@@ -274,25 +273,22 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
- /* Check for a pending done list */
writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
(void) readl (&ohci->regs->intrdisable);
- spin_unlock_irqrestore (&ohci->lock, flags);
+ spin_unlock_irq (&ohci->lock);
#ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac)
enable_irq (hcd->pdev->irq);
#endif
+
+ /* Check for a pending done list */
if (ohci->hcca->done_head)
dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
/* assume there are TDs on the bulk and control lists */
writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
-
-// ohci_dump_status (ohci);
-ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
- ohci->sleeping, ohci->disabled);
break;
default:
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 0d1e63469030..7a6a1d4ec5c5 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -449,7 +449,7 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
ohci->ed_rm_list = ed;
/* enable SOF interrupt */
- if (!ohci->sleeping) {
+ if (HCD_IS_RUNNING (ohci->hcd.state)) {
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
// flush those pci writes
@@ -794,7 +794,16 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* looks odd ... that doesn't include protocol stalls
* (or maybe some other things)
*/
- if (cc != TD_CC_STALL || !usb_pipecontrol (urb->pipe))
+ switch (cc) {
+ case TD_DATAUNDERRUN:
+ if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)
+ break;
+ /* fallthrough */
+ case TD_CC_STALL:
+ if (usb_pipecontrol (urb->pipe))
+ break;
+ /* fallthrough */
+ default:
ohci_dbg (ohci,
"urb %p path %s ep%d%s %08x cc %d --> status %d\n",
urb, urb->dev->devpath,
@@ -802,6 +811,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
usb_pipein (urb->pipe) ? "in" : "out",
le32_to_cpu (td->hwINFO),
cc, cc_to_error [cc]);
+ }
return rev;
}
@@ -871,7 +881,8 @@ rescan_all:
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps.
*/
- if (tick_before (tick, ed->tick) && !ohci->disabled) {
+ if (tick_before (tick, ed->tick)
+ && HCD_IS_RUNNING(ohci->hcd.state)) {
last = &ed->ed_next;
continue;
}
@@ -901,7 +912,7 @@ rescan_this:
urb = td->urb;
urb_priv = td->urb->hcpriv;
- if (urb_priv->state != URB_DEL) {
+ if (urb->status == -EINPROGRESS) {
prev = &td->hwNextTD;
continue;
}
@@ -938,7 +949,7 @@ rescan_this:
/* but if there's work queued, reschedule */
if (!list_empty (&ed->td_list)) {
- if (!ohci->disabled && !ohci->sleeping)
+ if (HCD_IS_RUNNING(ohci->hcd.state))
ed_schedule (ohci, ed);
}
@@ -947,7 +958,7 @@ rescan_this:
}
/* maybe reenable control and bulk lists */
- if (!ohci->disabled && !ohci->ed_rm_list) {
+ if (HCD_IS_RUNNING(ohci->hcd.state) && !ohci->ed_rm_list) {
u32 command = 0, control = 0;
if (ohci->ed_controltail) {
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index a9c564b98897..7419f7f10741 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -314,13 +314,10 @@ typedef struct urb_priv {
struct ed *ed;
__u16 length; // # tds in this request
__u16 td_cnt; // tds already serviced
- int state;
struct td *td [0]; // all TDs in this request
} urb_priv_t;
-#define URB_DEL 1
-
#define TD_HASH_SIZE 64 /* power'o'two */
// sizeof (struct td) ~= 64 == 2^6 ...
#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE)
@@ -365,8 +362,6 @@ struct ohci_hcd {
/*
* driver state
*/
- int disabled; /* e.g. got a UE, we're hung */
- int sleeping;
int load [NUM_INTS];
u32 hc_control; /* copy of hc control reg */
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 2e64c26c9266..fb9a0a30457e 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -28,6 +28,7 @@ comment "Input core support is needed for USB HID input layer or HIDBP support"
config USB_HIDINPUT
bool "HID input layer support"
+ default y
depends on INPUT && USB_HID
help
Say Y here if you want to use a USB keyboard, mouse or joystick,
diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h
index 5af43d42c33a..dd935b62c1a8 100644
--- a/drivers/usb/serial/keyspan_usa90msg.h
+++ b/drivers/usb/serial/keyspan_usa90msg.h
@@ -182,14 +182,14 @@ struct keyspan_usa90_portStatusMessage
// MSR bits
-#define MSR_dCTS 0x01 // CTS has changed since last report
-#define MSR_dDSR 0x02
-#define MSR_dRI 0x04
-#define MSR_dDCD 0x08
-
-#define MSR_CTS 0x10 // current state of CTS
-#define MSR_DSR 0x20
-#define MSR_RI 0x40
+#define USA_MSR_dCTS 0x01 // CTS has changed since last report
+#define USA_MSR_dDSR 0x02
+#define USA_MSR_dRI 0x04
+#define USA_MSR_dDCD 0x08
+
+#define USA_MSR_CTS 0x10 // current state of CTS
+#define USA_MSR_DSR 0x20
+#define USA_USA_MSR_RI 0x40
#define MSR_DCD 0x80
// ie: the maximum length of an endpoint buffer
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 6eb51b58bc87..6e13bbeb6aa8 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -778,9 +778,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id *i
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
- dbg("%s - reset config", __FUNCTION__);
- retval = usb_reset_configuration (serial->dev);
-
if (id->driver_info) {
startup = (void *)id->driver_info;
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index a66a3664a9cb..3c7c42213f89 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1461,6 +1461,15 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
unsigned long addr, size;
struct imstt_par *par;
struct fb_info *info;
+#ifdef CONFIG_PPC_OF
+ struct device_node *dp;
+
+ dp = pci_device_to_OF_node(pdev);
+ if(dp)
+ printk(KERN_INFO "%s: OF name %s\n",__FUNCTION__, dp->name);
+ else
+ printk(KERN_ERR "imsttfb: no OF node for pci device\n");
+#endif /* CONFIG_PPC_OF */
size = sizeof(struct fb_info) + sizeof(struct imstt_par) +
sizeof(u32) * 16;
@@ -1488,6 +1497,11 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
switch (pdev->device) {
case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
par->ramdac = IBM;
+#ifdef CONFIG_PPC_OF
+ if (dp && ((strcmp(dp->name, "IMS,tt128mb8") == 0) ||
+ (strcmp(dp->name, "IMS,tt128mb8A") == 0)))
+ par->ramdac = TVP;
+#endif /* CONFIG_PPC_OF */
break;
case PCI_DEVICE_ID_IMS_TT3D: /* IMS,tt3d */
par->ramdac = TVP;
diff --git a/fs/Kconfig b/fs/Kconfig
index e61c963af94e..9cd68069d6d6 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -204,7 +204,7 @@ config REISERFS_FS
In general, ReiserFS is as fast as ext2, but is very efficient with
large directories and small files. Additional patches are needed
- for NFS and quotas, please see <http://www.reiserfs.org/> for links.
+ for NFS and quotas, please see <http://www.namesys.com/> for links.
It is more easily extended to have features currently found in
database and keyword search systems than block allocation based file
@@ -212,7 +212,7 @@ config REISERFS_FS
plugins consistent with our motto ``It takes more than a license to
make source code open.''
- Read <http://www.reiserfs.org/> to learn more about reiserfs.
+ Read <http://www.namesys.com/> to learn more about reiserfs.
Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com.
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 0df165f8ee01..12cad78987fd 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -19,7 +19,7 @@ static struct posix_acl *
ext2_acl_from_disk(const void *value, size_t size)
{
const char *end = (char *)value + size;
- size_t n, count;
+ int n, count;
struct posix_acl *acl;
if (!value)
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 53051432b4bf..2ae72c1a7e86 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -20,7 +20,7 @@ static struct posix_acl *
ext3_acl_from_disk(const void *value, size_t size)
{
const char *end = (char *)value + size;
- size_t n, count;
+ int n, count;
struct posix_acl *acl;
if (!value)
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 1144f75b0662..02a877d32232 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -769,7 +769,6 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock,
int boundary = 0;
int depth = ext3_block_to_path(inode, iblock, offsets, &boundary);
struct ext3_inode_info *ei = EXT3_I(inode);
- loff_t new_size;
J_ASSERT(handle != NULL || create == 0);
@@ -834,23 +833,17 @@ out:
if (!err)
err = ext3_splice_branch(handle, inode, iblock, chain,
partial, left);
+ /* i_disksize growing is protected by truncate_sem
+ * don't forget to protect it if you're about to implement
+ * concurrent ext3_get_block() -bzzz */
+ if (!err && extend_disksize && inode->i_size > ei->i_disksize)
+ ei->i_disksize = inode->i_size;
up(&ei->truncate_sem);
if (err == -EAGAIN)
goto changed;
if (err)
goto cleanup;
- if (extend_disksize) {
- /*
- * This is not racy against ext3_truncate's modification of
- * i_disksize because VM/VFS ensures that the file cannot be
- * extended while truncate is in progress. It is racy between
- * multiple parallel instances of get_block, but we have BKL.
- */
- new_size = inode->i_size;
- if (new_size > ei->i_disksize)
- ei->i_disksize = new_size;
- }
set_buffer_new(bh_result);
goto got_it;
diff --git a/fs/inode.c b/fs/inode.c
index 76d7881f2b60..4ba2baca5b0c 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -453,7 +453,7 @@ static void prune_icache(int nr_to_scan)
dispose_list(&freeable);
up(&iprune_sem);
- if (current_is_kswapd)
+ if (current_is_kswapd())
mod_page_state(kswapd_inodesteal, reap);
else
mod_page_state(pginodesteal, reap);
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 3cc44044a70a..ebef6567753c 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: background.c,v 1.38 2003/05/26 09:50:38 dwmw2 Exp $
+ * $Id: background.c,v 1.44 2003/10/08 13:29:55 dwmw2 Exp $
*
*/
@@ -19,6 +19,7 @@
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/unistd.h>
+#include <linux/suspend.h>
#include "nodelist.h"
@@ -61,13 +62,6 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
{
- if (c->mtd->type == MTD_NANDFLASH) {
- /* stop a eventually scheduled wbuf flush timer */
- del_timer_sync(&c->wbuf_timer);
- /* make sure, that a scheduled wbuf flush task is completed */
- flush_scheduled_work();
- }
-
spin_lock(&c->erase_completion_lock);
if (c->gc_task) {
D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
@@ -82,6 +76,9 @@ static int jffs2_garbage_collect_thread(void *_c)
struct jffs2_sb_info *c = _c;
daemonize("jffs2_gcd_mtd%d", c->mtd->index);
+ allow_signal(SIGKILL);
+ allow_signal(SIGSTOP);
+ allow_signal(SIGCONT);
c->gc_task = current;
up(&c->gc_thread_start);
@@ -89,10 +86,7 @@ static int jffs2_garbage_collect_thread(void *_c)
set_user_nice(current, 10);
for (;;) {
- spin_lock_irq(&current_sig_lock);
- siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
- recalc_sigpending();
- spin_unlock_irq(&current_sig_lock);
+ allow_signal(SIGHUP);
if (!thread_should_wake(c)) {
set_current_state (TASK_INTERRUPTIBLE);
@@ -104,6 +98,13 @@ static int jffs2_garbage_collect_thread(void *_c)
schedule();
}
+ if (current->flags & PF_FREEZE) {
+ refrigerator(0);
+ /* refrigerator() should recalc sigpending for us
+ but doesn't. No matter - allow_signal() will. */
+ continue;
+ }
+
cond_resched();
/* Put_super will send a SIGKILL and then wait on the sem.
@@ -112,9 +113,7 @@ static int jffs2_garbage_collect_thread(void *_c)
siginfo_t info;
unsigned long signr;
- spin_lock_irq(&current_sig_lock);
- signr = dequeue_signal(current, &current->blocked, &info);
- spin_unlock_irq(&current_sig_lock);
+ signr = dequeue_signal_lock(current, &current->blocked, &info);
switch(signr) {
case SIGSTOP:
@@ -125,6 +124,7 @@ static int jffs2_garbage_collect_thread(void *_c)
case SIGKILL:
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
+ die:
spin_lock(&c->erase_completion_lock);
c->gc_task = NULL;
spin_unlock(&c->erase_completion_lock);
@@ -138,13 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c)
}
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
- spin_lock_irq(&current_sig_lock);
- siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
- recalc_sigpending();
- spin_unlock_irq(&current_sig_lock);
+ disallow_signal(SIGHUP);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
- jffs2_garbage_collect_pass(c);
+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
+ printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n");
+ goto die;
+ }
}
}
@@ -169,8 +169,8 @@ static int thread_should_wake(struct jffs2_sb_info *c)
*/
dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
- if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER &&
- (dirty > c->sector_size))
+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
+ (dirty > c->nospc_dirty_size))
ret = 1;
D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 01a575d6bfae..c05f64b5a2a1 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $
+ * $Id: build.c,v 1.52 2003/10/09 00:38:38 dwmw2 Exp $
*
*/
@@ -228,6 +228,58 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
return ret;
}
+static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
+{
+ uint32_t size;
+
+ /* Deletion should almost _always_ be allowed. We're fairly
+ buggered once we stop allowing people to delete stuff
+ because there's not enough free space... */
+ c->resv_blocks_deletion = 2;
+
+ /* Be conservative about how much space we need before we allow writes.
+ On top of that which is required for deletia, require an extra 2%
+ of the medium to be available, for overhead caused by nodes being
+ split across blocks, etc. */
+
+ size = c->flash_size / 50; /* 2% of flash size */
+ size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */
+ size += c->sector_size - 1; /* ... and round up */
+
+ c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size);
+
+ /* When do we let the GC thread run in the background */
+
+ c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
+
+ /* When do we allow garbage collection to merge nodes to make
+ long-term progress at the expense of short-term space exhaustion? */
+ c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
+
+ /* When do we allow garbage collection to eat from bad blocks rather
+ than actually making progress? */
+ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2;
+
+ /* If there's less than this amount of dirty space, don't bother
+ trying to GC to make more space. It'll be a fruitless task */
+ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
+
+ D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
+ c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
+ D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n",
+ c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
+ D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n",
+ c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
+ D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
+ c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
+ D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n",
+ c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
+ D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n",
+ c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
+ D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
+ c->nospc_dirty_size));
+}
+
int jffs2_do_mount_fs(struct jffs2_sb_info *c)
{
int i;
@@ -276,5 +328,8 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
kfree(c->blocks);
return -EIO;
}
+
+ jffs2_calc_trigger_levels(c);
+
return 0;
}
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index a2479e837acd..471ec55e6a15 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr.c,v 1.26 2003/01/12 13:21:28 dwmw2 Exp $
+ * $Id: compr.c,v 1.27 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
index 9dec50194a2c..a72ce670c5d4 100644
--- a/fs/jffs2/compr_rtime.c
+++ b/fs/jffs2/compr_rtime.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
*
*
* Very simple lz77-ish encoder.
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 76ad2570a301..c05e65f4c724 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 93742552a9e9..561e37f3d644 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: dir.c,v 1.77 2003/06/05 14:42:24 dwmw2 Exp $
+ * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $
*
*/
@@ -22,18 +22,22 @@
#include <linux/time.h>
#include "nodelist.h"
-/* Urgh. Please tell me there's a nicer way of doing this. */
+/* Urgh. Please tell me there's a nicer way of doing these. */
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
typedef int mknod_arg_t;
+#define NAMEI_COMPAT(x) ((void *)x)
#else
typedef dev_t mknod_arg_t;
+#define NAMEI_COMPAT(x) (x)
#endif
static int jffs2_readdir (struct file *, void *, filldir_t);
-static int jffs2_create (struct inode *,struct dentry *,int, struct nameidata *);
-static struct dentry *jffs2_lookup (struct inode *,struct dentry *, struct nameidata *);
+static int jffs2_create (struct inode *,struct dentry *,int,
+ struct nameidata *);
+static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
+ struct nameidata *);
static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
static int jffs2_unlink (struct inode *,struct dentry *);
static int jffs2_symlink (struct inode *,struct dentry *,const char *);
@@ -54,8 +58,8 @@ struct file_operations jffs2_dir_operations =
struct inode_operations jffs2_dir_inode_operations =
{
- .create = jffs2_create,
- .lookup = jffs2_lookup,
+ .create = NAMEI_COMPAT(jffs2_create),
+ .lookup = NAMEI_COMPAT(jffs2_lookup),
.link = jffs2_link,
.unlink = jffs2_unlink,
.symlink = jffs2_symlink,
@@ -73,7 +77,8 @@ struct inode_operations jffs2_dir_inode_operations =
and we use the same hash function as the dentries. Makes this
nice and simple
*/
-static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, struct nameidata *nd)
+static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
+ struct nameidata *nd)
{
struct jffs2_inode_info *dir_f;
struct jffs2_sb_info *c;
@@ -176,7 +181,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
- struct nameidata *nd)
+ struct nameidata *nd)
{
struct jffs2_raw_inode *ri;
struct jffs2_inode_info *f, *dir_f;
@@ -292,7 +297,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
struct jffs2_full_dirent *fd;
int namelen;
uint32_t alloclen, phys_ofs;
- uint32_t writtenlen;
int ret;
/* FIXME: If you care. We'd need to use frags for the target
@@ -339,7 +343,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, &writtenlen);
+ fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_inode(ri);
@@ -356,20 +360,12 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f->metadata = fn;
up(&f->sem);
- /* Work out where to put the dirent node now. */
- writtenlen = PAD(writtenlen);
- phys_ofs += writtenlen;
- alloclen -= writtenlen;
-
- if (alloclen < sizeof(*rd)+namelen) {
- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ jffs2_complete_reservation(c);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ if (ret) {
+ /* Eep. */
+ jffs2_clear_inode(inode);
+ return ret;
}
rd = jffs2_alloc_raw_dirent();
@@ -397,7 +393,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
@@ -436,7 +432,6 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
struct jffs2_full_dirent *fd;
int namelen;
uint32_t alloclen, phys_ofs;
- uint32_t writtenlen;
int ret;
mode |= S_IFDIR;
@@ -476,7 +471,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_inode(ri);
@@ -493,20 +488,12 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
f->metadata = fn;
up(&f->sem);
- /* Work out where to put the dirent node now. */
- writtenlen = PAD(writtenlen);
- phys_ofs += writtenlen;
- alloclen -= writtenlen;
-
- if (alloclen < sizeof(*rd)+namelen) {
- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ jffs2_complete_reservation(c);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ if (ret) {
+ /* Eep. */
+ jffs2_clear_inode(inode);
+ return ret;
}
rd = jffs2_alloc_raw_dirent();
@@ -534,7 +521,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
@@ -591,7 +578,6 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mk
jint16_t dev;
int devlen = 0;
uint32_t alloclen, phys_ofs;
- uint32_t writtenlen;
int ret;
if (!old_valid_dev(rdev))
@@ -639,7 +625,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mk
ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, &writtenlen);
+ fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_inode(ri);
@@ -656,20 +642,12 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mk
f->metadata = fn;
up(&f->sem);
- /* Work out where to put the dirent node now. */
- writtenlen = PAD(writtenlen);
- phys_ofs += writtenlen;
- alloclen -= writtenlen;
-
- if (alloclen < sizeof(*rd)+namelen) {
- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ jffs2_complete_reservation(c);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ if (ret) {
+ /* Eep. */
+ jffs2_clear_inode(inode);
+ return ret;
}
rd = jffs2_alloc_raw_dirent();
@@ -700,7 +678,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mk
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 6e4327692e8d..f7a940962e5f 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $
+ * $Id: erase.c,v 1.53 2003/10/08 17:22:54 dwmw2 Exp $
*
*/
@@ -123,10 +123,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
list_del(&jeb->list);
c->erasing_size += c->sector_size;
+ c->wasted_size -= jeb->wasted_size;
c->free_size -= jeb->free_size;
c->used_size -= jeb->used_size;
c->dirty_size -= jeb->dirty_size;
- jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
+ jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
jffs2_free_all_node_refs(c, jeb);
list_add(&jeb->list, &c->erasing_list);
spin_unlock(&c->erase_completion_lock);
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index e462866532d8..8b3f8e7e5640 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: file.c,v 1.85 2003/05/26 09:50:38 dwmw2 Exp $
+ * $Id: file.c,v 1.96 2003/10/11 11:47:23 dwmw2 Exp $
*
*/
@@ -29,24 +29,10 @@ extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- if (!c->wbuf || !c->wbuf_len)
- return 0;
- /* flush write buffer and update c->nextblock */
-
- /* FIXME NAND */
- /* At the moment we flush the buffer, to make sure
- * that every thing is on the flash.
- * maybe we have to think about it to find a smarter
- * solution.
- */
- down(&c->alloc_sem);
- down(&f->sem);
- jffs2_flush_wbuf(c,2);
- up(&f->sem);
- up(&c->alloc_sem);
+ /* Trigger GC to flush any pending writes for this inode */
+ jffs2_flush_wbuf_gc(c, inode->i_ino);
return 0;
}
@@ -79,151 +65,6 @@ struct address_space_operations jffs2_file_address_operations =
.commit_write = jffs2_commit_write
};
-int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
-{
- struct jffs2_full_dnode *old_metadata, *new_metadata;
- struct inode *inode = dentry->d_inode;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- struct jffs2_raw_inode *ri;
- unsigned short dev;
- unsigned char *mdata = NULL;
- int mdatalen = 0;
- unsigned int ivalid;
- uint32_t phys_ofs, alloclen;
- int ret;
- D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
- ret = inode_change_ok(inode, iattr);
- if (ret)
- return ret;
-
- /* Special cases - we don't want more than one data node
- for these types on the medium at any time. So setattr
- must read the original data associated with the node
- (i.e. the device numbers or the target name) and write
- it out again with the appropriate data attached */
- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
- /* For these, we don't actually need to read the old node */
- dev = old_encode_dev(dentry->d_inode->i_rdev);
- mdata = (char *)&dev;
- mdatalen = sizeof(dev);
- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
- } else if (S_ISLNK(inode->i_mode)) {
- mdatalen = f->metadata->size;
- mdata = kmalloc(f->metadata->size, GFP_USER);
- if (!mdata)
- return -ENOMEM;
- ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
- if (ret) {
- kfree(mdata);
- return ret;
- }
- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
- }
-
- ri = jffs2_alloc_raw_inode();
- if (!ri) {
- if (S_ISLNK(inode->i_mode))
- kfree(mdata);
- return -ENOMEM;
- }
-
- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
- jffs2_free_raw_inode(ri);
- if (S_ISLNK(inode->i_mode & S_IFMT))
- kfree(mdata);
- return ret;
- }
- down(&f->sem);
- ivalid = iattr->ia_valid;
-
- ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
- ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
- ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
- ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-
- ri->ino = cpu_to_je32(inode->i_ino);
- ri->version = cpu_to_je32(++f->highest_version);
-
- ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
- ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
-
- if (ivalid & ATTR_MODE)
- if (iattr->ia_mode & S_ISGID &&
- !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
- ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
- else
- ri->mode = cpu_to_jemode(iattr->ia_mode);
- else
- ri->mode = cpu_to_jemode(inode->i_mode);
-
-
- ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
- ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
- ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
- ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
-
- ri->offset = cpu_to_je32(0);
- ri->csize = ri->dsize = cpu_to_je32(mdatalen);
- ri->compr = JFFS2_COMPR_NONE;
- if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
- /* It's an extension. Make it a hole node */
- ri->compr = JFFS2_COMPR_ZERO;
- ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
- ri->offset = cpu_to_je32(inode->i_size);
- }
- ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- if (mdatalen)
- ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
- else
- ri->data_crc = cpu_to_je32(0);
-
- new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, NULL);
- if (S_ISLNK(inode->i_mode))
- kfree(mdata);
-
- if (IS_ERR(new_metadata)) {
- jffs2_complete_reservation(c);
- jffs2_free_raw_inode(ri);
- up(&f->sem);
- return PTR_ERR(new_metadata);
- }
- /* It worked. Update the inode */
- inode->i_atime = ITIME(je32_to_cpu(ri->atime));
- inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
- inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
- inode->i_mode = jemode_to_cpu(ri->mode);
- inode->i_uid = je16_to_cpu(ri->uid);
- inode->i_gid = je16_to_cpu(ri->gid);
-
-
- old_metadata = f->metadata;
-
- if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
- vmtruncate(inode, iattr->ia_size);
- jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
- }
-
- if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
- jffs2_add_full_dnode_to_inode(c, f, new_metadata);
- inode->i_size = iattr->ia_size;
- f->metadata = NULL;
- } else {
- f->metadata = new_metadata;
- }
- if (old_metadata) {
- jffs2_mark_node_obsolete(c, old_metadata->raw);
- jffs2_free_full_dnode(old_metadata);
- }
- jffs2_free_raw_inode(ri);
-
- up(&f->sem);
- jffs2_complete_reservation(c);
-
- return 0;
-}
-
int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -320,7 +161,7 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = cpu_to_je32(0);
- fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL);
+ fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
if (IS_ERR(fn)) {
ret = PTR_ERR(fn);
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index d71073d27b77..bf1d109a035f 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: fs.c,v 1.24 2003/04/29 09:52:58 dwmw2 Exp $
+ * $Id: fs.c,v 1.32 2003/10/11 11:47:23 dwmw2 Exp $
*
*/
@@ -21,8 +21,159 @@
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/vfs.h>
+#include <linux/crc32.h>
#include "nodelist.h"
+
+static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
+{
+ struct jffs2_full_dnode *old_metadata, *new_metadata;
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_raw_inode *ri;
+ unsigned short dev;
+ unsigned char *mdata = NULL;
+ int mdatalen = 0;
+ unsigned int ivalid;
+ uint32_t phys_ofs, alloclen;
+ int ret;
+ D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
+ ret = inode_change_ok(inode, iattr);
+ if (ret)
+ return ret;
+
+ /* Special cases - we don't want more than one data node
+ for these types on the medium at any time. So setattr
+ must read the original data associated with the node
+ (i.e. the device numbers or the target name) and write
+ it out again with the appropriate data attached */
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+ /* For these, we don't actually need to read the old node */
+ dev = old_encode_dev(inode->i_rdev);
+ mdata = (char *)&dev;
+ mdatalen = sizeof(dev);
+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
+ } else if (S_ISLNK(inode->i_mode)) {
+ mdatalen = f->metadata->size;
+ mdata = kmalloc(f->metadata->size, GFP_USER);
+ if (!mdata)
+ return -ENOMEM;
+ ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
+ if (ret) {
+ kfree(mdata);
+ return ret;
+ }
+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
+ }
+
+ ri = jffs2_alloc_raw_inode();
+ if (!ri) {
+ if (S_ISLNK(inode->i_mode))
+ kfree(mdata);
+ return -ENOMEM;
+ }
+
+ ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ if (ret) {
+ jffs2_free_raw_inode(ri);
+ if (S_ISLNK(inode->i_mode & S_IFMT))
+ kfree(mdata);
+ return ret;
+ }
+ down(&f->sem);
+ ivalid = iattr->ia_valid;
+
+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+ ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
+
+ ri->ino = cpu_to_je32(inode->i_ino);
+ ri->version = cpu_to_je32(++f->highest_version);
+
+ ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
+ ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
+
+ if (ivalid & ATTR_MODE)
+ if (iattr->ia_mode & S_ISGID &&
+ !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
+ ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
+ else
+ ri->mode = cpu_to_jemode(iattr->ia_mode);
+ else
+ ri->mode = cpu_to_jemode(inode->i_mode);
+
+
+ ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
+ ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
+ ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
+ ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
+
+ ri->offset = cpu_to_je32(0);
+ ri->csize = ri->dsize = cpu_to_je32(mdatalen);
+ ri->compr = JFFS2_COMPR_NONE;
+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+ /* It's an extension. Make it a hole node */
+ ri->compr = JFFS2_COMPR_ZERO;
+ ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
+ ri->offset = cpu_to_je32(inode->i_size);
+ }
+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+ if (mdatalen)
+ ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
+ else
+ ri->data_crc = cpu_to_je32(0);
+
+ new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
+ if (S_ISLNK(inode->i_mode))
+ kfree(mdata);
+
+ if (IS_ERR(new_metadata)) {
+ jffs2_complete_reservation(c);
+ jffs2_free_raw_inode(ri);
+ up(&f->sem);
+ return PTR_ERR(new_metadata);
+ }
+ /* It worked. Update the inode */
+ inode->i_atime = ITIME(je32_to_cpu(ri->atime));
+ inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+ inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
+ inode->i_mode = jemode_to_cpu(ri->mode);
+ inode->i_uid = je16_to_cpu(ri->uid);
+ inode->i_gid = je16_to_cpu(ri->gid);
+
+
+ old_metadata = f->metadata;
+
+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
+ vmtruncate(inode, iattr->ia_size);
+ jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
+ }
+
+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
+ jffs2_add_full_dnode_to_inode(c, f, new_metadata);
+ inode->i_size = iattr->ia_size;
+ f->metadata = NULL;
+ } else {
+ f->metadata = new_metadata;
+ }
+ if (old_metadata) {
+ jffs2_mark_node_obsolete(c, old_metadata->raw);
+ jffs2_free_full_dnode(old_metadata);
+ }
+ jffs2_free_raw_inode(ri);
+
+ up(&f->sem);
+ jffs2_complete_reservation(c);
+
+ return 0;
+}
+
+int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ return jffs2_do_setattr(dentry->d_inode, iattr);
+}
+
int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
@@ -38,8 +189,8 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
spin_lock(&c->erase_completion_lock);
avail = c->dirty_size + c->free_size;
- if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
- avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE;
+ if (avail > c->sector_size * c->resv_blocks_write)
+ avail -= c->sector_size * c->resv_blocks_write;
else
avail = 0;
@@ -149,7 +300,7 @@ void jffs2_read_inode (struct inode *inode)
case S_IFIFO:
inode->i_op = &jffs2_file_inode_operations;
init_special_inode(inode, inode->i_mode,
- old_decode_dev(je16_to_cpu(rdev)));
+ old_decode_dev((je16_to_cpu(rdev))));
break;
default:
@@ -161,6 +312,27 @@ void jffs2_read_inode (struct inode *inode)
D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
}
+void jffs2_dirty_inode(struct inode *inode)
+{
+ struct iattr iattr;
+
+ if (!(inode->i_state & I_DIRTY_DATASYNC)) {
+ D1(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
+ return;
+ }
+
+ D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino));
+
+ iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME;
+ iattr.ia_mode = inode->i_mode;
+ iattr.ia_uid = inode->i_uid;
+ iattr.ia_gid = inode->i_gid;
+ iattr.ia_atime = inode->i_atime;
+ iattr.ia_mtime = inode->i_mtime;
+ iattr.ia_ctime = inode->i_ctime;
+
+ jffs2_do_setattr(inode, &iattr);
+}
int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
{
@@ -194,6 +366,7 @@ void jffs2_write_super (struct super_block *sb)
D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
jffs2_garbage_collect_trigger(c);
jffs2_erase_pending_blocks(c);
+ jffs2_flush_wbuf_gc(c, 0);
}
@@ -288,25 +461,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
/* Joern -- stick alignment for weird 8-byte-page flash here */
if (jffs2_cleanmarker_oob(c)) {
- /* Cleanmarker is out-of-band, so inline size zero */
- c->cleanmarker_size = 0;
- }
-
- if (c->mtd->type == MTD_NANDFLASH) {
- /* Initialise write buffer */
- c->wbuf_pagesize = c->mtd->oobblock;
- c->wbuf_ofs = 0xFFFFFFFF;
- c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
- if (!c->wbuf)
- return -ENOMEM;
-
- /* Initialise process for timed wbuf flush */
- INIT_WORK(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c);
-
- /* Initialise timer for timed wbuf flush */
- init_timer(&c->wbuf_timer);
- c->wbuf_timer.function = jffs2_wbuf_timeout;
- c->wbuf_timer.data = (unsigned long) c;
+ /* NAND (or other bizarre) flash... do setup accordingly */
+ ret = jffs2_nand_flash_setup(c);
+ if (ret)
+ return ret;
}
c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
@@ -352,7 +510,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
out_inohash:
kfree(c->inocache_list);
out_wbuf:
- if (c->wbuf)
- kfree(c->wbuf);
+ jffs2_nand_flash_cleanup(c);
+
return ret;
}
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index a715475bdec7..1cc6bfc8fc42 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $
+ * $Id: gc.c,v 1.114 2003/10/09 13:53:35 dwmw2 Exp $
*
*/
@@ -49,7 +49,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
put the clever wear-levelling algorithms. Eventually. */
/* We possibly want to favour the dirtier blocks more when the
number of free blocks is low. */
- if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) {
+ if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
nextlist = &c->bad_used_list;
} else if (n < 50 && !list_empty(&c->erasable_list)) {
@@ -274,7 +274,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
if (ref_flags(raw) == REF_PRISTINE)
ic->state = INO_STATE_GC;
else {
- D1(printk("Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
+ D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
inum));
}
break;
@@ -493,6 +493,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
int ret;
uint32_t phys_ofs, alloclen;
uint32_t crc;
+ int retried = 0;
D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
@@ -573,13 +574,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
ret = -ENOMEM;
goto out_node;
}
+
+ /* OK, all the CRCs are good; this node can just be copied as-is. */
+ retry:
nraw->flash_offset = phys_ofs;
nraw->totlen = raw->totlen;
nraw->next_phys = NULL;
- /* OK, all the CRCs are good; this node can just be copied as-is. */
-
ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node);
+
if (ret || (retlen != raw->totlen)) {
printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
raw->totlen, phys_ofs, ret, retlen);
@@ -592,8 +595,34 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
jffs2_mark_node_obsolete(c, nraw);
} else {
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
- jffs2_free_raw_node_ref(raw);
+ jffs2_free_raw_node_ref(nraw);
}
+ if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {
+ /* Try to reallocate space and retry */
+ uint32_t dummy;
+ struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
+
+ retried = 1;
+
+ D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ ret = jffs2_reserve_space_gc(c, raw->totlen, &phys_ofs, &dummy);
+
+ if (!ret) {
+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ goto retry;
+ }
+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+ jffs2_free_raw_node_ref(nraw);
+ }
+
if (!ret)
ret = -EIO;
goto out_node;
@@ -684,7 +713,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
- new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, NULL);
+ new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC);
if (IS_ERR(new_fn)) {
printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
@@ -728,7 +757,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
sizeof(rd)+rd.nsize, ret);
return ret;
}
- new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, NULL);
+ new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC);
if (IS_ERR(new_fd)) {
printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
@@ -951,7 +980,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
sizeof(ri), ret);
return ret;
}
- new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL);
+ new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC);
if (IS_ERR(new_fn)) {
printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
@@ -1010,7 +1039,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
{
struct jffs2_full_dnode *new_fn;
struct jffs2_raw_inode ri;
- uint32_t alloclen, phys_ofs, offset, orig_end;
+ uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
int ret = 0;
unsigned char *comprbuf = NULL, *writebuf;
struct page *pg;
@@ -1023,29 +1052,129 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
f->inocache->ino, start, end));
orig_end = end;
+ orig_start = start;
- /* If we're looking at the last node in the block we're
- garbage-collecting, we allow ourselves to merge as if the
- block was already erasing. We're likely to be GC'ing a
- partial page, and the next block we GC is likely to have
- the other half of this page right at the beginning, which
- means we'd expand it _then_, as nr_erasing_blocks would have
- increased since we checked, and in doing so would obsolete
- the partial node which we'd have written here. Meaning that
- the GC would churn and churn, and just leave dirty blocks in
- it's wake.
- */
- if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {
- /* Shitloads of space */
- /* FIXME: Integrate this properly with GC calculations */
- start &= ~(PAGE_CACHE_SIZE-1);
- end = min_t(uint32_t, start + PAGE_CACHE_SIZE, JFFS2_F_I_SIZE(f));
- D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",
- start, end));
- if (end < orig_end) {
- printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);
- end = orig_end;
+ if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {
+ /* Attempt to do some merging. But only expand to cover logically
+ adjacent frags if the block containing them is already considered
+ to be dirty. Otherwise we end up with GC just going round in
+ circles dirtying the nodes it already wrote out, especially
+ on NAND where we have small eraseblocks and hence a much higher
+ chance of nodes having to be split to cross boundaries. */
+
+ struct jffs2_node_frag *frag;
+ uint32_t min, max;
+
+ min = start & ~(PAGE_CACHE_SIZE-1);
+ max = min + PAGE_CACHE_SIZE;
+
+ frag = jffs2_lookup_node_frag(&f->fragtree, start);
+
+ /* BUG_ON(!frag) but that'll happen anyway... */
+
+ BUG_ON(frag->ofs != start);
+
+ /* First grow down... */
+ while((frag = frag_prev(frag)) && frag->ofs >= min) {
+
+ /* If the previous frag doesn't even reach the beginning, there's
+ excessive fragmentation. Just merge. */
+ if (frag->ofs > min) {
+ D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",
+ frag->ofs, frag->ofs+frag->size));
+ start = frag->ofs;
+ continue;
+ }
+ /* OK. This frag holds the first byte of the page. */
+ if (!frag->node || !frag->node->raw) {
+ D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",
+ frag->ofs, frag->ofs+frag->size));
+ break;
+ } else {
+
+ /* OK, it's a frag which extends to the beginning of the page. Does it live
+ in a block which is still considered clean? If so, don't obsolete it.
+ If not, cover it anyway. */
+
+ struct jffs2_raw_node_ref *raw = frag->node->raw;
+ struct jffs2_eraseblock *jeb;
+
+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
+
+ if (jeb == c->gcblock) {
+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+ start = frag->ofs;
+ break;
+ }
+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
+ D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",
+ frag->ofs, frag->ofs+frag->size, jeb->offset));
+ break;
+ }
+
+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",
+ frag->ofs, frag->ofs+frag->size, jeb->offset));
+ start = frag->ofs;
+ break;
+ }
+ }
+
+ /* ... then up */
+
+ /* Find last frag which is actually part of the node we're to GC. */
+ frag = jffs2_lookup_node_frag(&f->fragtree, end-1);
+
+ while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) {
+
+ /* If the previous frag doesn't even reach the beginning, there's lots
+ of fragmentation. Just merge. */
+ if (frag->ofs+frag->size < max) {
+ D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",
+ frag->ofs, frag->ofs+frag->size));
+ end = frag->ofs + frag->size;
+ continue;
+ }
+
+ if (!frag->node || !frag->node->raw) {
+ D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",
+ frag->ofs, frag->ofs+frag->size));
+ break;
+ } else {
+
+ /* OK, it's a frag which extends to the beginning of the page. Does it live
+ in a block which is still considered clean? If so, don't obsolete it.
+ If not, cover it anyway. */
+
+ struct jffs2_raw_node_ref *raw = frag->node->raw;
+ struct jffs2_eraseblock *jeb;
+
+ jeb = &c->blocks[raw->flash_offset / c->sector_size];
+
+ if (jeb == c->gcblock) {
+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",
+ frag->ofs, frag->ofs+frag->size, ref_offset(raw)));
+ end = frag->ofs + frag->size;
+ break;
+ }
+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {
+ D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",
+ frag->ofs, frag->ofs+frag->size, jeb->offset));
+ break;
+ }
+
+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",
+ frag->ofs, frag->ofs+frag->size, jeb->offset));
+ end = frag->ofs + frag->size;
+ break;
+ }
}
+ D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
+ orig_start, orig_end, start, end));
+
+ BUG_ON(end > JFFS2_F_I_SIZE(f));
+ BUG_ON(end < orig_end);
+ BUG_ON(start > orig_start);
}
/* First, use readpage() to read the appropriate page into the page cache */
@@ -1114,7 +1243,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
- new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, NULL);
+ new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, ALLOC_GC);
if (IS_ERR(new_fn)) {
printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c
index 734608a97806..1c0bebc6b60e 100644
--- a/fs/jffs2/ioctl.c
+++ b/fs/jffs2/ioctl.c
@@ -3,11 +3,11 @@
*
* Copyright (C) 2001 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: ioctl.c,v 1.6 2002/05/20 14:56:38 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.7 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 4346f9874a2f..d81680fe6aea 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: malloc.c,v 1.24 2003/03/11 17:30:29 gleixner Exp $
+ * $Id: malloc.c,v 1.25 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 294854d372f7..6c94c36998f1 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.80 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 0cfad439f844..d36f29aa5991 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.h,v 1.93 2003/02/24 21:47:28 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.104 2003/10/08 11:45:11 dwmw2 Exp $
*
*/
@@ -29,7 +29,7 @@
#endif
#ifndef CONFIG_JFFS2_FS_DEBUG
-#define CONFIG_JFFS2_FS_DEBUG 2
+#define CONFIG_JFFS2_FS_DEBUG 1
#endif
#if CONFIG_JFFS2_FS_DEBUG > 0
@@ -201,10 +201,11 @@ struct jffs2_eraseblock
};
#define ACCT_SANITY_CHECK(c, jeb) do { \
- if (jeb->used_size + jeb->dirty_size + jeb->free_size + jeb->wasted_size + jeb->unchecked_size != c->sector_size) { \
- printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
+ struct jffs2_eraseblock *___j = jeb; \
+ if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \
+ printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
- jeb->free_size, jeb->dirty_size, jeb->used_size, jeb->wasted_size, jeb->unchecked_size, c->sector_size); \
+ ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \
BUG(); \
} \
if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
@@ -215,15 +216,46 @@ struct jffs2_eraseblock
} \
} while(0)
+static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
+{
+ struct jffs2_raw_node_ref *ref;
+ int i=0;
+
+ printk(KERN_NOTICE);
+ for (ref = jeb->first_node; ref; ref = ref->next_phys) {
+ printk("%08x->", ref_offset(ref));
+ if (++i == 8) {
+ i = 0;
+ printk("\n" KERN_NOTICE);
+ }
+ }
+ printk("\n");
+}
+
+
#define ACCT_PARANOIA_CHECK(jeb) do { \
uint32_t my_used_size = 0; \
uint32_t my_unchecked_size = 0; \
struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
while (ref2) { \
+ if (unlikely(ref2->flash_offset < jeb->offset || \
+ ref2->flash_offset > jeb->offset + c->sector_size)) { \
+ printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \
+ ref_offset(ref2), jeb->offset); \
+ paranoia_failed_dump(jeb); \
+ BUG(); \
+ } \
if (ref_flags(ref2) == REF_UNCHECKED) \
my_unchecked_size += ref2->totlen; \
else if (!ref_obsolete(ref2)) \
my_used_size += ref2->totlen; \
+ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
+ printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
+ ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
+ jeb->last_node, ref_offset(jeb->last_node)); \
+ paranoia_failed_dump(jeb); \
+ BUG(); \
+ } \
ref2 = ref2->next_phys; \
} \
if (my_used_size != jeb->used_size) { \
@@ -239,14 +271,7 @@ struct jffs2_eraseblock
#define ALLOC_NORMAL 0 /* Normal allocation */
#define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
#define ALLOC_GC 2 /* Space requested for GC. Give it or die */
-
-#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */
-#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */
-#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE) /* ... allow a normal filesystem deletion */
-#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */
-#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */
-#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */
-
+#define ALLOC_NORETRY 3 /* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */
/* How much dirty space before it goes on the very_dirty_list */
#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
@@ -314,8 +339,9 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c);
/* write.c */
int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri);
-struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, uint32_t *writelen);
-struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, uint32_t *writelen);
+
+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode);
+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode);
int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct jffs2_raw_inode *ri, unsigned char *buf,
uint32_t offset, uint32_t writelen, uint32_t *retlen);
@@ -383,7 +409,8 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
#ifdef CONFIG_JFFS2_FS_NAND
/* wbuf.c */
-int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 62ab0469ac03..980de2e22cd8 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodemgmt.c,v 1.94 2003/02/19 17:50:26 gleixner Exp $
+ * $Id: nodemgmt.c,v 1.102 2003/10/08 17:21:19 dwmw2 Exp $
*
*/
@@ -43,13 +43,10 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
{
int ret = -EAGAIN;
- int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
+ int blocksneeded = c->resv_blocks_write;
/* align it */
minsize = PAD(minsize);
- if (prio == ALLOC_DELETION)
- blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
-
D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
down(&c->alloc_sem);
@@ -63,8 +60,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
int ret;
uint32_t dirty, avail;
- up(&c->alloc_sem);
-
/* calculate real dirty size
* dirty_size contains blocks on erase_pending_list
* those blocks are counted in c->nr_erasing_blocks.
@@ -78,10 +73,16 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
* of nodes.
*/
dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
- if (dirty < c->sector_size) {
- D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n",
+ if (dirty < c->nospc_dirty_size) {
+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
+ break;
+ }
+ D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
dirty, c->unchecked_size, c->sector_size));
+
spin_unlock(&c->erase_completion_lock);
+ up(&c->alloc_sem);
return -ENOSPC;
}
@@ -96,12 +97,20 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
*/
avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
if ( (avail / c->sector_size) <= blocksneeded) {
+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
+ break;
+ }
+
D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
avail, blocksneeded * c->sector_size));
spin_unlock(&c->erase_completion_lock);
+ up(&c->alloc_sem);
return -ENOSPC;
}
-
+
+ up(&c->alloc_sem);
+
D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
@@ -158,12 +167,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
if (jeb && minsize > jeb->free_size) {
/* Skip the end of this block and file it as having some dirty space */
/* If there's a pending write to it, flush now */
- if (c->wbuf_len) {
+ if (jffs2_wbuf_dirty(c)) {
spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
- jffs2_flush_wbuf(c, 1);
+ jffs2_flush_wbuf_pad(c);
spin_lock(&c->erase_completion_lock);
- /* We know nobody's going to have changed nextblock. Just continue */
+ jeb = c->nextblock;
+ goto restart;
}
c->wasted_size += jeb->free_size;
c->free_size -= jeb->free_size;
@@ -219,7 +229,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
/* c->nextblock is NULL, no update to c->nextblock allowed */
spin_unlock(&c->erase_completion_lock);
- jffs2_flush_wbuf(c, 1);
+ jffs2_flush_wbuf_pad(c);
spin_lock(&c->erase_completion_lock);
/* Have another go. It'll be on the erasable_list now */
return -EAGAIN;
@@ -344,10 +354,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- if (c->wbuf_len) {
+ if (jffs2_wbuf_dirty(c)) {
/* Flush the last write in the block if it's outstanding */
spin_unlock(&c->erase_completion_lock);
- jffs2_flush_wbuf(c, 1);
+ jffs2_flush_wbuf_pad(c);
spin_lock(&c->erase_completion_lock);
}
@@ -370,6 +380,20 @@ void jffs2_complete_reservation(struct jffs2_sb_info *c)
up(&c->alloc_sem);
}
+static inline int on_list(struct list_head *obj, struct list_head *head)
+{
+ struct list_head *this;
+
+ list_for_each(this, head) {
+ if (this == obj) {
+ D1(printk("%p is on list at %p\n", obj, head));
+ return 1;
+
+ }
+ }
+ return 0;
+}
+
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
{
struct jffs2_eraseblock *jeb;
@@ -418,11 +442,26 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
// Take care, that wasted size is taken into concern
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
D1(printk("Dirtying\n"));
- addedsize = ref->totlen + jeb->wasted_size;
- jeb->dirty_size += addedsize;
- c->dirty_size += addedsize;
- c->wasted_size -= jeb->wasted_size;
- jeb->wasted_size = 0;
+ addedsize = ref->totlen;
+ jeb->dirty_size += ref->totlen;
+ c->dirty_size += ref->totlen;
+
+ /* Convert wasted space to dirty, if not a bad block */
+ if (jeb->wasted_size) {
+ if (on_list(&jeb->list, &c->bad_used_list)) {
+ D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n",
+ jeb->offset));
+ addedsize = 0; /* To fool the refiling code later */
+ } else {
+ D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n",
+ jeb->wasted_size, jeb->offset));
+ addedsize += jeb->wasted_size;
+ jeb->dirty_size += jeb->wasted_size;
+ c->dirty_size += jeb->wasted_size;
+ c->wasted_size -= jeb->wasted_size;
+ jeb->wasted_size = 0;
+ }
+ }
} else {
D1(printk("Wasting\n"));
addedsize = 0;
@@ -455,7 +494,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
list_del(&jeb->list);
}
- if (c->wbuf_len) {
+ if (jffs2_wbuf_dirty(c)) {
D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
#if 0 /* This check was added to allow us to find places where we added nodes to the lists
@@ -506,7 +545,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
list_add_tail(&jeb->list, &c->dirty_list);
} else if (VERYDIRTY(c, jeb->dirty_size) &&
- !VERYDIRTY(c, jeb->dirty_size - ref->totlen)) {
+ !VERYDIRTY(c, jeb->dirty_size - addedsize)) {
D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
list_del(&jeb->list);
D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
@@ -569,7 +608,7 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
- printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE);
+ printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write);
if (c->nextblock) {
printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
@@ -672,7 +711,7 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->erasable_pending_wbuf_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
- printk(KERN_DEBUG "erase_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
+ printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
}
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index d06443ceec68..91401c1c9dca 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: os-linux.h,v 1.26 2003/05/16 18:45:25 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.37 2003/10/11 11:47:23 dwmw2 Exp $
*
*/
@@ -19,6 +19,9 @@
#define os_to_jffs2_mode(x) (x)
#define jffs2_to_os_mode(x) (x)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
+#define kstatfs statfs
+#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
@@ -68,7 +71,7 @@
/* Hmmm. P'raps generic code should only ever see versions of signal
functions which do the locking automatically? */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) && !defined(__rh_config_h__)
#define current_sig_lock current->sigmask_lock
#else
#define current_sig_lock current->sighand->siglock
@@ -108,10 +111,14 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
-#define jffs2_flush_wbuf(c, flag) do { ; } while(0)
+#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
-#define jffs2_flash_writev jffs2_flash_direct_writev
+#define jffs2_nand_flash_setup(c) (0)
+#define jffs2_nand_flash_cleanup(c) do {} while(0)
+#define jffs2_wbuf_dirty(c) (0)
+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
@@ -122,11 +129,11 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
-
+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
struct kstatfs;
/* wbuf.c */
-int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
@@ -135,6 +142,8 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
void jffs2_wbuf_timeout(unsigned long data);
void jffs2_wbuf_process(void *data);
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
#endif /* NAND */
/* background.c */
@@ -151,7 +160,6 @@ extern struct file_operations jffs2_file_operations;
extern struct inode_operations jffs2_file_inode_operations;
extern struct address_space_operations jffs2_file_address_operations;
int jffs2_fsync(struct file *, struct dentry *, int);
-int jffs2_setattr (struct dentry *dentry, struct iattr *iattr);
int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
int jffs2_readpage (struct file *, struct page *);
@@ -165,8 +173,10 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
extern struct inode_operations jffs2_symlink_inode_operations;
/* fs.c */
+int jffs2_setattr (struct dentry *, struct iattr *);
void jffs2_read_inode (struct inode *);
void jffs2_clear_inode (struct inode *);
+void jffs2_dirty_inode(struct inode *inode);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
struct jffs2_raw_inode *ri);
int jffs2_statfs (struct super_block *, struct kstatfs *);
diff --git a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h
index 412c467c540a..953b65320558 100644
--- a/fs/jffs2/pushpull.h
+++ b/fs/jffs2/pushpull.h
@@ -3,11 +3,11 @@
*
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: pushpull.h,v 1.8 2002/05/20 14:56:38 dwmw2 Exp $
+ * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index 7216eb97cd46..adeeeb19aa4b 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $
+ * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
@@ -16,6 +16,7 @@
#include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
+#include <linux/compiler.h>
#include "nodelist.h"
int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
@@ -165,7 +166,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
/* Now we're pointing at the first frag which overlaps our page */
while(offset < end) {
D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
- if (!frag || frag->ofs > offset) {
+ if (unlikely(!frag || frag->ofs > offset)) {
uint32_t holesize = end - offset;
if (frag) {
D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
@@ -177,13 +178,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
buf += holesize;
offset += holesize;
continue;
- } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) {
- D1(printk(KERN_NOTICE "Eep. Overlap in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
- f->inocache->ino, frag->ofs, offset));
- D1(jffs2_print_frag_list(f));
- memset(buf, 0, end - offset);
- return -EIO;
- } else if (!frag->node) {
+ } else if (unlikely(!frag->node)) {
uint32_t holeend = min(end, frag->ofs + frag->size);
D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
memset(buf, 0, holeend - offset);
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 4f935bfa2fd0..ea4bbf7f237f 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $
+ * $Id: readinode.c,v 1.107 2003/10/04 08:33:06 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 55c51478692c..6e59cad2da9c 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: scan.c,v 1.100 2003/06/05 14:42:24 dwmw2 Exp $
+ * $Id: scan.c,v 1.104 2003/10/11 14:52:48 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
@@ -65,6 +65,16 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
#define BLK_STATE_ALLDIRTY 4
#define BLK_STATE_BADBLOCK 5
+static inline int min_free(struct jffs2_sb_info *c)
+{
+ uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
+#ifdef CONFIG_JFFS2_FS_NAND
+ if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
+ return c->wbuf_pagesize;
+#endif
+ return min;
+
+}
int jffs2_scan_medium(struct jffs2_sb_info *c)
{
int i, ret;
@@ -106,7 +116,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
if (ret < 0)
- return ret;
+ goto out;
ACCT_PARANOIA_CHECK(jeb);
@@ -151,8 +161,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
Later when we do snapshots, this must be the most recent block,
not the one with most free space.
*/
- if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) &&
- (jffs2_can_mark_obsolete(c) || jeb->free_size > c->wbuf_pagesize) &&
+ if (jeb->free_size > min_free(c) &&
(!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
/* Better candidate for the next writes to go to */
if (c->nextblock) {
@@ -210,7 +219,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->dirty_size -= c->nextblock->dirty_size;
c->nextblock->dirty_size = 0;
}
-
+#ifdef CONFIG_JFFS2_FS_NAND
if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
@@ -226,21 +235,25 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->nextblock->free_size -= skip;
c->free_size -= skip;
}
+#endif
if (c->nr_erasing_blocks) {
if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
jffs2_erase_pending_trigger(c);
}
+ ret = 0;
+ out:
if (buf_size)
kfree(flashbuf);
#ifndef __ECOS
else
c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
#endif
- return 0;
+ return ret;
}
static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
@@ -672,6 +685,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
ofs, je32_to_cpu(ri->node_crc), crc);
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
+ jffs2_free_raw_node_ref(raw);
return 0;
}
ic = jffs2_scan_make_ino_cache(c, ino);
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index cc55f6176f9b..0f662f5d8a81 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: super.c,v 1.79 2003/05/27 22:35:42 dwmw2 Exp $
+ * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $
*
*/
@@ -26,8 +26,7 @@
#include <linux/namei.h>
#include "nodelist.h"
-void jffs2_put_super (struct super_block *);
-
+static void jffs2_put_super(struct super_block *);
static kmem_cache_t *jffs2_inode_cachep;
@@ -65,7 +64,8 @@ static struct super_operations jffs2_super_operations =
.write_super = jffs2_write_super,
.statfs = jffs2_statfs,
.remount_fs = jffs2_remount_fs,
- .clear_inode = jffs2_clear_inode
+ .clear_inode = jffs2_clear_inode,
+ .dirty_inode = jffs2_dirty_inode,
};
static int jffs2_sb_compare(struct super_block *sb, void *data)
@@ -136,8 +136,7 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
/* Failure case... */
up_write(&sb->s_umount);
deactivate_super(sb);
- sb = ERR_PTR(ret);
- goto out_put1;
+ return ERR_PTR(ret);
}
sb->s_flags |= MS_ACTIVE;
@@ -145,7 +144,6 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
out_put:
kfree(c);
- out_put1:
put_mtd_device(mtd);
return sb;
@@ -253,8 +251,7 @@ out:
return ERR_PTR(err);
}
-
-void jffs2_put_super (struct super_block *sb)
+static void jffs2_put_super (struct super_block *sb)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
@@ -263,13 +260,12 @@ void jffs2_put_super (struct super_block *sb)
if (!(sb->s_flags & MS_RDONLY))
jffs2_stop_garbage_collect_thread(c);
down(&c->alloc_sem);
- jffs2_flush_wbuf(c, 1);
+ jffs2_flush_wbuf_pad(c);
up(&c->alloc_sem);
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
kfree(c->blocks);
- if (c->wbuf)
- kfree(c->wbuf);
+ jffs2_nand_flash_cleanup(c);
kfree(c->inocache_list);
if (c->mtd->sync)
c->mtd->sync(c->mtd);
@@ -284,7 +280,7 @@ static void jffs2_kill_sb(struct super_block *sb)
put_mtd_device(c->mtd);
kfree(c);
}
-
+
static struct file_system_type jffs2_fs_type = {
.owner = THIS_MODULE,
.name = "jffs2",
@@ -292,13 +288,15 @@ static struct file_system_type jffs2_fs_type = {
.kill_sb = jffs2_kill_sb,
};
-
-
static int __init init_jffs2_fs(void)
{
int ret;
- printk(KERN_INFO "JFFS2 version 2.1. (C) 2001, 2002 Red Hat, Inc.\n");
+ printk(KERN_INFO "JFFS2 version 2.2."
+#ifdef CONFIG_FS_JFFS2_NAND
+ " (NAND)"
+#endif
+ " (C) 2001-2003 Red Hat, Inc.\n");
jffs2_inode_cachep = kmem_cache_create("jffs2_i",
sizeof(struct jffs2_inode_info),
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 56de574be22b..46d306cf0df4 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -3,11 +3,11 @@
*
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: symlink.c,v 1.11 2002/07/23 17:00:45 dwmw2 Exp $
+ * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $
*
*/
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 82ae18377782..ecfb155cb82b 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: wbuf.c,v 1.30 2003/02/19 17:48:49 gleixner Exp $
+ * $Id: wbuf.c,v 1.53 2003/10/11 11:46:09 dwmw2 Exp $
*
*/
@@ -18,28 +18,86 @@
#include <linux/mtd/nand.h>
#include "nodelist.h"
+/* For testing write failures */
+#undef BREAKME
+#undef BREAKMEHEADER
+
+#ifdef BREAKME
+static unsigned char *brokenbuf;
+#endif
+
/* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 5
/* two seconds timeout for timed wbuf-flushing */
#define WBUF_FLUSH_TIMEOUT 2 * HZ
-#define JFFS2_OOB_ECCPOS0 0
-#define JFFS2_OOB_ECCPOS1 1
-#define JFFS2_OOB_ECCPOS2 2
-#define JFFS2_OOB_ECCPOS3 3
-#define JFFS2_OOB_ECCPOS4 6
-#define JFFS2_OOB_ECCPOS5 7
+struct jffs2_inodirty {
+ uint32_t ino;
+ struct jffs2_inodirty *next;
+};
-#define NAND_JFFS2_OOB8_FSDAPOS 6
-#define NAND_JFFS2_OOB16_FSDAPOS 8
-#define NAND_JFFS2_OOB8_FSDALEN 2
-#define NAND_JFFS2_OOB16_FSDALEN 8
+static struct jffs2_inodirty inodirty_nomem;
-struct nand_oobinfo jffs2_oobinfo = {
- .useecc = 1,
- .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
-};
+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
+{
+ struct jffs2_inodirty *this = c->wbuf_inodes;
+
+ /* If a malloc failed, consider _everything_ dirty */
+ if (this == &inodirty_nomem)
+ return 1;
+
+ /* If ino == 0, _any_ non-GC writes mean 'yes' */
+ if (this && !ino)
+ return 1;
+
+ /* Look to see if the inode in question is pending in the wbuf */
+ while (this) {
+ if (this->ino == ino)
+ return 1;
+ this = this->next;
+ }
+ return 0;
+}
+
+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
+{
+ struct jffs2_inodirty *this;
+
+ this = c->wbuf_inodes;
+
+ if (this != &inodirty_nomem) {
+ while (this) {
+ struct jffs2_inodirty *next = this->next;
+ kfree(this);
+ this = next;
+ }
+ }
+ c->wbuf_inodes = NULL;
+}
+
+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
+{
+ struct jffs2_inodirty *new;
+
+ /* Mark the superblock dirty so that kupdated will flush... */
+ OFNI_BS_2SFFJ(c)->s_dirt = 1;
+
+ if (jffs2_wbuf_pending_for_ino(c, ino))
+ return;
+
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
+ jffs2_clear_wbuf_ino_list(c);
+ c->wbuf_inodes = &inodirty_nomem;
+ return;
+ }
+ new->ino = ino;
+ new->next = c->wbuf_inodes;
+ c->wbuf_inodes = new;
+ return;
+}
static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
{
@@ -70,74 +128,267 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
}
}
-/*
-* Timed flushing of wbuf. If we have no consecutive write to wbuf, within
-* the specified time, we flush the contents with padding !
-*/
-void jffs2_wbuf_timeout (unsigned long data)
-{
- struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;
- /*
- * Wake up the flush process, we need process context to have the right
- * to sleep on flash write
- */
- D1(printk(KERN_DEBUG "jffs2_wbuf_timeout(): timer expired\n"));
- schedule_work(&c->wbuf_task);
-}
+/* Recover from failure to write wbuf. Recover the nodes up to the
+ * wbuf, not the one which we were starting to try to write. */
-/*
-* Process for timed wbuf flush
-*
-* FIXME What happens, if we have a write failure there ????
-*/
-void jffs2_wbuf_process (void *data)
+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
{
- struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;
-
- D1(printk(KERN_DEBUG "jffs2_wbuf_process() entered\n"));
-
- /* Check, if the timer is active again */
- if (timer_pending (&c->wbuf_timer)) {
- D1(printk (KERN_DEBUG "Nothing to do, timer is active again\n"));
- return;
+ struct jffs2_eraseblock *jeb, *new_jeb;
+ struct jffs2_raw_node_ref **first_raw, **raw;
+ size_t retlen;
+ int ret;
+ unsigned char *buf;
+ uint32_t start, end, ofs, len;
+
+ spin_lock(&c->erase_completion_lock);
+
+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+ D1(printk("About to refile bad block at %08x\n", jeb->offset));
+
+ D2(jffs2_dump_block_lists(c));
+ /* File the existing block on the bad_used_list.... */
+ if (c->nextblock == jeb)
+ c->nextblock = NULL;
+ else /* Not sure this should ever happen... need more coffee */
+ list_del(&jeb->list);
+ if (jeb->first_node) {
+ D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
+ list_add(&jeb->list, &c->bad_used_list);
+ } else {
+ BUG();
+ /* It has to have had some nodes or we couldn't be here */
+ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
+ list_add(&jeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_erase_pending_trigger(c);
+ }
+ D2(jffs2_dump_block_lists(c));
+
+ /* Adjust its size counts accordingly */
+ c->wasted_size += jeb->free_size;
+ c->free_size -= jeb->free_size;
+ jeb->wasted_size += jeb->free_size;
+ jeb->free_size = 0;
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ /* Find the first node to be recovered, by skipping over every
+ node which ends before the wbuf starts, or which is obsolete. */
+ first_raw = &jeb->first_node;
+ while (*first_raw &&
+ (ref_obsolete(*first_raw) ||
+ (ref_offset(*first_raw) + (*first_raw)->totlen) < c->wbuf_ofs)) {
+ D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
+ ref_offset(*first_raw), ref_flags(*first_raw),
+ (ref_offset(*first_raw) + (*first_raw)->totlen),
+ c->wbuf_ofs));
+ first_raw = &(*first_raw)->next_phys;
}
- if (down_trylock(&c->alloc_sem)) {
- /* If someone else has the alloc_sem, they're about to
- write anyway. So no need to waste space by
- padding */
- D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupied\n"));
+ if (!*first_raw) {
+ /* All nodes were obsolete. Nothing to recover. */
+ D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
+ spin_unlock(&c->erase_completion_lock);
return;
- }
+ }
- D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem got\n"));
+ start = ref_offset(*first_raw);
+ end = ref_offset(*first_raw) + (*first_raw)->totlen;
- if (!c->nextblock) {
- D1(printk(KERN_DEBUG "jffs2_wbuf_process(): nextblock NULL, nothing to do\n"));
- if (c->wbuf_len) {
- printk(KERN_WARNING "jffs2_wbuf_process(): c->wbuf_len is 0x%03x but nextblock is NULL!\n", c->wbuf_len);
- up(&c->alloc_sem);
- BUG();
+ /* Find the last node to be recovered */
+ raw = first_raw;
+ while ((*raw)) {
+ if (!ref_obsolete(*raw))
+ end = ref_offset(*raw) + (*raw)->totlen;
+
+ raw = &(*raw)->next_phys;
+ }
+ spin_unlock(&c->erase_completion_lock);
+
+ D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end));
+
+ buf = NULL;
+ if (start < c->wbuf_ofs) {
+ /* First affected node was already partially written.
+ * Attempt to reread the old data into our buffer. */
+
+ buf = kmalloc(end - start, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n");
+
+ goto read_failed;
}
+
+ /* Do the read... */
+ ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
+ if (ret == -EIO && retlen == c->wbuf_ofs - start) {
+ /* ECC recovered */
+ ret = 0;
+ }
+ if (ret || retlen != c->wbuf_ofs - start) {
+ printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
+
+ kfree(buf);
+ buf = NULL;
+ read_failed:
+ first_raw = &(*first_raw)->next_phys;
+ /* If this was the only node to be recovered, give up */
+ if (!(*first_raw))
+ return;
+
+ /* It wasn't. Go on and try to recover nodes complete in the wbuf */
+ start = ref_offset(*first_raw);
+ } else {
+ /* Read succeeded. Copy the remaining data from the wbuf */
+ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
+ }
+ }
+ /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
+ Either 'buf' contains the data, or we find it in the wbuf */
+
+
+ /* ... and get an allocation of space from a shiny new block instead */
+ ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
+ if (ret) {
+ printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
+ if (buf)
+ kfree(buf);
return;
}
-
-
- /* if !c->nextblock then the tail will have got flushed from
- jffs2_do_reserve_space() anyway. */
- if(c->nextblock)
- jffs2_flush_wbuf(c, 2); /* pad and adjust nextblock */
+ if (end-start >= c->wbuf_pagesize) {
+ /* Need to do another write immediately. This, btw,
+ means that we'll be writing from 'buf' and not from
+ the wbuf. Since if we're writing from the wbuf there
+ won't be more than a wbuf full of data, now will
+ there? :) */
+
+ uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
+
+ D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
+ towrite, ofs));
+
+#ifdef BREAKMEHEADER
+ static int breakme;
+ if (breakme++ == 20) {
+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
+ breakme = 0;
+ c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
+ brokenbuf, NULL, c->oobinfo);
+ ret = -EIO;
+ } else
+#endif
+ ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
+ buf, NULL, c->oobinfo);
+
+ if (ret || retlen != towrite) {
+ /* Argh. We tried. Really we did. */
+ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n");
+ kfree(buf);
+
+ if (retlen) {
+ struct jffs2_raw_node_ref *raw2;
+
+ raw2 = jffs2_alloc_raw_node_ref();
+ if (!raw2)
+ return;
+
+ raw2->flash_offset = ofs | REF_OBSOLETE;
+ raw2->totlen = (*first_raw)->totlen;
+ raw2->next_phys = NULL;
+ raw2->next_in_ino = NULL;
+
+ jffs2_add_physical_node_ref(c, raw2);
+ }
+ return;
+ }
+ printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);
- up(&c->alloc_sem);
-}
+ c->wbuf_len = (end - start) - towrite;
+ c->wbuf_ofs = ofs + towrite;
+ memcpy(c->wbuf, buf + towrite, c->wbuf_len);
+ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
+ kfree(buf);
+ } else {
+ /* OK, now we're left with the dregs in whichever buffer we're using */
+ if (buf) {
+ memcpy(c->wbuf, buf, end-start);
+ kfree(buf);
+ } else {
+ memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
+ }
+ c->wbuf_ofs = ofs;
+ c->wbuf_len = end - start;
+ }
+
+ /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
+ new_jeb = &c->blocks[ofs / c->sector_size];
+
+ spin_lock(&c->erase_completion_lock);
+ if (new_jeb->first_node) {
+ /* Odd, but possible with ST flash later maybe */
+ new_jeb->last_node->next_phys = *first_raw;
+ } else {
+ new_jeb->first_node = *first_raw;
+ }
+
+ raw = first_raw;
+ while (*raw) {
+ D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
+ (*raw)->totlen, ref_offset(*raw), ref_flags(*raw), ofs));
+
+ if (ref_obsolete(*raw)) {
+ /* Shouldn't really happen much */
+ new_jeb->dirty_size += (*raw)->totlen;
+ new_jeb->free_size -= (*raw)->totlen;
+ c->dirty_size += (*raw)->totlen;
+ } else {
+ new_jeb->used_size += (*raw)->totlen;
+ new_jeb->free_size -= (*raw)->totlen;
+ jeb->dirty_size += (*raw)->totlen;
+ jeb->used_size -= (*raw)->totlen;
+ c->dirty_size += (*raw)->totlen;
+ }
+ c->free_size -= (*raw)->totlen;
+ (*raw)->flash_offset = ofs | ref_flags(*raw);
+ ofs += (*raw)->totlen;
+ new_jeb->last_node = *raw;
+
+ raw = &(*raw)->next_phys;
+ }
+
+ /* Fix up the original jeb now it's on the bad_list */
+ *first_raw = NULL;
+ if (first_raw == &jeb->first_node) {
+ jeb->last_node = NULL;
+ D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
+ list_del(&jeb->list);
+ list_add(&jeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_erase_pending_trigger(c);
+ }
+ else
+ jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ ACCT_SANITY_CHECK(c,new_jeb);
+ D1(ACCT_PARANOIA_CHECK(new_jeb));
+
+ spin_unlock(&c->erase_completion_lock);
+
+ D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));
+}
/* Meaning of pad argument:
0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
1: Pad, do not adjust nextblock free_size
2: Pad, adjust nextblock free_size
*/
-int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
{
int ret;
size_t retlen;
@@ -153,9 +404,6 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
BUG();
}
- /* delete a eventually started timed wbuf flush */
- del_timer_sync(&c->wbuf_timer);
-
if(!c->wbuf || !c->wbuf_len)
return 0;
@@ -179,28 +427,30 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
/* else jffs2_flash_writev has actually filled in the rest of the
buffer for us, and will deal with the node refs etc. later. */
- ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, &jffs2_oobinfo);
-
+#ifdef BREAKME
+ static int breakme;
+ if (breakme++ == 20) {
+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
+ breakme = 0;
+ c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
+ &retlen, brokenbuf, NULL, c->oobinfo);
+ ret = -EIO;
+ } else
+#endif
+ ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
+
+
if (ret || retlen != c->wbuf_pagesize) {
if (ret)
- printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %d\n",ret);
- else
- printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
+ else {
+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
retlen, c->wbuf_pagesize);
-
- ret = -EIO;
- /* CHECKME NAND
- So that the caller knows what happened. If
- we were called from jffs2_flash_writev(), it'll
- know to return failure and _its_ caller will
- try again. writev gives back to jffs2_write_xxx
- in write.c. There are the real fixme's
- */
+ ret = -EIO;
+ }
+
+ jffs2_wbuf_recover(c);
- /* FIXME NAND
- If we were called from GC or fsync, there's no repair kit yet
- */
-
return ret;
}
@@ -230,18 +480,71 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
/* Stick any now-obsoleted blocks on the erase_pending_list */
spin_lock(&c->erase_completion_lock);
jffs2_refile_wbuf_blocks(c);
+ jffs2_clear_wbuf_ino_list(c);
spin_unlock(&c->erase_completion_lock);
memset(c->wbuf,0xff,c->wbuf_pagesize);
- /* adjust write buffer offset, else we get a non contigous write bug */
- c->wbuf_ofs+= c->wbuf_pagesize;
+ /* adjust write buffer offset, else we get a non contiguous write bug */
+ c->wbuf_ofs += c->wbuf_pagesize;
c->wbuf_len = 0;
return 0;
}
+/* Trigger garbage collection to flush the write-buffer.
+ If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
+ outstanding. If ino arg non-zero, do it only if a write for the
+ given inode is outstanding. */
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
+{
+ uint32_t old_wbuf_ofs;
+ uint32_t old_wbuf_len;
+ int ret = 0;
+
+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
+
+ down(&c->alloc_sem);
+ if (!jffs2_wbuf_pending_for_ino(c, ino)) {
+ D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
+ up(&c->alloc_sem);
+ return 0;
+ }
+
+ old_wbuf_ofs = c->wbuf_ofs;
+ old_wbuf_len = c->wbuf_len;
+
+ while (old_wbuf_len &&
+ old_wbuf_ofs == c->wbuf_ofs) {
+
+ up(&c->alloc_sem);
+
+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
+
+ ret = jffs2_garbage_collect_pass(c);
+ if (ret) {
+ /* GC failed. Flush it with padding instead */
+ down(&c->alloc_sem);
+ ret = __jffs2_flush_wbuf(c, 2);
+ break;
+ }
+ down(&c->alloc_sem);
+ }
+
+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
+
+ up(&c->alloc_sem);
+ return ret;
+}
+
+/* Pad write-buffer to end and write it, wasting space. */
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
+{
+ return __jffs2_flush_wbuf(c, 1);
+}
+
+
#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
-int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen)
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
{
struct iovec outvecs[3];
uint32_t totlen = 0;
@@ -275,7 +578,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsi
/* It's a write to a new block */
if (c->wbuf_len) {
D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
- ret = jffs2_flush_wbuf(c, 1);
+ ret = jffs2_flush_wbuf_pad(c);
if (ret) {
/* the underlying layer has to check wbuf_len to do the cleanup */
D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
@@ -341,16 +644,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsi
}
/* write buffer is full, flush buffer */
- ret = jffs2_flush_wbuf(c, 0);
+ ret = __jffs2_flush_wbuf(c, 0);
if (ret) {
/* the underlying layer has to check wbuf_len to do the cleanup */
D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
+ /* Retlen zero to make sure our caller doesn't mark the space dirty.
+ We've already done everything that's necessary */
*retlen = 0;
return ret;
}
outvec_to += donelen;
c->wbuf_ofs = outvec_to;
-
+
/* All invecs done ? */
if (invec == count)
goto alldone;
@@ -396,7 +701,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsi
outvecs[splitvec].iov_len = split_ofs;
/* We did cross a page boundary, so we write some now */
- ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, &jffs2_oobinfo);
+ ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
/* At this point we have no problem,
c->wbuf is empty.
@@ -433,13 +738,14 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsi
}
c->wbuf_len = wbuf_ptr - c->wbuf;
-alldone:
+ /* If there's a remainder in the wbuf and it's a non-GC write,
+ remember that the wbuf affects this ino */
+alldone:
*retlen = donelen;
- /* Setup timed wbuf flush, if buffer len != 0 */
- if (c->wbuf_len) {
- D1(printk (KERN_DEBUG "jffs2_flash_writev: mod wbuf_timer\n"));
- mod_timer(&c->wbuf_timer, jiffies + WBUF_FLUSH_TIMEOUT);
- }
+
+ if (c->wbuf_len && ino)
+ jffs2_wbuf_dirties_inode(c, ino);
+
return 0;
}
@@ -456,7 +762,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
vecs[0].iov_base = (unsigned char *) buf;
vecs[0].iov_len = len;
- return jffs2_flash_writev(c, vecs, 1, ofs, retlen);
+ return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
}
/*
@@ -469,7 +775,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
/* Read flash */
if (!jffs2_can_mark_obsolete(c)) {
- ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, &jffs2_oobinfo);
+ ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
if ( (ret == -EIO) && (*retlen == len) ) {
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
@@ -525,22 +831,12 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
{
unsigned char *buf;
int ret = 0;
- int i,len,cnt,page;
+ int i,len,page;
size_t retlen;
- int fsdata_pos,badblock_pos,oob_size;
+ int oob_size;
oob_size = c->mtd->oobsize;
- switch(c->mtd->ecctype) {
- case MTD_ECC_SW:
- fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
- badblock_pos = NAND_BADBLOCK_POS;
- break;
- default:
- D1(printk(KERN_WARNING "jffs2_write_oob_empty(): Invalid ECC type\n"));
- return -EINVAL;
- }
-
/* allocate a buffer for all oob data in this sector */
len = 4 * oob_size;
buf = kmalloc(len, GFP_KERNEL);
@@ -568,19 +864,22 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
/* Special check for first two pages */
for (page = 0; page < 2 * oob_size; page += oob_size) {
/* Check for bad block marker */
- if (buf[page+badblock_pos] != 0xff) {
+ if (buf[page+c->badblock_pos] != 0xff) {
D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
/* Return 2 for bad and 3 for failed block
bad goes to list_bad and failed to list_erase */
ret = (!page) ? 2 : 3;
goto out;
}
- cnt = oob_size;
- if (mode)
- cnt -= fsdata_pos;
- for(i = 0; i < cnt ; i+=sizeof(unsigned short)) {
- unsigned short dat = *(unsigned short *)(&buf[page+i]);
- if(dat != 0xffff) {
+ for(i = 0; i < oob_size ; i++) {
+ /* Yeah, we know about the cleanmarker. */
+ if (mode && i >= c->fsdata_pos &&
+ i < c->fsdata_pos+c->fsdata_len)
+ continue;
+
+ if (buf[page+i] != 0xFF) {
+ D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
+ buf[page+i], page+i, jeb->offset));
ret = 1;
goto out;
}
@@ -617,23 +916,11 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
unsigned char *p;
int ret, i, cnt, retval = 0;
size_t retlen, offset;
- int fsdata_pos, fsdata_len, oob_size, badblock_pos;
+ int oob_size;
offset = jeb->offset;
oob_size = c->mtd->oobsize;
- switch (c->mtd->ecctype) {
- case MTD_ECC_SW:
- fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
- fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
- badblock_pos = NAND_BADBLOCK_POS;
- break;
- default:
- D1 (printk (KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
- return -EINVAL;
- }
-
-
/* Loop through the physical blocks */
for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
/*
@@ -653,14 +940,15 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
/* Check for bad block marker */
- if (buf[badblock_pos] != 0xff) {
- D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+ if (buf[c->badblock_pos] != 0xff) {
+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n",
+ jeb->offset, buf[c->badblock_pos], buf[c->badblock_pos + oob_size], c->badblock_pos));
return 2;
}
/* Check for failure counter in the second page */
- if (buf[badblock_pos + oob_size] != 0xff) {
- D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[badblock_pos + oob_size]));
+ if (buf[c->badblock_pos + oob_size] != 0xff) {
+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size]));
return 3;
}
@@ -671,12 +959,19 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
n.totlen = cpu_to_je32 (8);
p = (unsigned char *) &n;
- for (i = 0; i < fsdata_len; i++) {
- if (buf[fsdata_pos + i] != p[i]) {
- D2 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset));
+ for (i = 0; i < c->fsdata_len; i++) {
+ if (buf[c->fsdata_pos + i] != p[i]) {
retval = 1;
}
}
+ D1(if (retval == 1) {
+ printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
+ printk(KERN_WARNING "OOB at %08x was ", offset);
+ for (i=0; i < oob_size; i++) {
+ printk("%02x ", buf[i]);
+ }
+ printk("\n");
+ })
}
offset += c->mtd->erasesize;
}
@@ -687,31 +982,20 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
{
struct jffs2_unknown_node n;
int ret;
- int fsdata_pos,fsdata_len;
size_t retlen;
- switch(c->mtd->ecctype) {
- case MTD_ECC_SW:
- fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
- fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
- break;
- default:
- D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
- return -EINVAL;
- }
-
n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
n.totlen = cpu_to_je32(8);
- ret = jffs2_flash_write_oob(c, jeb->offset + fsdata_pos, fsdata_len, &retlen, (unsigned char *)&n);
+ ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
if (ret) {
D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
return ret;
}
- if (retlen != fsdata_len) {
- D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, fsdata_len));
+ if (retlen != c->fsdata_len) {
+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len));
return ret;
}
return 0;
@@ -725,18 +1009,9 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
unsigned char buf[16];
int ret;
size_t retlen;
- int oob_size, badblock_pos;
+ int oob_size;
oob_size = c->mtd->oobsize;
-
- switch(c->mtd->ecctype) {
- case MTD_ECC_SW:
- badblock_pos = NAND_BADBLOCK_POS;
- break;
- default:
- D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Invalid ECC type\n"));
- return -EINVAL;
- }
ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf);
@@ -750,7 +1025,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
return -EIO;
}
- jeb->bad_count = buf[badblock_pos];
+ jeb->bad_count = buf[c->badblock_pos];
return 0;
}
@@ -767,25 +1042,16 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
unsigned char buf = 0x0;
- int ret,pos;
+ int ret;
size_t retlen;
- switch(c->mtd->ecctype) {
- case MTD_ECC_SW:
- pos = NAND_BADBLOCK_POS;
- break;
- default:
- D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Invalid ECC type\n"));
- return -EINVAL;
- }
-
/* if the count is < max, we try to write the counter to the 2nd page oob area */
if( ++jeb->bad_count < MAX_ERASE_FAILURES) {
buf = (unsigned char)jeb->bad_count;
- pos += c->mtd->oobblock;
+ c->badblock_pos += c->mtd->oobblock;
}
- ret = jffs2_flash_write_oob(c, jeb->offset + pos, 1, &retlen, &buf);
+ ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf);
if (ret) {
D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
@@ -797,3 +1063,88 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
}
return 0;
}
+
+#define JFFS2_OOB_ECCPOS0 0
+#define JFFS2_OOB_ECCPOS1 1
+#define JFFS2_OOB_ECCPOS2 2
+#define JFFS2_OOB_ECCPOS3 3
+#define JFFS2_OOB_ECCPOS4 6
+#define JFFS2_OOB_ECCPOS5 7
+
+#define NAND_JFFS2_OOB8_FSDAPOS 6
+#define NAND_JFFS2_OOB16_FSDAPOS 8
+#define NAND_JFFS2_OOB8_FSDALEN 2
+#define NAND_JFFS2_OOB16_FSDALEN 8
+
+static struct nand_oobinfo jffs2_oobinfo_swecc = {
+ .useecc = 1,
+ .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2,
+ JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
+};
+
+static struct nand_oobinfo jffs2_oobinfo_docecc = {
+ .useecc = 1,
+ .eccpos = {0,1,2,3,4,5}
+};
+
+
+
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+{
+ /* Cleanmarker is out-of-band, so inline size zero */
+ c->cleanmarker_size = 0;
+
+ /* Initialise write buffer */
+ c->wbuf_pagesize = c->mtd->oobblock;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+ /* FIXME: If we had a generic way of describing the hardware's
+ use of OOB area, we could perhaps make this generic too. */
+ switch(c->mtd->ecctype) {
+ case MTD_ECC_SW:
+ D1(printk(KERN_DEBUG "JFFS2 using software ECC\n"));
+ c->oobinfo = &jffs2_oobinfo_swecc;
+ if (c->mtd->oobsize == 8) {
+ c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS;
+ c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN;
+ } else {
+ c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS;
+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+ }
+ c->badblock_pos = NAND_BADBLOCK_POS;
+ break;
+
+ case MTD_ECC_RS_DiskOnChip:
+ D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n"));
+ c->oobinfo = &jffs2_oobinfo_docecc;
+ c->fsdata_pos = 6;
+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+ c->badblock_pos = 15;
+ break;
+
+ default:
+ printk("JFFS2 doesn't yet know how to handle ECC type %d\n",
+ c->mtd->ecctype);
+ return -EINVAL;
+ }
+
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+#ifdef BREAKME
+ if (!brokenbuf)
+ brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!brokenbuf) {
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+ memset(brokenbuf, 0xdb, c->wbuf_pagesize);
+#endif
+ return 0;
+}
+
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
+{
+ kfree(c->wbuf);
+}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index cc50ffbaea3d..f28d9d5bcd36 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -1,13 +1,13 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: write.c,v 1.65 2003/01/21 18:11:29 dwmw2 Exp $
+ * $Id: write.c,v 1.75 2003/10/08 11:45:11 dwmw2 Exp $
*
*/
@@ -86,7 +86,7 @@ static void writecheck(struct jffs2_sb_info *c, uint32_t ofs)
/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
write it to the flash, link it into the existing inode/fragment list */
-struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, uint32_t *writelen)
+struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode)
{
struct jffs2_raw_node_ref *raw;
@@ -94,6 +94,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
size_t retlen;
struct iovec vecs[2];
int ret;
+ int retried = 0;
unsigned long cnt = 2;
D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
@@ -120,24 +121,28 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
jffs2_free_raw_node_ref(raw);
return ERR_PTR(-ENOMEM);
}
- raw->flash_offset = flash_ofs;
- raw->totlen = PAD(sizeof(*ri)+datalen);
- raw->next_phys = NULL;
fn->ofs = je32_to_cpu(ri->offset);
fn->size = je32_to_cpu(ri->dsize);
fn->frags = 0;
- fn->raw = raw;
/* check number of valid vecs */
if (!datalen || !data)
cnt = 1;
+ retry:
+ fn->raw = raw;
+
+ raw->flash_offset = flash_ofs;
+ raw->totlen = PAD(sizeof(*ri)+datalen);
+ raw->next_phys = NULL;
+
+ ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
+ (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
- ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen);
-
if (ret || (retlen != sizeof(*ri) + datalen)) {
printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
sizeof(*ri)+datalen, flash_ofs, ret, retlen);
+
/* Mark the space as dirtied */
if (retlen) {
/* Doesn't belong to any inode */
@@ -155,11 +160,42 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
jffs2_free_raw_node_ref(raw);
}
+ if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) {
+ /* Try to reallocate space and retry */
+ uint32_t dummy;
+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
+ retried = 1;
+
+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ if (alloc_mode == ALLOC_GC) {
+ ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
+ } else {
+ /* Locking pain */
+ up(&f->sem);
+ jffs2_complete_reservation(c);
+
+ ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
+ down(&f->sem);
+ }
+
+ if (!ret) {
+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ goto retry;
+ }
+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+ jffs2_free_raw_node_ref(raw);
+ }
/* Release the full_dnode which is now useless, and return */
jffs2_free_full_dnode(fn);
- if (writelen)
- *writelen = retlen;
return ERR_PTR(ret?ret:-EIO);
}
/* Mark the space used */
@@ -184,19 +220,21 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize),
je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
- if (writelen)
- *writelen = retlen;
- f->inocache->nodes = raw;
+ if (retried) {
+ ACCT_SANITY_CHECK(c,NULL);
+ }
+
return fn;
}
-struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, uint32_t *writelen)
+struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode)
{
struct jffs2_raw_node_ref *raw;
struct jffs2_full_dirent *fd;
size_t retlen;
struct iovec vecs[2];
+ int retried = 0;
int ret;
D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
@@ -225,11 +263,6 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
jffs2_free_raw_node_ref(raw);
return ERR_PTR(-ENOMEM);
}
- raw->flash_offset = flash_ofs;
- raw->totlen = PAD(sizeof(*rd)+namelen);
- raw->next_in_ino = f->inocache->nodes;
- f->inocache->nodes = raw;
- raw->next_phys = NULL;
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
@@ -237,14 +270,22 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
fd->type = rd->type;
memcpy(fd->name, name, namelen);
fd->name[namelen]=0;
+
+ retry:
fd->raw = raw;
- ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen);
+ raw->flash_offset = flash_ofs;
+ raw->totlen = PAD(sizeof(*rd)+namelen);
+ raw->next_phys = NULL;
+
+ ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
+ (alloc_mode==ALLOC_GC)?0:fd->ino);
if (ret || (retlen != sizeof(*rd) + namelen)) {
printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
sizeof(*rd)+namelen, flash_ofs, ret, retlen);
/* Mark the space as dirtied */
if (retlen) {
+ raw->next_in_ino = NULL;
raw->flash_offset |= REF_OBSOLETE;
jffs2_add_physical_node_ref(c, raw);
jffs2_mark_node_obsolete(c, raw);
@@ -252,20 +293,53 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
jffs2_free_raw_node_ref(raw);
}
+ if (!retried && (raw = jffs2_alloc_raw_node_ref())) {
+ /* Try to reallocate space and retry */
+ uint32_t dummy;
+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
+
+ retried = 1;
+ D1(printk(KERN_DEBUG "Retrying failed write.\n"));
+
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+
+ if (alloc_mode == ALLOC_GC) {
+ ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
+ } else {
+ /* Locking pain */
+ up(&f->sem);
+ jffs2_complete_reservation(c);
+
+ ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
+ down(&f->sem);
+ }
+
+ if (!ret) {
+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
+ ACCT_SANITY_CHECK(c,jeb);
+ D1(ACCT_PARANOIA_CHECK(jeb));
+ goto retry;
+ }
+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
+ jffs2_free_raw_node_ref(raw);
+ }
/* Release the full_dnode which is now useless, and return */
jffs2_free_full_dirent(fd);
- if (writelen)
- *writelen = retlen;
return ERR_PTR(ret?ret:-EIO);
}
/* Mark the space used */
raw->flash_offset |= REF_PRISTINE;
jffs2_add_physical_node_ref(c, raw);
- if (writelen)
- *writelen = retlen;
+ raw->next_in_ino = f->inocache->nodes;
f->inocache->nodes = raw;
+
+ if (retried) {
+ ACCT_SANITY_CHECK(c,NULL);
+ }
+
return fd;
}
@@ -288,7 +362,9 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned char comprtype = JFFS2_COMPR_NONE;
uint32_t phys_ofs, alloclen;
uint32_t datalen, cdatalen;
+ int retried = 0;
+ retry:
D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
@@ -331,7 +407,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
- fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, NULL);
+ fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
if (comprtype != JFFS2_COMPR_NONE)
kfree(comprbuf);
@@ -340,6 +416,12 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
ret = PTR_ERR(fn);
up(&f->sem);
jffs2_complete_reservation(c);
+ if (!retried) {
+ /* Write error to be retried */
+ retried = 1;
+ D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
+ goto retry;
+ }
break;
}
ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -381,7 +463,6 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
struct jffs2_full_dnode *fn;
struct jffs2_full_dirent *fd;
uint32_t alloclen, phys_ofs;
- uint32_t writtenlen;
int ret;
/* Try to reserve enough space for both node and dirent.
@@ -397,7 +478,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
jemode_to_cpu(ri->mode)));
@@ -414,22 +495,14 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
*/
f->metadata = fn;
- /* Work out where to put the dirent node now. */
- writtenlen = PAD(writtenlen);
- phys_ofs += writtenlen;
- alloclen -= writtenlen;
up(&f->sem);
-
- if (alloclen < sizeof(*rd)+namelen) {
- /* Not enough space left in this chunk. Get some more */
- jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ jffs2_complete_reservation(c);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
- if (ret) {
- /* Eep. */
- D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
- return ret;
- }
+ if (ret) {
+ /* Eep. */
+ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
+ return ret;
}
rd = jffs2_alloc_raw_dirent();
@@ -455,7 +528,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, &writtenlen);
+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_dirent(rd);
@@ -513,7 +586,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
jffs2_free_raw_dirent(rd);
@@ -598,7 +671,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_dirent(rd);
diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c
index 84a6c13e6ae5..80cd3820373f 100644
--- a/fs/jffs2/writev.c
+++ b/fs/jffs2/writev.c
@@ -3,11 +3,11 @@
*
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: writev.c,v 1.3 2002/08/08 08:35:21 dwmw2 Exp $
+ * $Id: writev.c,v 1.4 2003/10/04 08:33:07 dwmw2 Exp $
*
*/
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 1eba76a6f603..d26f6590bd05 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -226,6 +226,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
static inline char * task_sig(struct task_struct *p, char *buffer)
{
sigset_t pending, shpending, blocked, ignored, caught;
+ int num_threads = 0;
sigemptyset(&pending);
sigemptyset(&shpending);
@@ -241,10 +242,13 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
shpending = p->signal->shared_pending.signal;
blocked = p->blocked;
collect_sigign_sigcatch(p, &ignored, &caught);
+ num_threads = atomic_read(&p->signal->count);
spin_unlock_irq(&p->sighand->siglock);
}
read_unlock(&tasklist_lock);
+ buffer += sprintf(buffer, "Threads:\t%d\n", num_threads);
+
/* render them all */
buffer = render_sigset_t("SigPnd:\t", &pending, buffer);
buffer = render_sigset_t("ShdPnd:\t", &shpending, buffer);
@@ -296,6 +300,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
char state;
int res;
pid_t ppid;
+ int num_threads = 0;
struct mm_struct *mm;
state = *get_task_state(task);
@@ -324,6 +329,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
read_lock(&tasklist_lock);
if (task->sighand) {
spin_lock_irq(&task->sighand->siglock);
+ num_threads = atomic_read(&task->signal->count);
collect_sigign_sigcatch(task, &sigign, &sigcatch);
spin_unlock_irq(&task->sighand->siglock);
}
@@ -338,7 +344,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
ppid = task->pid ? task->real_parent->pid : 0;
read_unlock(&tasklist_lock);
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \
+%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
task->pid,
task->comm,
@@ -359,7 +365,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
jiffies_to_clock_t(task->cstime),
priority,
nice,
- 0UL /* removed */,
+ num_threads,
jiffies_to_clock_t(task->it_real_value),
(unsigned long long)
jiffies_64_to_clock_t(task->start_time - INITIAL_JIFFIES),
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 90074d247eb6..377d12003f21 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -478,14 +478,15 @@ static void *r_start(struct seq_file *m, loff_t *pos)
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
+ if (v)
+ deactivate_super(v);
return NULL;
}
static void r_stop(struct seq_file *m, void *v)
{
- struct proc_dir_entry *de = m->private;
- struct super_block *s = de->data;
- deactivate_super(s);
+ if (v)
+ deactivate_super(v);
}
static int r_show(struct seq_file *m, void *v)
diff --git a/include/asm-h8300/semaphore.h b/include/asm-h8300/semaphore.h
index 62e6e9ce669e..283f0860a2af 100644
--- a/include/asm-h8300/semaphore.h
+++ b/include/asm-h8300/semaphore.h
@@ -101,13 +101,14 @@ static inline void down(struct semaphore * sem)
"mov.l er1,%0\n\t"
"bpl 1f\n\t"
"ldc r3l,ccr\n\t"
+ "mov.l %1,er0\n\t"
"jsr @___down\n\t"
"bra 2f\n"
"1:\n\t"
"ldc r3l,ccr\n"
"2:"
: "+m"(*count)
- :
+ : "g"(sem)
: "cc", "er1", "er2", "er3");
}
@@ -129,6 +130,7 @@ static inline int down_interruptible(struct semaphore * sem)
"mov.l er2,%1\n\t"
"bpl 1f\n\t"
"ldc r1l,ccr\n\t"
+ "mov.l %2,er0\n\t"
"jsr @___down_interruptible\n\t"
"bra 2f\n"
"1:\n\t"
@@ -136,7 +138,7 @@ static inline int down_interruptible(struct semaphore * sem)
"sub.l %0,%0\n\t"
"2:\n\t"
: "=r" (count),"+m" (*count)
- :
+ : "g"(sem)
: "cc", "er1", "er2", "er3");
return (int)count;
}
@@ -161,6 +163,7 @@ static inline int down_trylock(struct semaphore * sem)
"jmp @3f\n\t"
LOCK_SECTION_START(".align 2\n\t")
"3:\n\t"
+ "mov.l %2,er0\n\t"
"jsr @___down_trylock\n\t"
"jmp @2f\n\t"
LOCK_SECTION_END
@@ -169,7 +172,7 @@ static inline int down_trylock(struct semaphore * sem)
"sub.l %1,%1\n"
"2:"
: "+m" (*count),"=r"(count)
- :
+ : "g"(sem)
: "cc", "er1","er2", "er3");
return (int)count;
}
@@ -199,10 +202,11 @@ static inline void up(struct semaphore * sem)
"sub.l er2,er2\n\t"
"cmp.l er2,er1\n\t"
"bgt 1f\n\t"
+ "mov.l %1,er0\n\t"
"jsr @___up\n"
"1:"
: "+m"(*count)
- :
+ : "g"(sem)
: "cc", "er1", "er2", "er3");
}
diff --git a/include/asm-i386/div64.h b/include/asm-i386/div64.h
index e99f044af73b..28ed8b296afc 100644
--- a/include/asm-i386/div64.h
+++ b/include/asm-i386/div64.h
@@ -14,14 +14,15 @@
* convention" on x86.
*/
#define do_div(n,base) ({ \
- unsigned long __upper, __low, __high, __mod; \
+ unsigned long __upper, __low, __high, __mod, __base; \
+ __base = (base); \
asm("":"=a" (__low), "=d" (__high):"A" (n)); \
__upper = __high; \
if (__high) { \
- __upper = __high % (base); \
- __high = __high / (base); \
+ __upper = __high % (__base); \
+ __high = __high / (__base); \
} \
- asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (base), "0" (__low), "1" (__upper)); \
+ asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
asm("":"=A" (n):"a" (__low),"d" (__high)); \
__mod; \
})
diff --git a/include/asm-i386/mach-numaq/mach_mpparse.h b/include/asm-i386/mach-numaq/mach_mpparse.h
index 41c7d08d973d..51bbac8fc0c2 100644
--- a/include/asm-i386/mach-numaq/mach_mpparse.h
+++ b/include/asm-i386/mach-numaq/mach_mpparse.h
@@ -1,9 +1,6 @@
#ifndef __ASM_MACH_MPPARSE_H
#define __ASM_MACH_MPPARSE_H
-static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
- unsigned short oemsize);
-
static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
struct mpc_config_translation *translation)
{
@@ -24,16 +21,6 @@ static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
quad_local_to_mp_bus_id[quad][local] = m->mpc_busid;
}
-static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
- char *productid)
-{
- if (strncmp(oem, "IBM NUMA", 8))
- printk("Warning! May not be a NUMA-Q system!\n");
- if (mpc->mpc_oemptr)
- smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr,
- mpc->mpc_oemsize);
-}
-
/* Hook from generic ACPI tables.c */
static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index bca7f54ccf43..b9998ad13267 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -498,7 +498,7 @@ unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019])
#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1022])
-struct microcode {
+struct microcode_header {
unsigned int hdrver;
unsigned int rev;
unsigned int date;
@@ -506,10 +506,32 @@ struct microcode {
unsigned int cksum;
unsigned int ldrver;
unsigned int pf;
- unsigned int reserved[5];
- unsigned int bits[500];
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode {
+ struct microcode_header hdr;
+ unsigned int bits[0];
+};
+
+typedef struct microcode microcode_t;
+typedef struct microcode_header microcode_header_t;
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
};
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
/* '6' because it used to be for P6 only (but now covers Pentium 4 as well) */
#define MICROCODE_IOCFREE _IO('6',0)
diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h
index 198c4c202c42..9618467c930a 100644
--- a/include/asm-ia64/asmmacro.h
+++ b/include/asm-ia64/asmmacro.h
@@ -68,20 +68,25 @@ name:
* we'll patch out the work-around bundles with NOPs, so their impact is minimal.
*/
#define DO_MCKINLEY_E9_WORKAROUND
+
#ifdef DO_MCKINLEY_E9_WORKAROUND
.section ".data.patch.mckinley_e9", "a"
.previous
/* workaround for Itanium 2 Errata 9: */
-# define MCKINLEY_E9_WORKAROUND \
- .xdata4 ".data.patch.mckinley_e9", 1f-.;\
-1:{ .mib; \
- nop.m 0; \
- nop.i 0; \
- br.call.sptk.many b7=1f;; \
- }; \
-1:
+# define FSYS_RETURN \
+ .xdata4 ".data.patch.mckinley_e9", 1f-.; \
+1:{ .mib; \
+ nop.m 0; \
+ mov r16=ar.pfs; \
+ br.call.sptk.many b7=2f;; \
+ }; \
+2:{ .mib; \
+ nop.m 0; \
+ mov ar.pfs=r16; \
+ br.ret.sptk.many b6;; \
+ }
#else
-# define MCKINLEY_E9_WORKAROUND
+# define FSYS_RETURN br.ret.sptk.many b6
#endif
#endif /* _ASM_IA64_ASMMACRO_H */
diff --git a/include/asm-ia64/delay.h b/include/asm-ia64/delay.h
index 74c542acc1e8..1b9df23a5641 100644
--- a/include/asm-ia64/delay.h
+++ b/include/asm-ia64/delay.h
@@ -67,14 +67,15 @@ ia64_get_itc (void)
return result;
}
+extern void ia64_delay_loop (unsigned long loops);
+
static __inline__ void
__delay (unsigned long loops)
{
- if (loops < 1)
+ if (unlikely(loops < 1))
return;
- while (loops--)
- ia64_nop(0);
+ ia64_delay_loop (loops - 1);
}
static __inline__ void
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index 9146e1cff4e6..37c868205751 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -99,4 +99,6 @@ extern ia64_mv_dma_supported sn_dma_supported;
#define platform_dma_sync_sg sn_dma_sync_sg
#define platform_dma_supported sn_dma_supported
+#include <asm/sn/sn2/io.h>
+
#endif /* _ASM_IA64_MACHVEC_SN2_H */
diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
index da678bd6358f..6791e7358a03 100644
--- a/include/asm-ia64/mca.h
+++ b/include/asm-ia64/mca.h
@@ -108,8 +108,6 @@ enum {
IA64_MCA_NEW_CONTEXT = -1 /* SAL to return to new context */
};
-#define MIN_STATE_AREA_SIZE 57
-
typedef struct ia64_mca_os_to_sal_state_s {
u64 imots_os_status; /* OS status to SAL as to what happened
* with the MCA handling.
diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h
index bcca098828ed..2aa8437dcf75 100644
--- a/include/asm-ia64/mca_asm.h
+++ b/include/asm-ia64/mca_asm.h
@@ -110,10 +110,9 @@
;; \
dep temp1 = -1, temp1, PSR_MC, 1; \
;; \
- movl temp2 = start_addr; \
mov cr.ipsr = temp1; \
;; \
- INST_VA_TO_PA(temp2); \
+ LOAD_PHYSICAL(p0, temp2, start_addr); \
;; \
mov cr.iip = temp2; \
mov cr.ifs = r0; \
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index 074219720d61..1590dc65b30b 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -7,6 +7,8 @@
* for more details.
*/
+#include <linux/config.h>
+
/*
* Entries defined so far:
* - boot param structure itself
@@ -32,10 +34,27 @@ extern void reserve_memory (void);
extern void find_initrd (void);
extern int filter_rsvd_memory (unsigned long start, unsigned long end, void *arg);
+/*
+ * For rounding an address to the next IA64_GRANULE_SIZE or order
+ */
+#define GRANULEROUNDDOWN(n) ((n) & ~(IA64_GRANULE_SIZE-1))
+#define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
+#define ORDERROUNDDOWN(n) ((n) & ~((PAGE_SIZE<<MAX_ORDER)-1))
+
#ifdef CONFIG_DISCONTIGMEM
-extern void call_pernode_memory (unsigned long start, unsigned long end, void *arg);
+ extern void call_pernode_memory (unsigned long start, unsigned long len, void *func);
+#else
+# define call_pernode_memory(start, len, func) (*func)(start, len, 0)
#endif
#define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */
+ extern unsigned long vmalloc_end;
+ extern struct page *vmem_map;
+ extern int find_largest_hole (u64 start, u64 end, void *arg);
+ extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
+#endif
+
#endif /* meminit_h */
diff --git a/include/asm-ia64/mmzone.h b/include/asm-ia64/mmzone.h
index 9e060cd61ca4..e811b18c31d7 100644
--- a/include/asm-ia64/mmzone.h
+++ b/include/asm-ia64/mmzone.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 2000 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 2000,2003 Silicon Graphics, Inc. All rights reserved.
* Copyright (c) 2002 NEC Corp.
* Copyright (c) 2002 Erich Focht <efocht@ess.nec.de>
* Copyright (c) 2002 Kimio Suganuma <k-suganuma@da.jp.nec.com>
@@ -12,148 +12,26 @@
#define _ASM_IA64_MMZONE_H
#include <linux/config.h>
-#include <linux/init.h>
-
-/*
- * Given a kaddr, find the base mem_map address for the start of the mem_map
- * entries for the bank containing the kaddr.
- */
-#define BANK_MEM_MAP_BASE(kaddr) local_node_data->bank_mem_map_base[BANK_MEM_MAP_INDEX(kaddr)]
-
-/*
- * Given a kaddr, this macro return the relative map number
- * within the bank.
- */
-#define BANK_MAP_NR(kaddr) (BANK_OFFSET(kaddr) >> PAGE_SHIFT)
-
-/*
- * Given a pte, this macro returns a pointer to the page struct for the pte.
- */
-#define pte_page(pte) virt_to_page(PAGE_OFFSET | (pte_val(pte)&_PFN_MASK))
-
-/*
- * Determine if a kaddr is a valid memory address of memory that
- * actually exists.
- *
- * The check consists of 2 parts:
- * - verify that the address is a region 7 address & does not
- * contain any bits that preclude it from being a valid platform
- * memory address
- * - verify that the chunk actually exists.
- *
- * Note that IO addresses are NOT considered valid addresses.
- *
- * Note, many platforms can simply check if kaddr exceeds a specific size.
- * (However, this won't work on SGI platforms since IO space is embedded
- * within the range of valid memory addresses & nodes have holes in the
- * address range between banks).
- */
-#define kern_addr_valid(kaddr) ({long _kav=(long)(kaddr); \
- VALID_MEM_KADDR(_kav);})
-
-/*
- * Given a kaddr, return a pointer to the page struct for the page.
- * If the kaddr does not represent RAM memory that potentially exists, return
- * a pointer the page struct for max_mapnr. IO addresses will
- * return the page for max_nr. Addresses in unpopulated RAM banks may
- * return undefined results OR may panic the system.
- *
- */
-#define virt_to_page(kaddr) ({long _kvtp=(long)(kaddr); \
- (VALID_MEM_KADDR(_kvtp)) \
- ? BANK_MEM_MAP_BASE(_kvtp) + BANK_MAP_NR(_kvtp) \
- : NULL;})
-
-/*
- * Given a page struct entry, return the physical address that the page struct represents.
- * Since IA64 has all memory in the DMA zone, the following works:
- */
-#define page_to_phys(page) __pa(page_address(page))
-
-#define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map)
-
-#define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn)
-
-#define pfn_to_page(pfn) (struct page *)(node_mem_map(pfn_to_nid(pfn)) + node_localnr(pfn, pfn_to_nid(pfn)))
-
-#define pfn_to_nid(pfn) local_node_data->node_id_map[(pfn << PAGE_SHIFT) >> BANKSHIFT]
-
-#define page_to_pfn(page) (long)((page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn)
-
-
-/*
- * pfn_valid should be made as fast as possible, and the current definition
- * is valid for machines that are NUMA, but still contiguous, which is what
- * is currently supported. A more generalised, but slower definition would
- * be something like this - mbligh:
- * ( pfn_to_pgdat(pfn) && (pfn < node_end_pfn(pfn_to_nid(pfn))) )
- */
-#define pfn_valid(pfn) (pfn < max_low_pfn)
-extern unsigned long max_low_pfn;
-
-
-#if defined(CONFIG_IA64_DIG)
-
-/*
- * Platform definitions for DIG platform with contiguous memory.
- */
-#define MAX_PHYSNODE_ID 8 /* Maximum node number +1 */
-#define MAX_PHYS_MEMORY (1UL << 40) /* 1 TB */
-
-/*
- * Bank definitions.
- * Configurable settings for DIG: 512MB/bank: 16GB/node,
- * 2048MB/bank: 64GB/node,
- * 8192MB/bank: 256GB/node.
- */
-#define NR_BANKS_PER_NODE 32
-#if defined(CONFIG_IA64_NODESIZE_16GB)
-# define BANKSHIFT 29
-#elif defined(CONFIG_IA64_NODESIZE_64GB)
-# define BANKSHIFT 31
-#elif defined(CONFIG_IA64_NODESIZE_256GB)
-# define BANKSHIFT 33
-#else
-# error Unsupported bank and nodesize!
+#include <asm/page.h>
+#include <asm/meminit.h>
+
+#ifdef CONFIG_DISCONTIGMEM
+
+#ifdef CONFIG_IA64_DIG /* DIG systems are small */
+# define MAX_PHYSNODE_ID 8
+# define NR_NODES 8
+# define NR_MEMBLKS (NR_NODES * 32)
+#else /* sn2 is the biggest case, so we use that if !DIG */
+# define MAX_PHYSNODE_ID 2048
+# define NR_NODES 256
+# define NR_MEMBLKS (NR_NODES)
#endif
-#define BANKSIZE (1UL << BANKSHIFT)
-#elif defined(CONFIG_IA64_SGI_SN2)
-
-/*
- * SGI SN2 discontig definitions
- */
-#define MAX_PHYSNODE_ID 2048 /* 2048 node ids (also called nasid) */
-#define MAX_PHYS_MEMORY (1UL << 49)
-
-#define NR_BANKS_PER_NODE 4
-#define BANKSHIFT 38
-#define SN2_NODE_SIZE (64UL*1024*1024*1024) /* 64GB per node */
-#define BANKSIZE (SN2_NODE_SIZE/NR_BANKS_PER_NODE)
-
-#endif /* CONFIG_IA64_DIG */
-
-#if defined(CONFIG_IA64_DIG) || defined (CONFIG_IA64_SGI_SN2)
-/* Common defines for both platforms */
-#include <asm/numnodes.h>
-#define BANK_OFFSET(addr) ((unsigned long)(addr) & (BANKSIZE-1))
-#define NR_BANKS (NR_BANKS_PER_NODE * (1 << NODES_SHIFT))
-#define NR_MEMBLKS (NR_BANKS)
-
-/*
- * VALID_MEM_KADDR returns a boolean to indicate if a kaddr is
- * potentially a valid cacheable identity mapped RAM memory address.
- * Note that the RAM may or may not actually be present!!
- */
-#define VALID_MEM_KADDR(kaddr) 1
-
-/*
- * Given a nodeid & a bank number, find the address of the mem_map
- * entry for the first page of the bank.
- */
-#define BANK_MEM_MAP_INDEX(kaddr) \
- (((unsigned long)(kaddr) & (MAX_PHYS_MEMORY-1)) >> BANKSHIFT)
+extern unsigned long max_low_pfn;
-#endif /* CONFIG_IA64_DIG || CONFIG_IA64_SGI_SN2 */
+#define pfn_valid(pfn) (((pfn) < max_low_pfn) && ia64_pfn_valid(pfn))
+#define page_to_pfn(page) ((unsigned long) (page - vmem_map))
+#define pfn_to_page(pfn) (vmem_map + (pfn))
+#endif /* CONFIG_DISCONTIGMEM */
#endif /* _ASM_IA64_MMZONE_H */
diff --git a/include/asm-ia64/nodedata.h b/include/asm-ia64/nodedata.h
index eae5235fa8be..90908767b4f2 100644
--- a/include/asm-ia64/nodedata.h
+++ b/include/asm-ia64/nodedata.h
@@ -11,9 +11,14 @@
#ifndef _ASM_IA64_NODEDATA_H
#define _ASM_IA64_NODEDATA_H
+#include <linux/config.h>
#include <linux/numa.h>
+
+#include <asm/percpu.h>
#include <asm/mmzone.h>
+#ifdef CONFIG_DISCONTIGMEM
+
/*
* Node Data. One of these structures is located on each node of a NUMA system.
*/
@@ -22,10 +27,7 @@ struct pglist_data;
struct ia64_node_data {
short active_cpu_count;
short node;
- struct pglist_data *pg_data_ptrs[MAX_NUMNODES];
- struct page *bank_mem_map_base[NR_BANKS];
- struct ia64_node_data *node_data_ptrs[MAX_NUMNODES];
- short node_id_map[NR_BANKS];
+ struct pglist_data *pg_data_ptrs[NR_NODES];
};
@@ -34,41 +36,17 @@ struct ia64_node_data {
*/
#define local_node_data (local_cpu_data->node_data)
-
-/*
- * Return a pointer to the node_data structure for the specified node.
- */
-#define node_data(node) (local_node_data->node_data_ptrs[node])
-
-/*
- * Get a pointer to the node_id/node_data for the current cpu.
- * (boot time only)
- */
-extern int boot_get_local_nodeid(void);
-extern struct ia64_node_data *get_node_data_ptr(void);
-
/*
* Given a node id, return a pointer to the pg_data_t for the node.
- * The following 2 macros are similar.
*
* NODE_DATA - should be used in all code not related to system
* initialization. It uses pernode data structures to minimize
* offnode memory references. However, these structure are not
* present during boot. This macro can be used once cpu_init
* completes.
- *
- * BOOT_NODE_DATA
- * - should be used during system initialization
- * prior to freeing __initdata. It does not depend on the percpu
- * area being present.
- *
- * NOTE: The names of these macros are misleading but are difficult to change
- * since they are used in generic linux & on other architecures.
*/
#define NODE_DATA(nid) (local_node_data->pg_data_ptrs[nid])
-#define BOOT_NODE_DATA(nid) boot_get_pg_data_ptr((long)(nid))
-struct pglist_data;
-extern struct pglist_data * __init boot_get_pg_data_ptr(long);
+#endif /* CONFIG_DISCONTIGMEM */
#endif /* _ASM_IA64_NODEDATA_H */
diff --git a/include/asm-ia64/numa.h b/include/asm-ia64/numa.h
index 8b0d5edad7ba..f5a735239897 100644
--- a/include/asm-ia64/numa.h
+++ b/include/asm-ia64/numa.h
@@ -4,7 +4,7 @@
* for more details.
*
* This file contains NUMA specific prototypes and definitions.
- *
+ *
* 2002/08/05 Erich Focht <efocht@ess.nec.de>
*
*/
@@ -12,12 +12,17 @@
#define _ASM_IA64_NUMA_H
#include <linux/config.h>
-#include <linux/cpumask.h>
#ifdef CONFIG_NUMA
-#include <linux/numa.h>
#include <linux/cache.h>
+#include <linux/cache.h>
+#include <linux/cpumask.h>
+#include <linux/numa.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+
+#include <asm/mmzone.h>
extern volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned;
extern volatile cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
@@ -61,6 +66,10 @@ extern int paddr_to_nid(unsigned long paddr);
#define local_nodeid (cpu_to_node_map[smp_processor_id()])
+#else /* !CONFIG_NUMA */
+
+#define paddr_to_nid(addr) 0
+
#endif /* CONFIG_NUMA */
#endif /* _ASM_IA64_NUMA_H */
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 56f5c49a4e95..15b81b2984b9 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -94,18 +94,20 @@ do { \
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+extern int ia64_pfn_valid (unsigned long pfn);
+#else
+# define ia64_pfn_valid(pfn) 1
+#endif
+
#ifndef CONFIG_DISCONTIGMEM
-# ifdef CONFIG_VIRTUAL_MEM_MAP
- extern int ia64_pfn_valid (unsigned long pfn);
-# define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
-# else
-# define pfn_valid(pfn) ((pfn) < max_mapnr)
-# endif
-#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
#define page_to_pfn(page) ((unsigned long) (page - mem_map))
#define pfn_to_page(pfn) (mem_map + (pfn))
+#endif /* CONFIG_DISCONTIGMEM */
+
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
-#endif
+#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
typedef union ia64_va {
struct {
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index e3152bc4fb39..eccf580c1d5f 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -405,10 +405,11 @@ typedef struct pal_process_state_info_s {
* generated.
* (Trap Lost )
*/
- op : 3, /* Operation that
- * caused the machine
- * check
+ mi : 1, /* More information available
+ * call PAL_MC_ERROR_INFO
*/
+ pi : 1, /* Precise instruction pointer */
+ pm : 1, /* Precise min-state save area */
dy : 1, /* Processor dynamic
* state valid
@@ -450,11 +451,12 @@ typedef struct pal_process_state_info_s {
* by the processor
*/
- reserved2 : 12,
+ reserved2 : 11,
cc : 1, /* Cache check */
tc : 1, /* TLB check */
bc : 1, /* Bus check */
- uc : 1; /* Unknown check */
+ rc : 1, /* Register file check */
+ uc : 1; /* Uarch check */
} pal_processor_state_info_t;
diff --git a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
index 70f5b7b14468..a44ee78e999f 100644
--- a/include/asm-ia64/percpu.h
+++ b/include/asm-ia64/percpu.h
@@ -46,11 +46,13 @@ DECLARE_PER_CPU(unsigned long, local_per_cpu_offset);
extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size);
extern void setup_per_cpu_areas (void);
+extern void *per_cpu_init(void);
#else /* ! SMP */
#define per_cpu(var, cpu) ((void)cpu, per_cpu__##var)
#define __get_cpu_var(var) per_cpu__##var
+#define per_cpu_init() (__phys_per_cpu_start)
#endif /* SMP */
diff --git a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h
index b8e81aa3bffa..ac497dc3fb15 100644
--- a/include/asm-ia64/perfmon.h
+++ b/include/asm-ia64/perfmon.h
@@ -38,7 +38,6 @@
*/
#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */
#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */
-#define PFM_FL_UNSECURE 0x04 /* allow unsecure monitoring for non self-monitoring task */
#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */
/*
@@ -162,8 +161,6 @@ typedef union {
*/
#define PFM_VERSION_MAJ 2U
#define PFM_VERSION_MIN 0U
-#define PFM_SMPL_HDR_VERSION_MAJ 2U
-#define PFM_SMPL_HDR_VERSION_MIN 0U
#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff)
#define PFM_VERSION_MINOR(x) ((x) & 0xffff)
@@ -194,9 +191,8 @@ extern void pfm_handle_work(void);
/*
* Reset PMD register flags
*/
-#define PFM_PMD_NO_RESET 0
+#define PFM_PMD_SHORT_RESET 0
#define PFM_PMD_LONG_RESET 1
-#define PFM_PMD_SHORT_RESET 2
typedef union {
unsigned int val;
@@ -223,7 +219,7 @@ typedef struct {
} pfm_ovfl_arg_t;
-typedef struct _pfm_buffer_fmt_t {
+typedef struct {
char *fmt_name;
pfm_uuid_t fmt_uuid;
size_t fmt_arg_size;
@@ -237,8 +233,7 @@ typedef struct _pfm_buffer_fmt_t {
int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs);
- struct _pfm_buffer_fmt_t *fmt_next;
- struct _pfm_buffer_fmt_t *fmt_prev;
+ struct list_head fmt_list;
} pfm_buffer_fmt_t;
extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt);
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 9f1f917e9b13..a538701ac028 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -174,7 +174,6 @@ ia64_phys_addr_valid (unsigned long addr)
return (addr & (local_cpu_data->unimpl_pa_mask)) == 0;
}
-#ifndef CONFIG_DISCONTIGMEM
/*
* kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
* memory. For the return value to be meaningful, ADDR must be >=
@@ -190,7 +189,6 @@ ia64_phys_addr_valid (unsigned long addr)
*/
#define kern_addr_valid(addr) (1)
-#endif
/*
* Now come the defines and routines to manage and access the three-level
@@ -240,10 +238,8 @@ ia64_phys_addr_valid (unsigned long addr)
#define pte_none(pte) (!pte_val(pte))
#define pte_present(pte) (pte_val(pte) & (_PAGE_P | _PAGE_PROTNONE))
#define pte_clear(pte) (pte_val(*(pte)) = 0UL)
-#ifndef CONFIG_DISCONTIGMEM
/* pte_page() returns the "struct page *" corresponding to the PTE: */
#define pte_page(pte) virt_to_page(((pte_val(pte) & _PFN_MASK) + PAGE_OFFSET))
-#endif
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (!ia64_phys_addr_valid(pmd_val(pmd)))
diff --git a/include/asm-ia64/posix_types.h b/include/asm-ia64/posix_types.h
index 59a50b0e4e38..a6ebf79d0fe4 100644
--- a/include/asm-ia64/posix_types.h
+++ b/include/asm-ia64/posix_types.h
@@ -10,7 +10,7 @@
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
-typedef unsigned int __kernel_ino_t;
+typedef unsigned long __kernel_ino_t;
typedef unsigned int __kernel_mode_t;
typedef unsigned int __kernel_nlink_t;
typedef long __kernel_off_t;
diff --git a/include/asm-ia64/serial.h b/include/asm-ia64/serial.h
index 71693915f33c..0c7a2f3dcf13 100644
--- a/include/asm-ia64/serial.h
+++ b/include/asm-ia64/serial.h
@@ -4,8 +4,6 @@
* Derived from the i386 version.
*/
-#include <linux/config.h>
-
/*
* This assumes you have a 1.8432 MHz clock for your UART.
*
@@ -15,107 +13,7 @@
*/
#define BASE_BAUD ( 1843200 / 16 )
-#define CONFIG_SERIAL_DETECT_IRQ /* on IA-64, we always want to autodetect irqs */
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE
-#endif
-
/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
+ * All legacy serial ports should be enumerated via ACPI namespace, so
+ * we need not list them here.
*/
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS
-
diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h
index edf269398884..a21a48b0190f 100644
--- a/include/asm-ia64/sn/nodepda.h
+++ b/include/asm-ia64/sn/nodepda.h
@@ -128,7 +128,7 @@ typedef struct irqpda_s irqpda_t;
* Check if given a compact node id the corresponding node has all the
* cpus disabled.
*/
-#define is_headless_node(cnode) (!any_online_cpu(node_to_cpumask(cnode)))
+#define is_headless_node(cnode) (!node_to_cpu_mask[cnode])
/*
* Check if given a node vertex handle the corresponding node has all the
diff --git a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
index 9aa49df40247..5154d4904d69 100644
--- a/include/asm-ia64/uaccess.h
+++ b/include/asm-ia64/uaccess.h
@@ -408,11 +408,7 @@ struct exception_table_entry {
extern void handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
-#ifdef GAS_HAS_LOCAL_TAGS
# define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri)
-#else
-# define SEARCH_EXCEPTION_TABLE(regs) search_exception_tables(regs->cr_iip)
-#endif
static inline int
done_with_exception (struct pt_regs *regs)
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index f65623c70fb1..938dc93c70e7 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -237,17 +237,17 @@
#define __NR_epoll_wait 1245
#define __NR_restart_syscall 1246
#define __NR_semtimedop 1247
-#define __NR_sys_timer_create 1248
-#define __NR_sys_timer_settime 1249
-#define __NR_sys_timer_gettime 1250
-#define __NR_sys_timer_getoverrun 1251
-#define __NR_sys_timer_delete 1252
-#define __NR_sys_clock_settime 1253
-#define __NR_sys_clock_gettime 1254
-#define __NR_sys_clock_getres 1255
-#define __NR_sys_clock_nanosleep 1256
-#define __NR_sys_fstatfs64 1257
-#define __NR_sys_statfs64 1258
+#define __NR_timer_create 1248
+#define __NR_timer_settime 1249
+#define __NR_timer_gettime 1250
+#define __NR_timer_getoverrun 1251
+#define __NR_timer_delete 1252
+#define __NR_clock_settime 1253
+#define __NR_clock_gettime 1254
+#define __NR_clock_getres 1255
+#define __NR_clock_nanosleep 1256
+#define __NR_fstatfs64 1257
+#define __NR_statfs64 1258
#ifdef __KERNEL__
diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h
index 7741753b34d8..20953f3bca1e 100644
--- a/include/asm-ppc/reg.h
+++ b/include/asm-ppc/reg.h
@@ -87,6 +87,10 @@
#define SPRN_CTR 0x009 /* Count Register */
#define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
#define SPRN_DAR 0x013 /* Data Address Register */
+#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */
+#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
+#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
+#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */
#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */
@@ -397,6 +401,10 @@
#define THRM2 SPRN_THRM2 /* Thermal Management Register 2 */
#define THRM3 SPRN_THRM3 /* Thermal Management Register 3 */
#define XER SPRN_XER
+#define TBRL SPRN_TBRL /* Time Base Read Lower Register */
+#define TBRU SPRN_TBRU /* Time Base Read Upper Register */
+#define TBWL SPRN_TBWL /* Time Base Write Lower Register */
+#define TBWU SPRN_TBWU /* Time Base Write Upper Register */
/* Processor Version Register */
diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
index 093d59a25b4d..b008212e584d 100644
--- a/include/asm-ppc/reg_booke.h
+++ b/include/asm-ppc/reg_booke.h
@@ -59,14 +59,10 @@ do { \
#define SPRN_SPRG5R 0x105 /* Special Purpose Register General 5 Read */
#define SPRN_SPRG6R 0x106 /* Special Purpose Register General 6 Read */
#define SPRN_SPRG7R 0x107 /* Special Purpose Register General 7 Read */
-#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */
-#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
#define SPRN_SPRG4W 0x114 /* Special Purpose Register General 4 Write */
#define SPRN_SPRG5W 0x115 /* Special Purpose Register General 5 Write */
#define SPRN_SPRG6W 0x116 /* Special Purpose Register General 6 Write */
#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */
-#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
-#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */
#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */
#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */
@@ -252,10 +248,6 @@ do { \
#define SPRG5W SPRN_SPRG5W
#define SPRG6W SPRN_SPRG6W
#define SPRG7W SPRN_SPRG7W
-#define TBRL SPRN_TBRL /* Time Base Read Lower Register */
-#define TBRU SPRN_TBRU /* Time Base Read Upper Register */
-#define TBWL SPRN_TBWL /* Time Base Write Lower Register */
-#define TBWU SPRN_TBWU /* Time Base Write Upper Register */
/*
* The IBM-403 is an even more odd special case, as it is much
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
index 36b7a9b819c1..c885ff50bc86 100644
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -30,7 +30,7 @@
#ifndef __ASSEMBLY__
/* This structure can grow, it's real size is used by head.S code
- * via the mkdefs mecanism.
+ * via the mkdefs mechanism.
*/
struct cpu_spec;
diff --git a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h
index 79ba3c12ae3d..9744b7cb4ef9 100644
--- a/include/asm-ppc64/hardirq.h
+++ b/include/asm-ppc64/hardirq.h
@@ -15,9 +15,7 @@
typedef struct {
unsigned int __softirq_pending;
- unsigned int __syscall_count;
struct task_struct * __ksoftirqd_task;
- unsigned long idle_timestamp;
} ____cacheline_aligned irq_cpustat_t;
#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
diff --git a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
index c6fc6bfb0f5c..68b8e47017cd 100644
--- a/include/asm-ppc64/io.h
+++ b/include/asm-ppc64/io.h
@@ -17,6 +17,12 @@
#include <asm/memory.h>
#include <asm/delay.h>
+#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 *)(p), (a), (c))
+#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 *)(p), (a), (c))
+#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 *)(p), (a), (c))
+#define __ide_mm_outsl(p, a, c) _outsl_ns((volatile u32 *)(p), (a), (c))
+
+
#define SIO_CONFIG_RA 0x398
#define SIO_CONFIG_RD 0x399
@@ -93,7 +99,7 @@ extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
#define inw_p(port) inw(port)
#define outw_p(val, port) (udelay(1), outw((val), (port)))
#define inl_p(port) inl(port)
-#define outl_p(val, port) (udelay(1), outl((val, (port)))
+#define outl_p(val, port) (udelay(1), outl((val), (port)))
/*
* The *_ns versions below don't do byte-swapping.
diff --git a/include/asm-ppc64/memory.h b/include/asm-ppc64/memory.h
index 78297eff5015..82824fe447a0 100644
--- a/include/asm-ppc64/memory.h
+++ b/include/asm-ppc64/memory.h
@@ -58,7 +58,7 @@ static inline void isync(void)
#define HMT_LOW
#define HMT_MEDIUM
-#define HMT_LOW
+#define HMT_HIGH
#endif
#endif
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
index 8862dc52c483..da09c77b8123 100644
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -34,12 +34,15 @@ struct pci_dev;
#define HAVE_ARCH_PCI_MWI 1
static inline int pcibios_prep_mwi(struct pci_dev *dev)
{
- /*
- * pSeries firmware sets cacheline size and hardware treats
- * MWI the same as memory write, so we dont change cacheline size
- * or the MWI bit.
+ /*
+ * We would like to avoid touching the cacheline size or MWI bit
+ * but we cant do that with the current pcibios_prep_mwi
+ * interface. pSeries firmware sets the cacheline size (which is not
+ * the cpu cacheline size in all cases) and hardware treats MWI
+ * the same as memory write. So we dont touch the cacheline size
+ * here and allow the generic code to set the MWI bit.
*/
- return 1;
+ return 0;
}
extern unsigned int pcibios_assign_all_busses(void);
diff --git a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
index 9376b791bee7..23b0cde55e4e 100644
--- a/include/asm-ppc64/pgalloc.h
+++ b/include/asm-ppc64/pgalloc.h
@@ -2,8 +2,11 @@
#define _PPC64_PGALLOC_H
#include <linux/mm.h>
+#include <linux/slab.h>
#include <asm/processor.h>
+extern kmem_cache_t *zero_cache;
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,16 +17,13 @@
static inline pgd_t *
pgd_alloc(struct mm_struct *mm)
{
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
- if (pgd != NULL)
- clear_page(pgd);
- return pgd;
+ return kmem_cache_alloc(zero_cache, GFP_KERNEL);
}
static inline void
pgd_free(pgd_t *pgd)
{
- free_page((unsigned long)pgd);
+ kmem_cache_free(zero_cache, pgd);
}
#define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD)
@@ -31,18 +31,13 @@ pgd_free(pgd_t *pgd)
static inline pmd_t *
pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- pmd_t *pmd;
-
- pmd = (pmd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
- if (pmd)
- clear_page(pmd);
- return pmd;
+ return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
}
static inline void
pmd_free(pmd_t *pmd)
{
- free_page((unsigned long)pmd);
+ kmem_cache_free(zero_cache, pmd);
}
#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd)
@@ -54,12 +49,7 @@ pmd_free(pmd_t *pmd)
static inline pte_t *
pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
{
- pte_t *pte;
-
- pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
- if (pte)
- clear_page(pte);
- return pte;
+ return kmem_cache_alloc(zero_cache, GFP_KERNEL|__GFP_REPEAT);
}
static inline struct page *
@@ -76,7 +66,7 @@ pte_alloc_one(struct mm_struct *mm, unsigned long address)
static inline void
pte_free_kernel(pte_t *pte)
{
- free_page((unsigned long)pte);
+ kmem_cache_free(zero_cache, pte);
}
#define pte_free(pte_page) pte_free_kernel(page_address(pte_page))
diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
index c53351975e69..8564ebb88313 100644
--- a/include/asm-ppc64/pgtable.h
+++ b/include/asm-ppc64/pgtable.h
@@ -394,10 +394,7 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#define io_remap_page_range remap_page_range
-/*
- * No page table caches to initialise
- */
-#define pgtable_cache_init() do { } while (0)
+void pgtable_cache_init(void);
extern void hpte_init_pSeries(void);
extern void hpte_init_iSeries(void);
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index f878c5b05d42..0bfd4261518c 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -128,14 +128,6 @@
#define SPRN_DAC1 0x3F6 /* Data Address Compare 1 */
#define SPRN_DAC2 0x3F7 /* Data Address Compare 2 */
#define SPRN_DAR 0x013 /* Data Address Register */
-#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
-#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */
-#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */
-#define SPRN_DBAT1U 0x21A /* Data BAT 1 Upper Register */
-#define SPRN_DBAT2L 0x21D /* Data BAT 2 Lower Register */
-#define SPRN_DBAT2U 0x21C /* Data BAT 2 Upper Register */
-#define SPRN_DBAT3L 0x21F /* Data BAT 3 Lower Register */
-#define SPRN_DBAT3U 0x21E /* Data BAT 3 Upper Register */
#define SPRN_DBCR 0x3F2 /* Debug Control Regsiter */
#define DBCR_EDM 0x80000000
#define DBCR_IDM 0x40000000
@@ -229,14 +221,6 @@
#define SPRN_TST 0x3FC /* Thread switch timeout */
#define SPRN_IAC1 0x3F4 /* Instruction Address Compare 1 */
#define SPRN_IAC2 0x3F5 /* Instruction Address Compare 2 */
-#define SPRN_IBAT0L 0x211 /* Instruction BAT 0 Lower Register */
-#define SPRN_IBAT0U 0x210 /* Instruction BAT 0 Upper Register */
-#define SPRN_IBAT1L 0x213 /* Instruction BAT 1 Lower Register */
-#define SPRN_IBAT1U 0x212 /* Instruction BAT 1 Upper Register */
-#define SPRN_IBAT2L 0x215 /* Instruction BAT 2 Lower Register */
-#define SPRN_IBAT2U 0x214 /* Instruction BAT 2 Upper Register */
-#define SPRN_IBAT3L 0x217 /* Instruction BAT 3 Lower Register */
-#define SPRN_IBAT3U 0x216 /* Instruction BAT 3 Upper Register */
#define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */
#define ICCR_NOCACHE 0 /* Noncacheable */
#define ICCR_CACHE 1 /* Cacheable */
@@ -333,14 +317,6 @@
#define CTR SPRN_CTR /* Counter Register */
#define DAR SPRN_DAR /* Data Address Register */
#define DABR SPRN_DABR /* Data Address Breakpoint Register */
-#define DBAT0L SPRN_DBAT0L /* Data BAT 0 Lower Register */
-#define DBAT0U SPRN_DBAT0U /* Data BAT 0 Upper Register */
-#define DBAT1L SPRN_DBAT1L /* Data BAT 1 Lower Register */
-#define DBAT1U SPRN_DBAT1U /* Data BAT 1 Upper Register */
-#define DBAT2L SPRN_DBAT2L /* Data BAT 2 Lower Register */
-#define DBAT2U SPRN_DBAT2U /* Data BAT 2 Upper Register */
-#define DBAT3L SPRN_DBAT3L /* Data BAT 3 Lower Register */
-#define DBAT3U SPRN_DBAT3U /* Data BAT 3 Upper Register */
#define DCMP SPRN_DCMP /* Data TLB Compare Register */
#define DEC SPRN_DEC /* Decrement Register */
#define DMISS SPRN_DMISS /* Data TLB Miss Register */
@@ -354,14 +330,6 @@
#define TSC SPRN_TSC /* Thread switch control */
#define TST SPRN_TST /* Thread switch timeout */
#define IABR SPRN_IABR /* Instruction Address Breakpoint Register */
-#define IBAT0L SPRN_IBAT0L /* Instruction BAT 0 Lower Register */
-#define IBAT0U SPRN_IBAT0U /* Instruction BAT 0 Upper Register */
-#define IBAT1L SPRN_IBAT1L /* Instruction BAT 1 Lower Register */
-#define IBAT1U SPRN_IBAT1U /* Instruction BAT 1 Upper Register */
-#define IBAT2L SPRN_IBAT2L /* Instruction BAT 2 Lower Register */
-#define IBAT2U SPRN_IBAT2U /* Instruction BAT 2 Upper Register */
-#define IBAT3L SPRN_IBAT3L /* Instruction BAT 3 Lower Register */
-#define IBAT3U SPRN_IBAT3U /* Instruction BAT 3 Upper Register */
#define ICMP SPRN_ICMP /* Instruction TLB Compare Register */
#define IMISS SPRN_IMISS /* Instruction TLB Miss Register */
#define IMMR SPRN_IMMR /* PPC 860/821 Internal Memory Map Register */
@@ -391,84 +359,6 @@
#define THRM3 SPRN_THRM3 /* Thermal Management Register 3 */
#define XER SPRN_XER
-
-/* Device Control Registers */
-
-#define DCRN_BEAR 0x090 /* Bus Error Address Register */
-#define DCRN_BESR 0x091 /* Bus Error Syndrome Register */
-#define BESR_DSES 0x80000000 /* Data-Side Error Status */
-#define BESR_DMES 0x40000000 /* DMA Error Status */
-#define BESR_RWS 0x20000000 /* Read/Write Status */
-#define BESR_ETMASK 0x1C000000 /* Error Type */
-#define ET_PROT 0
-#define ET_PARITY 1
-#define ET_NCFG 2
-#define ET_BUSERR 4
-#define ET_BUSTO 6
-#define DCRN_DMACC0 0x0C4 /* DMA Chained Count Register 0 */
-#define DCRN_DMACC1 0x0CC /* DMA Chained Count Register 1 */
-#define DCRN_DMACC2 0x0D4 /* DMA Chained Count Register 2 */
-#define DCRN_DMACC3 0x0DC /* DMA Chained Count Register 3 */
-#define DCRN_DMACR0 0x0C0 /* DMA Channel Control Register 0 */
-#define DCRN_DMACR1 0x0C8 /* DMA Channel Control Register 1 */
-#define DCRN_DMACR2 0x0D0 /* DMA Channel Control Register 2 */
-#define DCRN_DMACR3 0x0D8 /* DMA Channel Control Register 3 */
-#define DCRN_DMACT0 0x0C1 /* DMA Count Register 0 */
-#define DCRN_DMACT1 0x0C9 /* DMA Count Register 1 */
-#define DCRN_DMACT2 0x0D1 /* DMA Count Register 2 */
-#define DCRN_DMACT3 0x0D9 /* DMA Count Register 3 */
-#define DCRN_DMADA0 0x0C2 /* DMA Destination Address Register 0 */
-#define DCRN_DMADA1 0x0CA /* DMA Destination Address Register 1 */
-#define DCRN_DMADA2 0x0D2 /* DMA Destination Address Register 2 */
-#define DCRN_DMADA3 0x0DA /* DMA Destination Address Register 3 */
-#define DCRN_DMASA0 0x0C3 /* DMA Source Address Register 0 */
-#define DCRN_DMASA1 0x0CB /* DMA Source Address Register 1 */
-#define DCRN_DMASA2 0x0D3 /* DMA Source Address Register 2 */
-#define DCRN_DMASA3 0x0DB /* DMA Source Address Register 3 */
-#define DCRN_DMASR 0x0E0 /* DMA Status Register */
-#define DCRN_EXIER 0x042 /* External Interrupt Enable Register */
-#define EXIER_CIE 0x80000000 /* Critical Interrupt Enable */
-#define EXIER_SRIE 0x08000000 /* Serial Port Rx Int. Enable */
-#define EXIER_STIE 0x04000000 /* Serial Port Tx Int. Enable */
-#define EXIER_JRIE 0x02000000 /* JTAG Serial Port Rx Int. Enable */
-#define EXIER_JTIE 0x01000000 /* JTAG Serial Port Tx Int. Enable */
-#define EXIER_D0IE 0x00800000 /* DMA Channel 0 Interrupt Enable */
-#define EXIER_D1IE 0x00400000 /* DMA Channel 1 Interrupt Enable */
-#define EXIER_D2IE 0x00200000 /* DMA Channel 2 Interrupt Enable */
-#define EXIER_D3IE 0x00100000 /* DMA Channel 3 Interrupt Enable */
-#define EXIER_E0IE 0x00000010 /* External Interrupt 0 Enable */
-#define EXIER_E1IE 0x00000008 /* External Interrupt 1 Enable */
-#define EXIER_E2IE 0x00000004 /* External Interrupt 2 Enable */
-#define EXIER_E3IE 0x00000002 /* External Interrupt 3 Enable */
-#define EXIER_E4IE 0x00000001 /* External Interrupt 4 Enable */
-#define DCRN_EXISR 0x040 /* External Interrupt Status Register */
-#define DCRN_IOCR 0x0A0 /* Input/Output Configuration Register */
-#define IOCR_E0TE 0x80000000
-#define IOCR_E0LP 0x40000000
-#define IOCR_E1TE 0x20000000
-#define IOCR_E1LP 0x10000000
-#define IOCR_E2TE 0x08000000
-#define IOCR_E2LP 0x04000000
-#define IOCR_E3TE 0x02000000
-#define IOCR_E3LP 0x01000000
-#define IOCR_E4TE 0x00800000
-#define IOCR_E4LP 0x00400000
-#define IOCR_EDT 0x00080000
-#define IOCR_SOR 0x00040000
-#define IOCR_EDO 0x00008000
-#define IOCR_2XC 0x00004000
-#define IOCR_ATC 0x00002000
-#define IOCR_SPD 0x00001000
-#define IOCR_BEM 0x00000800
-#define IOCR_PTD 0x00000400
-#define IOCR_ARE 0x00000080
-#define IOCR_DRC 0x00000020
-#define IOCR_RDM(x) (((x) & 0x3) << 3)
-#define IOCR_TCS 0x00000004
-#define IOCR_SCS 0x00000002
-#define IOCR_SPC 0x00000001
-
-
/* Processor Version Register (PVR) field extraction */
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
@@ -499,26 +389,6 @@
#define XGLUE(a,b) a##b
#define GLUE(a,b) XGLUE(a,b)
-/*
- * Begining of traceback info work for asm functions.
- */
-#define TB_ASM 0x000C000000000000
-#define TB_GLOBALLINK 0x0000800000000000
-#define TB_IS_EPROL 0x0000400000000000
-#define TB_HAS_TBOFF 0x0000200000000000
-#define TB_INT_PROC 0x0000100000000000
-#define TB_HAS_CTL 0x0000080000000000
-#define TB_TOCLESS 0x0000040000000000
-#define TB_FP_PRESENT 0x0000020000000000
-#define TB_LOG_ABORT 0x0000010000000000
-#define TB_INT_HNDL 0x0000008000000000
-#define TB_NAME_PRESENT 0x0000004000000000
-#define TB_SAVES_CR 0x0000000200000000
-#define TB_SAVES_LR 0x0000000100000000
-#define TB_STORES_BC 0x0000000080000000
-#define TB_PARMINFO 0x000000000000FFFF
-#define TB_DEFAULT TB_ASM | TB_HAS_TBOFF | TB_NAME_PRESENT
-
#ifdef __ASSEMBLY__
#define _GLOBAL(name) \
@@ -547,16 +417,6 @@ name: \
.type GLUE(.,name),@function; \
GLUE(.,name):
-#define _TRACEBACK(NAME) \
-GLUE(.LT,NAME): ;\
- .long 0 ;\
- .llong TB_DEFAULT ;\
- .long GLUE(.LT,NAME)-GLUE(.,NAME) ;\
- .short GLUE(GLUE(.LT,NAME),_procname_end)-GLUE(GLUE(.LT,NAME),_procname_start) ;\
-GLUE(GLUE(.LT,NAME),_procname_start): ;\
- .ascii __stringify(NAME) ;\
-GLUE(GLUE(.LT,NAME),_procname_end):
-
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-ppc64/siginfo.h b/include/asm-ppc64/siginfo.h
index 4481c731ab27..3a7c23dcb5aa 100644
--- a/include/asm-ppc64/siginfo.h
+++ b/include/asm-ppc64/siginfo.h
@@ -8,8 +8,8 @@
* 2 of the License, or (at your option) any later version.
*/
-#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4)
-#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
+#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
#include <asm-generic/siginfo.h>
diff --git a/include/asm-ppc64/thread_info.h b/include/asm-ppc64/thread_info.h
index 345008a8a14b..b7280fbb2dae 100644
--- a/include/asm-ppc64/thread_info.h
+++ b/include/asm-ppc64/thread_info.h
@@ -51,10 +51,8 @@ struct thread_info {
#define THREAD_ORDER 2
#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
#define THREAD_SHIFT (PAGE_SHIFT + THREAD_ORDER)
-
-#define alloc_thread_info(tsk) ((struct thread_info *) \
- __get_free_pages(GFP_KERNEL, THREAD_ORDER))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER)
+#define alloc_thread_info(task) ((struct thread_info *)kmalloc(THREAD_SIZE, GFP_KERNEL))
+#define free_thread_info(ti) kfree(ti)
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
diff --git a/include/asm-ppc64/uaccess.h b/include/asm-ppc64/uaccess.h
index 00f753a37df2..2c18c8ada2c9 100644
--- a/include/asm-ppc64/uaccess.h
+++ b/include/asm-ppc64/uaccess.h
@@ -218,7 +218,6 @@ do { \
extern unsigned long __copy_tofrom_user(void *to, const void *from,
unsigned long size);
-/* XXX should zero destination if fault happened */
static inline unsigned long
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
diff --git a/include/asm-sparc/atomic.h b/include/asm-sparc/atomic.h
index aa298155a8d3..f42ba9526265 100644
--- a/include/asm-sparc/atomic.h
+++ b/include/asm-sparc/atomic.h
@@ -48,10 +48,13 @@ static __inline__ int atomic_read(const atomic_t *v)
#define atomic_set(v, i) (((v)->counter) = ((i) << 8))
#endif
-static __inline__ int __atomic_add(int i, atomic_t *v)
+static inline int __atomic_add(int i, atomic_t *v)
{
register volatile int *ptr asm("g1");
register int increment asm("g2");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g7");
ptr = &v->counter;
increment = i;
@@ -60,17 +63,20 @@ static __inline__ int __atomic_add(int i, atomic_t *v)
"mov %%o7, %%g4\n\t"
"call ___atomic_add\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (increment)
+ : "=&r" (increment), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
: "0" (increment), "r" (ptr)
- : "g3", "g4", "g7", "memory", "cc");
+ : "memory", "cc");
return increment;
}
-static __inline__ int __atomic_sub(int i, atomic_t *v)
+static inline int __atomic_sub(int i, atomic_t *v)
{
register volatile int *ptr asm("g1");
register int increment asm("g2");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g7");
ptr = &v->counter;
increment = i;
@@ -79,9 +85,9 @@ static __inline__ int __atomic_sub(int i, atomic_t *v)
"mov %%o7, %%g4\n\t"
"call ___atomic_sub\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (increment)
+ : "=&r" (increment), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3)
: "0" (increment), "r" (ptr)
- : "g3", "g4", "g7", "memory", "cc");
+ : "memory", "cc");
return increment;
}
diff --git a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
index 4340bddccabb..a0e09a70ff78 100644
--- a/include/asm-sparc/bitops.h
+++ b/include/asm-sparc/bitops.h
@@ -20,10 +20,14 @@
* within the first byte. Sparc is BIG-Endian. Unless noted otherwise
* all bit-ops return 0 if bit was previously clear and != 0 otherwise.
*/
-static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
+static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -32,17 +36,21 @@ static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long
"mov %%o7, %%g4\n\t"
"call ___set_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "memory", "cc");
+ : "memory", "cc");
return mask != 0;
}
-static __inline__ void set_bit(unsigned long nr, volatile unsigned long *addr)
+static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -51,15 +59,19 @@ static __inline__ void set_bit(unsigned long nr, volatile unsigned long *addr)
"mov %%o7, %%g4\n\t"
"call ___set_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "cc");
+ : "memory", "cc");
}
-static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
+static inline int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -68,17 +80,21 @@ static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned lon
"mov %%o7, %%g4\n\t"
"call ___clear_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "memory", "cc");
+ : "memory", "cc");
return mask != 0;
}
-static __inline__ void clear_bit(unsigned long nr, volatile unsigned long *addr)
+static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -87,15 +103,19 @@ static __inline__ void clear_bit(unsigned long nr, volatile unsigned long *addr)
"mov %%o7, %%g4\n\t"
"call ___clear_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "cc");
+ : "memory", "cc");
}
-static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
+static inline int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -104,17 +124,21 @@ static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned lo
"mov %%o7, %%g4\n\t"
"call ___change_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "memory", "cc");
+ : "memory", "cc");
return mask != 0;
}
-static __inline__ void change_bit(unsigned long nr, volatile unsigned long *addr)
+static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
{
register unsigned long mask asm("g2");
register unsigned long *ADDR asm("g1");
+ register int tmp1 asm("g3");
+ register int tmp2 asm("g4");
+ register int tmp3 asm("g5");
+ register int tmp4 asm("g7");
ADDR = ((unsigned long *) addr) + (nr >> 5);
mask = 1 << (nr & 31);
@@ -123,15 +147,15 @@ static __inline__ void change_bit(unsigned long nr, volatile unsigned long *addr
"mov %%o7, %%g4\n\t"
"call ___change_bit\n\t"
" add %%o7, 8, %%o7\n"
- : "=&r" (mask)
+ : "=&r" (mask), "=r" (tmp1), "=r" (tmp2), "=r" (tmp3), "=r" (tmp4)
: "0" (mask), "r" (ADDR)
- : "g3", "g4", "g5", "g7", "cc");
+ : "memory", "cc");
}
/*
* non-atomic versions
*/
-static __inline__ void __set_bit(int nr, volatile unsigned long *addr)
+static inline void __set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -139,7 +163,7 @@ static __inline__ void __set_bit(int nr, volatile unsigned long *addr)
*p |= mask;
}
-static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -147,7 +171,7 @@ static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
*p &= ~mask;
}
-static __inline__ void __change_bit(int nr, volatile unsigned long *addr)
+static inline void __change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -155,7 +179,7 @@ static __inline__ void __change_bit(int nr, volatile unsigned long *addr)
*p ^= mask;
}
-static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -165,7 +189,7 @@ static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr)
return (old & mask) != 0;
}
-static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -175,7 +199,7 @@ static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
return (old & mask) != 0;
}
-static __inline__ int __test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
{
unsigned long mask = 1UL << (nr & 0x1f);
unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -189,13 +213,13 @@ static __inline__ int __test_and_change_bit(int nr, volatile unsigned long *addr
#define smp_mb__after_clear_bit() do { } while(0)
/* The following routine need not be atomic. */
-static __inline__ int test_bit(int nr, __const__ volatile unsigned long *addr)
+static inline int test_bit(int nr, __const__ volatile unsigned long *addr)
{
return (1UL & (((unsigned long *)addr)[nr >> 5] >> (nr & 31))) != 0UL;
}
/* The easy/cheese version for now. */
-static __inline__ unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
{
unsigned long result = 0;
@@ -212,7 +236,7 @@ static __inline__ unsigned long ffz(unsigned long word)
*
* Undefined if no bit exists, so code should check against 0 first.
*/
-static __inline__ int __ffs(unsigned long word)
+static inline int __ffs(unsigned long word)
{
int num = 0;
@@ -243,7 +267,7 @@ static __inline__ int __ffs(unsigned long word)
* unlikely to be set. It's guaranteed that at least one of the 140
* bits is cleared.
*/
-static __inline__ int sched_find_first_bit(unsigned long *b)
+static inline int sched_find_first_bit(unsigned long *b)
{
if (unlikely(b[0]))
@@ -262,7 +286,7 @@ static __inline__ int sched_find_first_bit(unsigned long *b)
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
*/
-static __inline__ int ffs(int x)
+static inline int ffs(int x)
{
if (!x)
return 0;
@@ -288,7 +312,7 @@ static __inline__ int ffs(int x)
* 'size' bits, starting the search at bit 'offset'. This is largely based
* on Linus's ALPHA routines, which are pretty portable BTW.
*/
-static __inline__ unsigned long find_next_zero_bit(unsigned long *addr,
+static inline unsigned long find_next_zero_bit(unsigned long *addr,
unsigned long size, unsigned long offset)
{
unsigned long *p = addr + (offset >> 5);
@@ -342,7 +366,7 @@ found_middle:
*
* Scheduler induced bitop, do not use.
*/
-static __inline__ int find_next_bit(unsigned long *addr, int size, int offset)
+static inline int find_next_bit(unsigned long *addr, int size, int offset)
{
unsigned long *p = addr + (offset >> 5);
int num = offset & ~0x1f;
@@ -362,7 +386,7 @@ static __inline__ int find_next_bit(unsigned long *addr, int size, int offset)
/*
*/
-static __inline__ int test_le_bit(int nr, __const__ unsigned long * addr)
+static inline int test_le_bit(int nr, __const__ unsigned long * addr)
{
__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
return (ADDR[nr >> 3] >> (nr & 7)) & 1;
@@ -371,7 +395,7 @@ static __inline__ int test_le_bit(int nr, __const__ unsigned long * addr)
/*
* non-atomic versions
*/
-static __inline__ void __set_le_bit(int nr, unsigned long *addr)
+static inline void __set_le_bit(int nr, unsigned long *addr)
{
unsigned char *ADDR = (unsigned char *)addr;
@@ -379,7 +403,7 @@ static __inline__ void __set_le_bit(int nr, unsigned long *addr)
*ADDR |= 1 << (nr & 0x07);
}
-static __inline__ void __clear_le_bit(int nr, unsigned long *addr)
+static inline void __clear_le_bit(int nr, unsigned long *addr)
{
unsigned char *ADDR = (unsigned char *)addr;
@@ -387,7 +411,7 @@ static __inline__ void __clear_le_bit(int nr, unsigned long *addr)
*ADDR &= ~(1 << (nr & 0x07));
}
-static __inline__ int __test_and_set_le_bit(int nr, unsigned long *addr)
+static inline int __test_and_set_le_bit(int nr, unsigned long *addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *)addr;
@@ -399,7 +423,7 @@ static __inline__ int __test_and_set_le_bit(int nr, unsigned long *addr)
return retval;
}
-static __inline__ int __test_and_clear_le_bit(int nr, unsigned long *addr)
+static inline int __test_and_clear_le_bit(int nr, unsigned long *addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *)addr;
@@ -411,7 +435,7 @@ static __inline__ int __test_and_clear_le_bit(int nr, unsigned long *addr)
return retval;
}
-static __inline__ unsigned long find_next_zero_le_bit(unsigned long *addr,
+static inline unsigned long find_next_zero_le_bit(unsigned long *addr,
unsigned long size, unsigned long offset)
{
unsigned long *p = addr + (offset >> 5);
@@ -455,14 +479,16 @@ found_middle:
#define find_first_zero_le_bit(addr, size) \
find_next_zero_le_bit((addr), (size), 0)
-#define ext2_set_bit __test_and_set_le_bit
-#define ext2_clear_bit __test_and_clear_le_bit
+#define ext2_set_bit(nr,addr) \
+ __test_and_set_le_bit((nr),(unsigned long *)(addr))
+#define ext2_clear_bit(nr,addr) \
+ __test_and_clear_le_bit((nr),(unsigned long *)(addr))
#define ext2_set_bit_atomic(lock, nr, addr) \
({ \
int ret; \
spin_lock(lock); \
- ret = ext2_set_bit((nr), (addr)); \
+ ret = ext2_set_bit((nr), (unsigned long *)(addr)); \
spin_unlock(lock); \
ret; \
})
@@ -471,21 +497,29 @@ found_middle:
({ \
int ret; \
spin_lock(lock); \
- ret = ext2_clear_bit((nr), (addr)); \
+ ret = ext2_clear_bit((nr), (unsigned long *)(addr)); \
spin_unlock(lock); \
ret; \
})
-#define ext2_test_bit test_le_bit
-#define ext2_find_first_zero_bit find_first_zero_le_bit
-#define ext2_find_next_zero_bit find_next_zero_le_bit
+#define ext2_test_bit(nr,addr) \
+ test_le_bit((nr),(unsigned long *)(addr))
+#define ext2_find_first_zero_bit(addr, size) \
+ find_first_zero_le_bit((unsigned long *)(addr), (size))
+#define ext2_find_next_zero_bit(addr, size, off) \
+ find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
/* Bitmap functions for the minix filesystem. */
-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
-#define minix_set_bit(nr,addr) set_bit(nr,addr)
-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
-#define minix_test_bit(nr,addr) test_bit(nr,addr)
-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+#define minix_test_and_set_bit(nr,addr) \
+ test_and_set_bit((nr),(unsigned long *)(addr))
+#define minix_set_bit(nr,addr) \
+ set_bit((nr),(unsigned long *)(addr))
+#define minix_test_and_clear_bit(nr,addr) \
+ test_and_clear_bit((nr),(unsigned long *)(addr))
+#define minix_test_bit(nr,addr) \
+ test_bit((nr),(unsigned long *)(addr))
+#define minix_find_first_zero_bit(addr,size) \
+ find_first_zero_bit((unsigned long *)(addr),(size))
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc/checksum.h b/include/asm-sparc/checksum.h
index eb027804f829..9dd5a7bfcb87 100644
--- a/include/asm-sparc/checksum.h
+++ b/include/asm-sparc/checksum.h
@@ -42,23 +42,26 @@ extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned i
extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
-extern __inline__ unsigned int
+static inline unsigned int
csum_partial_copy_nocheck (const char *src, char *dst, int len,
unsigned int sum)
{
register unsigned int ret asm("o0") = (unsigned int)src;
register char *d asm("o1") = dst;
register int l asm("g1") = len;
-
+
__asm__ __volatile__ (
"call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "\n\t"
- " mov %4, %%g7\n"
- : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ " mov %6, %%g7\n"
+ : "=&r" (ret), "=&r" (d), "=&r" (l)
+ : "0" (ret), "1" (d), "2" (l), "r" (sum)
+ : "o2", "o3", "o4", "o5", "o7",
+ "g2", "g3", "g4", "g5", "g7",
+ "memory", "cc");
return ret;
}
-extern __inline__ unsigned int
+static inline unsigned int
csum_partial_copy_from_user(const char *src, char *dst, int len,
unsigned int sum, int *err)
{
@@ -79,14 +82,16 @@ csum_partial_copy_from_user(const char *src, char *dst, int len,
".previous\n"
"1:\n\t"
"call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "\n\t"
- " st %5, [%%sp + 64]\n"
- : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ " st %8, [%%sp + 64]\n"
+ : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
+ : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err)
+ : "o2", "o3", "o4", "o5", "o7", "g2", "g3", "g4", "g5",
+ "cc", "memory");
return ret;
}
}
-extern __inline__ unsigned int
+static inline unsigned int
csum_partial_copy_to_user(const char *src, char *dst, int len,
unsigned int sum, int *err)
{
@@ -106,9 +111,12 @@ csum_partial_copy_to_user(const char *src, char *dst, int len,
".previous\n"
"1:\n\t"
"call " C_LABEL_STR(__csum_partial_copy_sparc_generic) "\n\t"
- " st %5, [%%sp + 64]\n"
- : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
- "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+ " st %8, [%%sp + 64]\n"
+ : "=&r" (ret), "=&r" (d), "=&r" (l), "=&r" (s)
+ : "0" (ret), "1" (d), "2" (l), "3" (s), "r" (err)
+ : "o2", "o3", "o4", "o5", "o7",
+ "g2", "g3", "g4", "g5",
+ "cc", "memory");
return ret;
}
}
@@ -119,8 +127,8 @@ csum_partial_copy_to_user(const char *src, char *dst, int len,
/* ihl is always 5 or greater, almost always is 5, and iph is word aligned
* the majority of the time.
*/
-extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
- unsigned int ihl)
+static inline unsigned short ip_fast_csum(const unsigned char *iph,
+ unsigned int ihl)
{
unsigned short sum;
@@ -157,7 +165,7 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
}
/* Fold a partial checksum without adding pseudo headers. */
-extern __inline__ unsigned int csum_fold(unsigned int sum)
+static inline unsigned int csum_fold(unsigned int sum)
{
unsigned int tmp;
@@ -171,11 +179,11 @@ extern __inline__ unsigned int csum_fold(unsigned int sum)
return sum;
}
-extern __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
- unsigned long daddr,
- unsigned int len,
- unsigned short proto,
- unsigned int sum)
+static inline unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned int len,
+ unsigned short proto,
+ unsigned int sum)
{
__asm__ __volatile__("addcc\t%1, %0, %0\n\t"
"addxcc\t%2, %0, %0\n\t"
@@ -203,11 +211,11 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
#define _HAVE_ARCH_IPV6_CSUM
-static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
- struct in6_addr *daddr,
- __u32 len,
- unsigned short proto,
- unsigned int sum)
+static inline unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u32 len,
+ unsigned short proto,
+ unsigned int sum)
{
__asm__ __volatile__ (
"addcc %3, %4, %%g4\n\t"
@@ -238,7 +246,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
}
/* this routine is used for miscellaneous IP-like checksums, mainly in icmp.c */
-extern __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
{
return csum_fold(csum_partial(buff, len, 0));
}
diff --git a/include/asm-sparc/io.h b/include/asm-sparc/io.h
index f3fdacf95ba5..72c304cad644 100644
--- a/include/asm-sparc/io.h
+++ b/include/asm-sparc/io.h
@@ -13,12 +13,12 @@
#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
-static __inline__ u32 flip_dword (u32 d)
+static inline u32 flip_dword (u32 d)
{
return ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff);
}
-static __inline__ u16 flip_word (u16 d)
+static inline u16 flip_word (u16 d)
{
return ((d&0xff) << 8) | ((d>>8)&0xff);
}
@@ -36,43 +36,73 @@ static __inline__ u16 flip_word (u16 d)
* The offshot is, we must cast readb et. al. arguments with a #define.
*/
-static __inline__ u8 __raw_readb(unsigned long addr)
+static inline u8 __raw_readb(unsigned long addr)
{
return *(volatile u8 *)addr;
}
-static __inline__ u16 __raw_readw(unsigned long addr)
+static inline u16 __raw_readw(unsigned long addr)
{
return *(volatile u16 *)addr;
}
-static __inline__ u32 __raw_readl(unsigned long addr)
+static inline u32 __raw_readl(unsigned long addr)
{
return *(volatile u32 *)addr;
}
-static __inline__ void __raw_writeb(u8 b, unsigned long addr)
+static inline void __raw_writeb(u8 b, unsigned long addr)
{
*(volatile u8 *)addr = b;
}
-static __inline__ void __raw_writew(u16 b, unsigned long addr)
+static inline void __raw_writew(u16 b, unsigned long addr)
{
*(volatile u16 *)addr = b;
}
-static __inline__ void __raw_writel(u32 b, unsigned long addr)
+static inline void __raw_writel(u32 b, unsigned long addr)
{
*(volatile u32 *)addr = b;
}
-#define readb(addr) (*(volatile u8 *)(addr))
-#define readw(addr) flip_word(*(volatile u16 *)(addr))
-#define readl(addr) flip_dword(*(volatile u32 *)(addr))
+static inline u8 __readb(unsigned long addr)
+{
+ return *(volatile u8 *)addr;
+}
+
+static inline u16 __readw(unsigned long addr)
+{
+ return flip_word(*(volatile u16 *)addr);
+}
+
+static inline u32 __readl(unsigned long addr)
+{
+ return flip_dword(*(volatile u32 *)addr);
+}
+
+static inline void __writeb(u8 b, unsigned long addr)
+{
+ *(volatile u8 *)addr = b;
+}
+
+static inline void __writew(u16 b, unsigned long addr)
+{
+ *(volatile u16 *)addr = flip_word(b);
+}
+
+static inline void __writel(u32 b, unsigned long addr)
+{
+ *(volatile u32 *)addr = flip_dword(b);
+}
+
+#define readb(addr) __readb((unsigned long)(addr))
+#define readw(addr) __readw((unsigned long)(addr))
+#define readl(addr) __readl((unsigned long)(addr))
-#define writeb(b, a) (*(volatile u8 *)(a) = b)
-#define writew(b, a) (*(volatile u16 *)(a) = flip_word(b))
-#define writel(b, a) (*(volatile u32 *)(a) = flip_dword(b))
+#define writeb(b, addr) __writeb((b),(unsigned long)(addr))
+#define writew(b, addr) __writew((b),(unsigned long)(addr))
+#define writel(b, addr) __writel((b),(unsigned long)(addr))
/*
* I/O space operations
@@ -91,17 +121,22 @@ static __inline__ void __raw_writel(u32 b, unsigned long addr)
* mapped somewhere into virtual kernel space and we
* can use inb/outb again.
*/
-#define inb_local(addr) readb(addr)
-#define inb(addr) readb(addr)
-#define inw(addr) readw(addr)
-#define inl(addr) readl(addr)
-#define inb_p(addr) readb(addr)
-
-#define outb_local(b, addr) writeb(b, addr)
-#define outb(b, addr) writeb(b, addr)
-#define outw(b, addr) writew(b, addr)
-#define outl(b, addr) writel(b, addr)
-#define outb_p(b, addr) writeb(b, addr)
+#define inb_local(addr) __readb(addr)
+#define inb(addr) __readb(addr)
+#define inw(addr) __readw(addr)
+#define inl(addr) __readl(addr)
+
+#define outb_local(b, addr) __writeb(b, addr)
+#define outb(b, addr) __writeb(b, addr)
+#define outw(b, addr) __writew(b, addr)
+#define outl(b, addr) __writel(b, addr)
+
+#define inb_p inb
+#define outb_p outb
+#define inw_p inw
+#define outw_p outw
+#define inl_p inl
+#define outl_p outl
extern void outsb(unsigned long addr, const void *src, unsigned long cnt);
extern void outsw(unsigned long addr, const void *src, unsigned long cnt);
@@ -118,32 +153,32 @@ extern void insl(unsigned long addr, void *dst, unsigned long count);
* SBus has only one, memory mapped, I/O space.
* We do not need to flip bytes for SBus of course.
*/
-static __inline__ u8 _sbus_readb(unsigned long addr)
+static inline u8 _sbus_readb(unsigned long addr)
{
return *(volatile u8 *)addr;
}
-static __inline__ u16 _sbus_readw(unsigned long addr)
+static inline u16 _sbus_readw(unsigned long addr)
{
return *(volatile u16 *)addr;
}
-static __inline__ u32 _sbus_readl(unsigned long addr)
+static inline u32 _sbus_readl(unsigned long addr)
{
return *(volatile u32 *)addr;
}
-static __inline__ void _sbus_writeb(u8 b, unsigned long addr)
+static inline void _sbus_writeb(u8 b, unsigned long addr)
{
*(volatile u8 *)addr = b;
}
-static __inline__ void _sbus_writew(u16 b, unsigned long addr)
+static inline void _sbus_writew(u16 b, unsigned long addr)
{
*(volatile u16 *)addr = b;
}
-static __inline__ void _sbus_writel(u32 b, unsigned long addr)
+static inline void _sbus_writel(u32 b, unsigned long addr)
{
*(volatile u32 *)addr = b;
}
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index c1d81aaf072a..5423905ffb40 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -39,14 +39,45 @@ BTFIXUPDEF_CALL(void, clear_clock_irq, void)
BTFIXUPDEF_CALL(void, clear_profile_irq, int)
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-#define disable_irq_nosync disable_irq
-#define disable_irq(irq) BTFIXUP_CALL(disable_irq)(irq)
-#define enable_irq(irq) BTFIXUP_CALL(enable_irq)(irq)
-#define disable_pil_irq(irq) BTFIXUP_CALL(disable_pil_irq)(irq)
-#define enable_pil_irq(irq) BTFIXUP_CALL(enable_pil_irq)(irq)
-#define clear_clock_irq() BTFIXUP_CALL(clear_clock_irq)()
-#define clear_profile_irq(cpu) BTFIXUP_CALL(clear_profile_irq)(cpu)
-#define load_profile_irq(cpu,limit) BTFIXUP_CALL(load_profile_irq)(cpu,limit)
+static inline void disable_irq_nosync(unsigned int irq)
+{
+ BTFIXUP_CALL(disable_irq)(irq);
+}
+
+static inline void disable_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(disable_irq)(irq);
+}
+
+static inline void enable_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(enable_irq)(irq);
+}
+
+static inline void disable_pil_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(disable_pil_irq)(irq);
+}
+
+static inline void enable_pil_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(enable_pil_irq)(irq);
+}
+
+static inline void clear_clock_irq(void)
+{
+ BTFIXUP_CALL(clear_clock_irq)();
+}
+
+static inline void clear_profile_irq(int irq)
+{
+ BTFIXUP_CALL(clear_profile_irq)(irq);
+}
+
+static inline void load_profile_irq(int cpu, int limit)
+{
+ BTFIXUP_CALL(load_profile_irq)(cpu, limit);
+}
extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *, struct pt_regs *));
extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
diff --git a/include/asm-sparc/pgtsun4.h b/include/asm-sparc/pgtsun4.h
index 1c6efda336c7..67a7d27dd16e 100644
--- a/include/asm-sparc/pgtsun4.h
+++ b/include/asm-sparc/pgtsun4.h
@@ -76,7 +76,7 @@
#ifndef __ASSEMBLY__
-extern __inline__ unsigned long sun4c_get_synchronous_error(void)
+static inline unsigned long sun4c_get_synchronous_error(void)
{
unsigned long sync_err;
@@ -86,7 +86,7 @@ extern __inline__ unsigned long sun4c_get_synchronous_error(void)
return sync_err;
}
-extern __inline__ unsigned long sun4c_get_synchronous_address(void)
+static inline unsigned long sun4c_get_synchronous_address(void)
{
unsigned long sync_addr;
@@ -97,7 +97,7 @@ extern __inline__ unsigned long sun4c_get_synchronous_address(void)
}
/* SUN4 pte, segmap, and context manipulation */
-extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
+static inline unsigned long sun4c_get_segmap(unsigned long addr)
{
register unsigned long entry;
@@ -107,14 +107,15 @@ extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
return entry;
}
-extern __inline__ void sun4c_put_segmap(unsigned long addr, unsigned long entry)
+static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry)
{
__asm__ __volatile__("\n\tstha %1, [%0] %2; nop; nop; nop;\n\t" : :
"r" (addr), "r" (entry),
- "i" (ASI_SEGMAP));
+ "i" (ASI_SEGMAP)
+ : "memory");
}
-extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
+static inline unsigned long sun4c_get_pte(unsigned long addr)
{
register unsigned long entry;
@@ -124,14 +125,15 @@ extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
return entry;
}
-extern __inline__ void sun4c_put_pte(unsigned long addr, unsigned long entry)
+static inline void sun4c_put_pte(unsigned long addr, unsigned long entry)
{
__asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : :
"r" (addr),
- "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE));
+ "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE)
+ : "memory");
}
-extern __inline__ int sun4c_get_context(void)
+static inline int sun4c_get_context(void)
{
register int ctx;
@@ -142,10 +144,11 @@ extern __inline__ int sun4c_get_context(void)
return ctx;
}
-extern __inline__ int sun4c_set_context(int ctx)
+static inline int sun4c_set_context(int ctx)
{
__asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : :
- "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+ "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL)
+ : "memory");
return ctx;
}
diff --git a/include/asm-sparc/pgtsun4c.h b/include/asm-sparc/pgtsun4c.h
index efc081004262..306aaa1c42cb 100644
--- a/include/asm-sparc/pgtsun4c.h
+++ b/include/asm-sparc/pgtsun4c.h
@@ -76,7 +76,7 @@
#ifndef __ASSEMBLY__
-extern __inline__ unsigned long sun4c_get_synchronous_error(void)
+static inline unsigned long sun4c_get_synchronous_error(void)
{
unsigned long sync_err;
@@ -86,7 +86,7 @@ extern __inline__ unsigned long sun4c_get_synchronous_error(void)
return sync_err;
}
-extern __inline__ unsigned long sun4c_get_synchronous_address(void)
+static inline unsigned long sun4c_get_synchronous_address(void)
{
unsigned long sync_addr;
@@ -97,7 +97,7 @@ extern __inline__ unsigned long sun4c_get_synchronous_address(void)
}
/* SUN4C pte, segmap, and context manipulation */
-extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
+static inline unsigned long sun4c_get_segmap(unsigned long addr)
{
register unsigned long entry;
@@ -108,15 +108,16 @@ extern __inline__ unsigned long sun4c_get_segmap(unsigned long addr)
return entry;
}
-extern __inline__ void sun4c_put_segmap(unsigned long addr, unsigned long entry)
+static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry)
{
__asm__ __volatile__("\n\tstba %1, [%0] %2; nop; nop; nop;\n\t" : :
"r" (addr), "r" (entry),
- "i" (ASI_SEGMAP));
+ "i" (ASI_SEGMAP)
+ : "memory");
}
-extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
+static inline unsigned long sun4c_get_pte(unsigned long addr)
{
register unsigned long entry;
@@ -126,14 +127,15 @@ extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
return entry;
}
-extern __inline__ void sun4c_put_pte(unsigned long addr, unsigned long entry)
+static inline void sun4c_put_pte(unsigned long addr, unsigned long entry)
{
__asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : :
"r" (addr),
- "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE));
+ "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE)
+ : "memory");
}
-extern __inline__ int sun4c_get_context(void)
+static inline int sun4c_get_context(void)
{
register int ctx;
@@ -144,10 +146,11 @@ extern __inline__ int sun4c_get_context(void)
return ctx;
}
-extern __inline__ int sun4c_set_context(int ctx)
+static inline int sun4c_set_context(int ctx)
{
__asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : :
- "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL));
+ "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL)
+ : "memory");
return ctx;
}
diff --git a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h
index 3f3bf3ca874c..2ae0e6bb9a53 100644
--- a/include/asm-sparc/processor.h
+++ b/include/asm-sparc/processor.h
@@ -130,8 +130,12 @@ extern __inline__ void start_thread(struct pt_regs * regs, unsigned long pc,
"std\t%%g0, [%0 + %3 + 0x30]\n\t"
"st\t%1, [%0 + %3 + 0x38]\n\t"
"st\t%%g0, [%0 + %3 + 0x3c]"
- : : "r" (regs), "r" (sp - sizeof(struct reg_window)), "r" (zero),
- "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])));
+ : /* no outputs */
+ : "r" (regs),
+ "r" (sp - sizeof(struct reg_window)),
+ "r" (zero),
+ "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))
+ : "memory");
}
/* Free all resources held by a thread. */
diff --git a/include/asm-sparc/ross.h b/include/asm-sparc/ross.h
index 42c5381eb732..f2c14b5080ed 100644
--- a/include/asm-sparc/ross.h
+++ b/include/asm-sparc/ross.h
@@ -96,27 +96,29 @@
#ifndef __ASSEMBLY__
-extern __inline__ unsigned int get_ross_icr(void)
+static inline unsigned int get_ross_icr(void)
{
unsigned int icreg;
__asm__ __volatile__(".word 0x8347c000\n\t" /* rd %iccr, %g1 */
- "mov %%g1, %0\n\t" :
- "=r" (icreg) : :
- "g1", "memory");
+ "mov %%g1, %0\n\t"
+ : "=r" (icreg)
+ : /* no inputs */
+ : "g1", "memory");
return icreg;
}
-extern __inline__ void put_ross_icr(unsigned int icreg)
+static inline void put_ross_icr(unsigned int icreg)
{
__asm__ __volatile__("or %%g0, %0, %%g1\n\t"
".word 0xbf806000\n\t" /* wr %g1, 0x0, %iccr */
"nop\n\t"
"nop\n\t"
- "nop\n\t" : :
- "r" (icreg) :
- "g1", "memory");
+ "nop\n\t"
+ : /* no outputs */
+ : "r" (icreg)
+ : "g1", "memory");
return;
}
@@ -124,52 +126,62 @@ extern __inline__ void put_ross_icr(unsigned int icreg)
/* HyperSparc specific cache flushing. */
/* This is for the on-chip instruction cache. */
-extern __inline__ void hyper_flush_whole_icache(void)
+static inline void hyper_flush_whole_icache(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_FLUSH_IWHOLE));
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_FLUSH_IWHOLE)
+ : "memory");
return;
}
extern int vac_cache_size;
extern int vac_line_size;
-extern __inline__ void hyper_clear_all_tags(void)
+static inline void hyper_clear_all_tags(void)
{
unsigned long addr;
for(addr = 0; addr < vac_cache_size; addr += vac_line_size)
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_DATAC_TAG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_DATAC_TAG)
+ : "memory");
}
-extern __inline__ void hyper_flush_unconditional_combined(void)
+static inline void hyper_flush_unconditional_combined(void)
{
unsigned long addr;
- for(addr = 0; addr < vac_cache_size; addr += vac_line_size)
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_FLUSH_CTX));
+ for (addr = 0; addr < vac_cache_size; addr += vac_line_size)
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_FLUSH_CTX)
+ : "memory");
}
-extern __inline__ void hyper_flush_cache_user(void)
+static inline void hyper_flush_cache_user(void)
{
unsigned long addr;
- for(addr = 0; addr < vac_cache_size; addr += vac_line_size)
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_FLUSH_USER));
+ for (addr = 0; addr < vac_cache_size; addr += vac_line_size)
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_FLUSH_USER)
+ : "memory");
}
-extern __inline__ void hyper_flush_cache_page(unsigned long page)
+static inline void hyper_flush_cache_page(unsigned long page)
{
unsigned long end;
page &= PAGE_MASK;
end = page + PAGE_SIZE;
- while(page < end) {
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (page), "i" (ASI_M_FLUSH_PAGE));
+ while (page < end) {
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (page), "i" (ASI_M_FLUSH_PAGE)
+ : "memory");
page += vac_line_size;
}
}
diff --git a/include/asm-sparc/swift.h b/include/asm-sparc/swift.h
index c3e2ffe2d7a5..e535061bf755 100644
--- a/include/asm-sparc/swift.h
+++ b/include/asm-sparc/swift.h
@@ -27,68 +27,80 @@
#define SWIFT_EN 0x00000001 /* MMU enable */
/* Bits [13:5] select one of 512 instruction cache tags */
-extern __inline__ void swift_inv_insn_tag(unsigned long addr)
+static inline void swift_inv_insn_tag(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_TXTC_TAG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_TXTC_TAG)
+ : "memory");
}
/* Bits [12:4] select one of 512 data cache tags */
-extern __inline__ void swift_inv_data_tag(unsigned long addr)
+static inline void swift_inv_data_tag(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_DATAC_TAG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_DATAC_TAG)
+ : "memory");
}
-extern __inline__ void swift_flush_dcache(void)
+static inline void swift_flush_dcache(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x2000; addr += 0x10)
+ for (addr = 0; addr < 0x2000; addr += 0x10)
swift_inv_data_tag(addr);
}
-extern __inline__ void swift_flush_icache(void)
+static inline void swift_flush_icache(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x4000; addr += 0x20)
+ for (addr = 0; addr < 0x4000; addr += 0x20)
swift_inv_insn_tag(addr);
}
-extern __inline__ void swift_idflash_clear(void)
+static inline void swift_idflash_clear(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x2000; addr += 0x10) {
+ for (addr = 0; addr < 0x2000; addr += 0x10) {
swift_inv_insn_tag(addr<<1);
swift_inv_data_tag(addr);
}
}
/* Swift is so broken, it isn't even safe to use the following. */
-extern __inline__ void swift_flush_page(unsigned long page)
+static inline void swift_flush_page(unsigned long page)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (page), "i" (ASI_M_FLUSH_PAGE));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (page), "i" (ASI_M_FLUSH_PAGE)
+ : "memory");
}
-extern __inline__ void swift_flush_segment(unsigned long addr)
+static inline void swift_flush_segment(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_FLUSH_SEG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_FLUSH_SEG)
+ : "memory");
}
-extern __inline__ void swift_flush_region(unsigned long addr)
+static inline void swift_flush_region(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_FLUSH_REGION));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_FLUSH_REGION)
+ : "memory");
}
-extern __inline__ void swift_flush_context(void)
+static inline void swift_flush_context(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_FLUSH_CTX));
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_FLUSH_CTX)
+ : "memory");
}
#endif /* !(_SPARC_SWIFT_H) */
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 86162b780635..b53cf2c6897e 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -220,7 +220,7 @@ extern __inline__ unsigned long swap_pil(unsigned long __new_psr)
"wr %0, %2, %%psr\n\t"
"nop; nop; nop;\n"
"1:\n"
- : "=r" (retval)
+ : "=&r" (retval)
: "r" (__new_psr), "i" (PSR_PIL)
: "g1", "g2", "memory", "cc");
@@ -298,7 +298,8 @@ extern __inline__ unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned
#ifdef CONFIG_SMP
__asm__ __volatile__("swap [%2], %0"
: "=&r" (val)
- : "0" (val), "r" (m));
+ : "0" (val), "r" (m)
+ : "memory");
return val;
#else
register unsigned long *ptr asm("g1");
diff --git a/include/asm-sparc/tsunami.h b/include/asm-sparc/tsunami.h
index 384ea6e68203..887add5c466b 100644
--- a/include/asm-sparc/tsunami.h
+++ b/include/asm-sparc/tsunami.h
@@ -45,16 +45,20 @@
#define TSUNAMI_NF 0x00000002
#define TSUNAMI_ME 0x00000001
-extern __inline__ void tsunami_flush_icache(void)
+static inline void tsunami_flush_icache(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_IC_FLCLEAR) : "memory");
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_IC_FLCLEAR)
+ : "memory");
}
-extern __inline__ void tsunami_flush_dcache(void)
+static inline void tsunami_flush_dcache(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_DC_FLCLEAR) : "memory");
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_DC_FLCLEAR)
+ : "memory");
}
#endif /* !(_SPARC_TSUNAMI_H) */
diff --git a/include/asm-sparc/turbosparc.h b/include/asm-sparc/turbosparc.h
index 5078d901bda6..31d2350a5818 100644
--- a/include/asm-sparc/turbosparc.h
+++ b/include/asm-sparc/turbosparc.h
@@ -59,60 +59,64 @@
#ifndef __ASSEMBLY__
/* Bits [13:5] select one of 512 instruction cache tags */
-extern __inline__ void turbosparc_inv_insn_tag(unsigned long addr)
+static inline void turbosparc_inv_insn_tag(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_TXTC_TAG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_TXTC_TAG)
+ : "memory");
}
/* Bits [13:5] select one of 512 data cache tags */
-extern __inline__ void turbosparc_inv_data_tag(unsigned long addr)
+static inline void turbosparc_inv_data_tag(unsigned long addr)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (addr), "i" (ASI_M_DATAC_TAG));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (addr), "i" (ASI_M_DATAC_TAG)
+ : "memory");
}
-extern __inline__ void turbosparc_flush_icache(void)
+static inline void turbosparc_flush_icache(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x4000; addr += 0x20)
+ for (addr = 0; addr < 0x4000; addr += 0x20)
turbosparc_inv_insn_tag(addr);
}
-extern __inline__ void turbosparc_flush_dcache(void)
+static inline void turbosparc_flush_dcache(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x4000; addr += 0x20)
+ for (addr = 0; addr < 0x4000; addr += 0x20)
turbosparc_inv_data_tag(addr);
}
-extern __inline__ void turbosparc_idflash_clear(void)
+static inline void turbosparc_idflash_clear(void)
{
unsigned long addr;
- for(addr = 0; addr < 0x4000; addr += 0x20) {
+ for (addr = 0; addr < 0x4000; addr += 0x20) {
turbosparc_inv_insn_tag(addr);
turbosparc_inv_data_tag(addr);
}
}
-extern __inline__ void turbosparc_set_ccreg(unsigned long regval)
+static inline void turbosparc_set_ccreg(unsigned long regval)
{
- __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
- "r" (regval), "r" (0x600),
- "i" (ASI_M_MMUREGS));
+ __asm__ __volatile__("sta %0, [%1] %2\n\t"
+ : /* no outputs */
+ : "r" (regval), "r" (0x600), "i" (ASI_M_MMUREGS)
+ : "memory");
}
-extern __inline__ unsigned long turbosparc_get_ccreg(void)
+static inline unsigned long turbosparc_get_ccreg(void)
{
unsigned long regval;
- __asm__ __volatile__("lda [%1] %2, %0\n\t" :
- "=r" (regval) :
- "r" (0x600),
- "i" (ASI_M_MMUREGS));
+ __asm__ __volatile__("lda [%1] %2, %0\n\t"
+ : "=r" (regval)
+ : "r" (0x600), "i" (ASI_M_MMUREGS));
return regval;
}
diff --git a/include/asm-sparc/vac-ops.h b/include/asm-sparc/vac-ops.h
index 7b991e82423d..9e0172323042 100644
--- a/include/asm-sparc/vac-ops.h
+++ b/include/asm-sparc/vac-ops.h
@@ -108,27 +108,29 @@ struct sun4c_vac_props {
extern struct sun4c_vac_props sun4c_vacinfo;
/* sun4c_enable_vac() enables the sun4c virtual address cache. */
-extern __inline__ void sun4c_enable_vac(void)
+static inline void sun4c_enable_vac(void)
{
- __asm__ __volatile__("lduba [%0] %1, %%g1\n\t"
- "or %%g1, %2, %%g1\n\t"
- "stba %%g1, [%0] %1\n\t" : :
- "r" ((unsigned int) AC_SENABLE),
- "i" (ASI_CONTROL), "i" (SENABLE_CACHE) :
- "g1");
- sun4c_vacinfo.on = 1;
+ __asm__ __volatile__("lduba [%0] %1, %%g1\n\t"
+ "or %%g1, %2, %%g1\n\t"
+ "stba %%g1, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" ((unsigned int) AC_SENABLE),
+ "i" (ASI_CONTROL), "i" (SENABLE_CACHE)
+ : "g1", "memory");
+ sun4c_vacinfo.on = 1;
}
/* sun4c_disable_vac() disables the virtual address cache. */
-extern __inline__ void sun4c_disable_vac(void)
+static inline void sun4c_disable_vac(void)
{
- __asm__ __volatile__("lduba [%0] %1, %%g1\n\t"
- "andn %%g1, %2, %%g1\n\t"
- "stba %%g1, [%0] %1\n\t" : :
- "r" ((unsigned int) AC_SENABLE),
- "i" (ASI_CONTROL), "i" (SENABLE_CACHE) :
- "g1");
- sun4c_vacinfo.on = 0;
+ __asm__ __volatile__("lduba [%0] %1, %%g1\n\t"
+ "andn %%g1, %2, %%g1\n\t"
+ "stba %%g1, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" ((unsigned int) AC_SENABLE),
+ "i" (ASI_CONTROL), "i" (SENABLE_CACHE)
+ : "g1", "memory");
+ sun4c_vacinfo.on = 0;
}
#endif /* !(_SPARC_VAC_OPS_H) */
diff --git a/include/asm-sparc/viking.h b/include/asm-sparc/viking.h
index 0312a2d557a9..3742cfa07663 100644
--- a/include/asm-sparc/viking.h
+++ b/include/asm-sparc/viking.h
@@ -110,48 +110,57 @@
#ifndef __ASSEMBLY__
-extern __inline__ void viking_flush_icache(void)
+static inline void viking_flush_icache(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_IC_FLCLEAR));
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_IC_FLCLEAR)
+ : "memory");
}
-extern __inline__ void viking_flush_dcache(void)
+static inline void viking_flush_dcache(void)
{
- __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
- "i" (ASI_M_DC_FLCLEAR));
+ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t"
+ : /* no outputs */
+ : "i" (ASI_M_DC_FLCLEAR)
+ : "memory");
}
-extern __inline__ void viking_unlock_icache(void)
+static inline void viking_unlock_icache(void)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (0x80000000), "i" (ASI_M_IC_FLCLEAR));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (0x80000000), "i" (ASI_M_IC_FLCLEAR)
+ : "memory");
}
-extern __inline__ void viking_unlock_dcache(void)
+static inline void viking_unlock_dcache(void)
{
- __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
- "r" (0x80000000), "i" (ASI_M_DC_FLCLEAR));
+ __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+ : /* no outputs */
+ : "r" (0x80000000), "i" (ASI_M_DC_FLCLEAR)
+ : "memory");
}
-extern __inline__ void viking_set_bpreg(unsigned long regval)
+static inline void viking_set_bpreg(unsigned long regval)
{
- __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
- "r" (regval),
- "i" (ASI_M_ACTION));
+ __asm__ __volatile__("sta %0, [%%g0] %1\n\t"
+ : /* no outputs */
+ : "r" (regval), "i" (ASI_M_ACTION)
+ : "memory");
}
-extern __inline__ unsigned long viking_get_bpreg(void)
+static inline unsigned long viking_get_bpreg(void)
{
unsigned long regval;
- __asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
- "=r" (regval) :
- "i" (ASI_M_ACTION));
+ __asm__ __volatile__("lda [%%g0] %1, %0\n\t"
+ : "=r" (regval)
+ : "i" (ASI_M_ACTION));
return regval;
}
-extern __inline__ void viking_get_dcache_ptag(int set, int block,
+static inline void viking_get_dcache_ptag(int set, int block,
unsigned long *data)
{
unsigned long ptag = ((set & 0x7f) << 5) | ((block & 0x3) << 26) |
@@ -160,15 +169,15 @@ extern __inline__ void viking_get_dcache_ptag(int set, int block,
__asm__ __volatile__ ("ldda [%2] %3, %%g2\n\t"
"or %%g0, %%g2, %0\n\t"
- "or %%g0, %%g3, %1\n\t" :
- "=r" (info), "=r" (page) :
- "r" (ptag), "i" (ASI_M_DATAC_TAG) :
- "g2", "g3");
+ "or %%g0, %%g3, %1\n\t"
+ : "=r" (info), "=r" (page)
+ : "r" (ptag), "i" (ASI_M_DATAC_TAG)
+ : "g2", "g3");
data[0] = info;
data[1] = page;
}
-extern __inline__ void viking_mxcc_turn_off_parity(unsigned long *mregp,
+static inline void viking_mxcc_turn_off_parity(unsigned long *mregp,
unsigned long *mxcc_cregp)
{
unsigned long mreg = *mregp;
@@ -190,30 +199,32 @@ extern __inline__ void viking_mxcc_turn_off_parity(unsigned long *mregp,
"2:\n\t"
"sta %0, [%%g0] %3\n\t"
"sta %1, [%2] %4\n"
- "1:\n\t" : :
- "r" (mreg), "r" (mxcc_creg),
- "r" (MXCC_CREG), "i" (ASI_M_MMUREGS),
- "i" (ASI_M_MXCC) : "g2", "cc");
+ "1:\n\t"
+ : /* no output */
+ : "r" (mreg), "r" (mxcc_creg),
+ "r" (MXCC_CREG), "i" (ASI_M_MMUREGS),
+ "i" (ASI_M_MXCC)
+ : "g2", "memory", "cc");
*mregp = mreg;
*mxcc_cregp = mxcc_creg;
}
-extern __inline__ unsigned long viking_hwprobe(unsigned long vaddr)
+static inline unsigned long viking_hwprobe(unsigned long vaddr)
{
unsigned long val;
vaddr &= PAGE_MASK;
/* Probe all MMU entries. */
- __asm__ __volatile__("lda [%1] %2, %0\n\t" :
- "=r" (val) :
- "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+ __asm__ __volatile__("lda [%1] %2, %0\n\t"
+ : "=r" (val)
+ : "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
if (!val)
return 0;
/* Probe region. */
- __asm__ __volatile__("lda [%1] %2, %0\n\t" :
- "=r" (val) :
- "r" (vaddr | 0x200), "i" (ASI_M_FLUSH_PROBE));
+ __asm__ __volatile__("lda [%1] %2, %0\n\t"
+ : "=r" (val)
+ : "r" (vaddr | 0x200), "i" (ASI_M_FLUSH_PROBE));
if ((val & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
vaddr &= ~SRMMU_PGDIR_MASK;
vaddr >>= PAGE_SHIFT;
@@ -221,9 +232,9 @@ extern __inline__ unsigned long viking_hwprobe(unsigned long vaddr)
}
/* Probe segment. */
- __asm__ __volatile__("lda [%1] %2, %0\n\t" :
- "=r" (val) :
- "r" (vaddr | 0x100), "i" (ASI_M_FLUSH_PROBE));
+ __asm__ __volatile__("lda [%1] %2, %0\n\t"
+ : "=r" (val)
+ : "r" (vaddr | 0x100), "i" (ASI_M_FLUSH_PROBE));
if ((val & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
vaddr &= ~SRMMU_PMD_MASK;
vaddr >>= PAGE_SHIFT;
@@ -231,9 +242,9 @@ extern __inline__ unsigned long viking_hwprobe(unsigned long vaddr)
}
/* Probe page. */
- __asm__ __volatile__("lda [%1] %2, %0\n\t" :
- "=r" (val) :
- "r" (vaddr), "i" (ASI_M_FLUSH_PROBE));
+ __asm__ __volatile__("lda [%1] %2, %0\n\t"
+ : "=r" (val)
+ : "r" (vaddr), "i" (ASI_M_FLUSH_PROBE));
return val;
}
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
index ba0ba0c23132..914d98371eec 100644
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -1,14 +1,15 @@
/*
- * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
+ * Copyright 2001-2003 Pavel Machek <pavel@suse.cz>
* Based on code
* Copyright 2001 Patrick Mochel <mochel@osdl.org>
*/
#include <asm/desc.h>
#include <asm/i387.h>
-static inline void
+static inline int
arch_prepare_suspend(void)
{
+ return 0;
}
/* Image of the saved processor state. If you touch this, fix acpi_wakeup.S. */
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index cc942f675ae9..8d4d0e397ed5 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -307,14 +307,14 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data);
*
* get_eeprom:
* Should fill in the magic field. Don't need to check len for zero
- * or wraparound but must check offset + len < size. Fill in the data
- * argument with the eeprom values from offset to offset + len. Update
- * len to the amount read. Returns an error or zero.
+ * or wraparound. Fill in the data argument with the eeprom values
+ * from offset to offset + len. Update len to the amount read.
+ * Returns an error or zero.
*
* set_eeprom:
* Should validate the magic field. Don't need to check len for zero
- * or wraparound but must check offset + len < size. Update len to
- * the amount written. Returns an error or zero.
+ * or wraparound. Update len to the amount written. Returns an error
+ * or zero.
*/
struct ethtool_ops {
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
@@ -328,6 +328,7 @@ struct ethtool_ops {
void (*set_msglevel)(struct net_device *, u32);
int (*nway_reset)(struct net_device *);
u32 (*get_link)(struct net_device *);
+ int (*get_eeprom_len)(struct net_device *);
int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index 2e9a2c8e4fdd..e1a49dca4abb 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -1,14 +1,14 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
- * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
+ * Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
- * $Id: jffs2.h,v 1.30 2003/02/15 00:15:22 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
*
*/
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index 246ff237325c..ee80d2520afb 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.37 2003/01/17 16:04:44 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.45 2003/10/08 11:46:27 dwmw2 Exp $ */
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
@@ -15,6 +15,8 @@
#define JFFS2_SB_FLAG_RO 1
#define JFFS2_SB_FLAG_MOUNTING 2
+struct jffs2_inodirty;
+
/* A struct for the overall file system control. Pointers to
jffs2_sb_info structs are named `c' in the source code.
Nee jffs_control
@@ -52,6 +54,15 @@ struct jffs2_sb_info {
uint32_t nr_free_blocks;
uint32_t nr_erasing_blocks;
+ /* Number of free blocks there must be before we... */
+ uint8_t resv_blocks_write; /* ... allow a normal filesystem write */
+ uint8_t resv_blocks_deletion; /* ... allow a normal filesystem deletion */
+ uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */
+ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */
+ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */
+
+ uint32_t nospc_dirty_size;
+
uint32_t nr_blocks;
struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks
* from the offset (blocks[ofs / sector_size]) */
@@ -84,13 +95,20 @@ struct jffs2_sb_info {
to an obsoleted node. I don't like this. Alternatives welcomed. */
struct semaphore erase_free_sem;
+#ifdef CONFIG_JFFS2_FS_NAND
/* Write-behind buffer for NAND flash */
unsigned char *wbuf;
uint32_t wbuf_ofs;
uint32_t wbuf_len;
uint32_t wbuf_pagesize;
- struct work_struct wbuf_task; /* task for timed wbuf flush */
- struct timer_list wbuf_timer; /* timer for flushing wbuf */
+ struct jffs2_inodirty *wbuf_inodes;
+
+ /* Information about out-of-band area usage... */
+ struct nand_oobinfo *oobinfo;
+ uint32_t badblock_pos;
+ uint32_t fsdata_pos;
+ uint32_t fsdata_len;
+#endif
/* OS-private pointer for getting back to master superblock info */
void *os_priv;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 03936a77f3da..2a53de551b53 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -511,7 +511,11 @@ extern struct net_device *__dev_get_by_flags(unsigned short flags,
unsigned short mask);
extern struct net_device *dev_get_by_name(const char *name);
extern struct net_device *__dev_get_by_name(const char *name);
-extern struct net_device *dev_alloc(const char *name, int *err);
+extern struct net_device *__dev_alloc(const char *name, int *err);
+static inline __deprecated struct net_device *dev_alloc(const char *name, int *err)
+{
+ return __dev_alloc(name, err);
+}
extern int dev_alloc_name(struct net_device *dev, const char *name);
extern int dev_open(struct net_device *dev);
extern int dev_close(struct net_device *dev);
diff --git a/include/linux/netfilter_bridge/ebt_among.h b/include/linux/netfilter_bridge/ebt_among.h
new file mode 100644
index 000000000000..307c1fed8511
--- /dev/null
+++ b/include/linux/netfilter_bridge/ebt_among.h
@@ -0,0 +1,65 @@
+#ifndef __LINUX_BRIDGE_EBT_AMONG_H
+#define __LINUX_BRIDGE_EBT_AMONG_H
+
+#define EBT_AMONG_DST 0x01
+#define EBT_AMONG_SRC 0x02
+
+/* Grzegorz Borowiak <grzes@gnu.univ.gda.pl> 2003
+ *
+ * Write-once-read-many hash table, used for checking if a given
+ * MAC address belongs to a set or not and possibly for checking
+ * if it is related with a given IPv4 address.
+ *
+ * The hash value of an address is its last byte.
+ *
+ * In real-world ethernet addresses, values of the last byte are
+ * evenly distributed and there is no need to consider other bytes.
+ * It would only slow the routines down.
+ *
+ * For MAC address comparison speedup reasons, we introduce a trick.
+ * MAC address is mapped onto an array of two 32-bit integers.
+ * This pair of integers is compared with MAC addresses in the
+ * hash table, which are stored also in form of pairs of integers
+ * (in `cmp' array). This is quick as it requires only two elementary
+ * number comparisons in worst case. Further, we take advantage of
+ * fact that entropy of 3 last bytes of address is larger than entropy
+ * of 3 first bytes. So first we compare 4 last bytes of addresses and
+ * if they are the same we compare 2 first.
+ *
+ * Yes, it is a memory overhead, but in 2003 AD, who cares?
+ */
+
+struct ebt_mac_wormhash_tuple
+{
+ uint32_t cmp[2];
+ uint32_t ip;
+};
+
+struct ebt_mac_wormhash
+{
+ int table[257];
+ int poolsize;
+ struct ebt_mac_wormhash_tuple pool[0];
+};
+
+#define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \
+ + (x)->poolsize * sizeof(struct ebt_mac_wormhash_tuple) : 0)
+
+struct ebt_among_info
+{
+ int wh_dst_ofs;
+ int wh_src_ofs;
+ int bitmask;
+};
+
+#define EBT_AMONG_DST_NEG 0x1
+#define EBT_AMONG_SRC_NEG 0x2
+
+#define ebt_among_wh_dst(x) ((x)->wh_dst_ofs ? \
+ (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_dst_ofs) : NULL)
+#define ebt_among_wh_src(x) ((x)->wh_src_ofs ? \
+ (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_src_ofs) : NULL)
+
+#define EBT_AMONG_MATCH "among"
+
+#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a7a92f6a70da..4241be4f518f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -541,6 +541,16 @@ union thread_union {
unsigned long stack[INIT_THREAD_SIZE/sizeof(long)];
};
+#ifndef __HAVE_ARCH_KSTACK_END
+static inline int kstack_end(void *addr)
+{
+ /* Reliable end of stack detection:
+ * Some APM bios versions misalign the stack
+ */
+ return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*)));
+}
+#endif
+
extern union thread_union init_thread_union;
extern struct task_struct init_task;
@@ -576,6 +586,19 @@ extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
+
+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ ret = dequeue_signal(tsk, mask, info);
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+ return ret;
+}
+
extern void block_all_signals(int (*notifier)(void *priv), void *priv,
sigset_t *mask);
extern void unblock_all_signals(void);
@@ -673,6 +696,7 @@ extern NORET_TYPE void do_group_exit(int);
extern void reparent_to_init(void);
extern void daemonize(const char *, ...);
extern int allow_signal(int);
+extern int disallow_signal(int);
extern task_t *child_reaper;
extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
diff --git a/include/net/syncppp.h b/include/net/syncppp.h
index f2032606419e..614cb6ba564e 100644
--- a/include/net/syncppp.h
+++ b/include/net/syncppp.h
@@ -59,8 +59,9 @@ struct ppp_device
static inline struct sppp *sppp_of(struct net_device *dev)
{
- struct ppp_device *ppp = dev->priv;
- return &ppp->sppp;
+ struct ppp_device **ppp = dev->priv;
+ BUG_ON((*ppp)->dev != dev);
+ return &(*ppp)->sppp;
}
#define PP_KEEPALIVE 0x01 /* use keepalive protocol */
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index a800891d2139..9a0ab579ae4f 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -9,6 +9,8 @@
#include "do_mounts.h"
+unsigned long initrd_start, initrd_end;
+int initrd_below_start_ok;
unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */
static int __initdata old_fd, root_fd;
static int __initdata mount_initrd = 1;
@@ -99,18 +101,20 @@ static void __init handle_initrd(void)
int __init initrd_load(void)
{
- if (!mount_initrd)
- return 0;
-
- create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, 0), NULL);
- create_dev("/dev/initrd", MKDEV(RAMDISK_MAJOR, INITRD_MINOR), NULL);
- /* Load the initrd data into /dev/ram0. Execute it as initrd unless
- * /dev/ram0 is supposed to be our actual root device, in
- * that case the ram disk is just set up here, and gets
- * mounted in the normal path. */
- if (rd_load_image("/dev/initrd") && ROOT_DEV != Root_RAM0) {
- handle_initrd();
- return 1;
+ if (mount_initrd) {
+ create_dev("/dev/ram", Root_RAM0, NULL);
+ /*
+ * Load the initrd data into /dev/ram0. Execute it as initrd
+ * unless /dev/ram0 is supposed to be our actual root device,
+ * in that case the ram disk is just set up here, and gets
+ * mounted in the normal path.
+ */
+ if (rd_load_image("/dev/initrd") && ROOT_DEV != Root_RAM0) {
+ sys_unlink("/dev/initrd");
+ handle_initrd();
+ return 1;
+ }
}
+ sys_unlink("/dev/initrd");
return 0;
}
diff --git a/init/initramfs.c b/init/initramfs.c
index 5a9f5b3b05f7..42eda038009f 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -8,9 +8,11 @@
#include <linux/delay.h>
#include <linux/string.h>
+static __initdata char *message;
static void __init error(char *x)
{
- panic("populate_root: %s\n", x);
+ if (!message)
+ message = x;
}
static void __init *malloc(int size)
@@ -63,7 +65,7 @@ static char __init *find_link(int major, int minor, int ino, char *name)
}
q = (struct hash *)malloc(sizeof(struct hash));
if (!q)
- error("can't allocate link hash entry");
+ panic("can't allocate link hash entry");
q->ino = ino;
q->minor = minor;
q->major = major;
@@ -119,7 +121,7 @@ static void __init parse_header(char *s)
/* FSM */
-enum state {
+static __initdata enum state {
Start,
Collect,
GotHeader,
@@ -130,9 +132,11 @@ enum state {
Reset
} state, next_state;
-char *victim;
-unsigned count;
-loff_t this_header, next_header;
+static __initdata char *victim;
+static __initdata unsigned count;
+static __initdata loff_t this_header, next_header;
+
+static __initdata int dry_run;
static inline void eat(unsigned n)
{
@@ -185,23 +189,30 @@ static int __init do_collect(void)
static int __init do_header(void)
{
+ if (memcmp(collected, "070701", 6)) {
+ error("no cpio magic");
+ return 1;
+ }
parse_header(collected);
next_header = this_header + N_ALIGN(name_len) + body_len;
next_header = (next_header + 3) & ~3;
+ if (dry_run) {
+ read_into(name_buf, N_ALIGN(name_len), GotName);
+ return 0;
+ }
+ state = SkipIt;
if (name_len <= 0 || name_len > PATH_MAX)
- state = SkipIt;
- else if (S_ISLNK(mode)) {
+ return 0;
+ if (S_ISLNK(mode)) {
if (body_len > PATH_MAX)
- state = SkipIt;
- else {
- collect = collected = symlink_buf;
- remains = N_ALIGN(name_len) + body_len;
- next_state = GotSymlink;
- state = Collect;
- }
- } else if (body_len && !S_ISREG(mode))
- state = SkipIt;
- else
+ return 0;
+ collect = collected = symlink_buf;
+ remains = N_ALIGN(name_len) + body_len;
+ next_state = GotSymlink;
+ state = Collect;
+ return 0;
+ }
+ if (S_ISREG(mode) || !body_len)
read_into(name_buf, N_ALIGN(name_len), GotName);
return 0;
}
@@ -248,6 +259,8 @@ static int __init do_name(void)
next_state = Reset;
return 0;
}
+ if (dry_run)
+ return 0;
if (S_ISREG(mode)) {
if (maybe_link() >= 0) {
wfd = sys_open(collected, O_WRONLY|O_CREAT, mode);
@@ -268,8 +281,7 @@ static int __init do_name(void)
sys_chown(collected, uid, gid);
sys_chmod(collected, mode);
}
- } else
- panic("populate_root: bogus mode: %o\n", mode);
+ }
return 0;
}
@@ -323,13 +335,14 @@ static int __init write_buffer(char *buf, unsigned len)
static void __init flush_buffer(char *buf, unsigned len)
{
int written;
- while ((written = write_buffer(buf, len)) < len) {
+ if (message)
+ return;
+ while ((written = write_buffer(buf, len)) < len && !message) {
char c = buf[written];
if (c == '0') {
buf += written;
len -= written;
state = Start;
- continue;
} else
error("junk in compressed archive");
}
@@ -408,18 +421,20 @@ static void __init flush_window(void)
outcnt = 0;
}
-static void __init unpack_to_rootfs(char *buf, unsigned len)
+char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
{
int written;
+ dry_run = check_only;
header_buf = malloc(110);
symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1);
name_buf = malloc(N_ALIGN(PATH_MAX));
window = malloc(WSIZE);
if (!window || !header_buf || !symlink_buf || !name_buf)
- error("can't allocate buffers");
+ panic("can't allocate buffers");
state = Start;
this_header = 0;
- while (len) {
+ message = NULL;
+ while (!message && len) {
loff_t saved_offset = this_header;
if (*buf == '0' && !(this_header & 3)) {
state = Start;
@@ -427,7 +442,8 @@ static void __init unpack_to_rootfs(char *buf, unsigned len)
buf += written;
len -= written;
continue;
- } else if (!*buf) {
+ }
+ if (!*buf) {
buf++;
len--;
this_header++;
@@ -442,7 +458,7 @@ static void __init unpack_to_rootfs(char *buf, unsigned len)
crc = (ulg)0xffffffffL; /* shift register contents */
makecrc();
if (gunzip())
- error("ungzip failed");
+ message = "ungzip failed";
if (state != Reset)
error("junk in gzipped archive");
this_header = saved_offset + inptr;
@@ -453,12 +469,41 @@ static void __init unpack_to_rootfs(char *buf, unsigned len)
free(name_buf);
free(symlink_buf);
free(header_buf);
+ return message;
}
extern char __initramfs_start, __initramfs_end;
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/initrd.h>
+#endif
void __init populate_rootfs(void)
{
- unpack_to_rootfs(&__initramfs_start,
- &__initramfs_end - &__initramfs_start);
+ cha