From fa3b5fb5766db3d19e7e9a3258d87260dc601f36 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 11 Jul 2003 02:13:09 +0000 Subject: [PATCH] Merge with 2.5.75. --- CREDITS | 16 +- Documentation/Changes | 13 + Documentation/SubmittingDrivers | 2 +- Documentation/SubmittingPatches | 2 +- Documentation/cpu-freq/user-guide.txt | 16 + Documentation/eisa.txt | 60 +- Documentation/filesystems/Locking | 6 +- Documentation/filesystems/jfs.txt | 9 + Documentation/filesystems/xfs.txt | 67 +- Documentation/oops-tracing.txt | 2 +- Documentation/pci.txt | 12 +- Documentation/usb/CREDITS | 2 +- MAINTAINERS | 26 +- Makefile | 2 +- README | 6 +- arch/alpha/mm/numa.c | 4 +- arch/arm/mm/init.c | 4 +- arch/arm26/Config.help | 387 --- arch/arm26/Kconfig | 156 +- arch/arm26/config.in | 151 -- arch/arm26/kernel/Makefile | 2 +- arch/arm26/kernel/arch.c | 30 - arch/arm26/kernel/asm-offsets.c | 2 +- arch/arm26/kernel/compat.c | 2 +- arch/arm26/kernel/dma.c | 2 +- arch/arm26/kernel/ecard.c | 20 +- arch/arm26/kernel/irq.c | 9 +- arch/arm26/kernel/process.c | 4 +- arch/arm26/kernel/setup.c | 73 +- arch/arm26/kernel/traps.c | 7 +- arch/arm26/lib/Makefile | 15 +- arch/arm26/machine/Makefile | 2 +- arch/arm26/machine/arch.c | 36 - arch/arm26/machine/irq.c | 4 +- arch/arm26/mm/init.c | 6 +- arch/arm26/mm/mm-memc.c | 2 - arch/cris/Kconfig | 885 ++----- arch/cris/Makefile | 74 +- arch/cris/{ => arch-v10}/Kconfig | 264 +- arch/cris/{ => arch-v10}/README.mm | 4 +- arch/cris/{ => arch-v10}/boot/Makefile | 0 arch/cris/{ => arch-v10}/boot/compressed/Makefile | 0 arch/cris/{ => arch-v10}/boot/compressed/README | 2 +- .../{ => arch-v10}/boot/compressed/decompress.ld | 1 + arch/cris/{ => arch-v10}/boot/compressed/head.S | 2 +- arch/cris/{ => arch-v10}/boot/compressed/misc.c | 8 +- arch/cris/{ => arch-v10}/boot/rescue/Makefile | 0 arch/cris/{ => arch-v10}/boot/rescue/head.S | 10 +- .../cris/{ => arch-v10}/boot/rescue/kimagerescue.S | 2 +- arch/cris/{ => arch-v10}/boot/rescue/rescue.ld | 0 arch/cris/{ => arch-v10}/boot/rescue/testrescue.S | 2 +- arch/cris/{ => arch-v10}/boot/tools/build.c | 0 arch/cris/{ => arch-v10}/defconfig | 0 arch/cris/{ => arch-v10}/drivers/Kconfig | 749 +++--- arch/cris/{ => arch-v10}/drivers/Makefile | 8 +- arch/cris/arch-v10/drivers/axisflashmap.c | 541 +++++ arch/cris/{ => arch-v10}/drivers/ds1302.c | 177 +- arch/cris/{ => arch-v10}/drivers/eeprom.c | 57 +- arch/cris/{ => arch-v10}/drivers/ethernet.c | 686 ++++-- arch/cris/arch-v10/drivers/gpio.c | 907 +++++++ arch/cris/{ => arch-v10}/drivers/i2c.c | 204 +- arch/cris/{ => arch-v10}/drivers/i2c.h | 2 +- arch/cris/arch-v10/drivers/pcf8563.c | 287 +++ arch/cris/{ => arch-v10}/drivers/serial.c | 1597 ++++++++----- arch/cris/{ => arch-v10}/drivers/serial.h | 19 +- arch/cris/arch-v10/kernel/Makefile | 16 + arch/cris/arch-v10/kernel/asm-offsets.c | 47 + arch/cris/{ => arch-v10}/kernel/debugport.c | 137 +- arch/cris/{ => arch-v10}/kernel/entry.S | 453 ++-- arch/cris/arch-v10/kernel/fasttimer.c | 996 ++++++++ arch/cris/{ => arch-v10}/kernel/head.S | 40 +- arch/cris/arch-v10/kernel/irq.c | 219 ++ arch/cris/{ => arch-v10}/kernel/kgdb.c | 20 +- arch/cris/arch-v10/kernel/process.c | 252 ++ arch/cris/{ => arch-v10}/kernel/ptrace.c | 212 +- arch/cris/arch-v10/kernel/setup.c | 96 + arch/cris/{ => arch-v10}/kernel/shadows.c | 2 +- arch/cris/{ => arch-v10}/kernel/signal.c | 52 +- arch/cris/{ => arch-v10}/kernel/time.c | 331 +-- arch/cris/arch-v10/kernel/traps.c | 132 + arch/cris/{ => arch-v10}/lib/Makefile | 2 + arch/cris/{ => arch-v10}/lib/checksum.S | 2 +- arch/cris/{ => arch-v10}/lib/checksumcopy.S | 2 +- arch/cris/{ => arch-v10}/lib/csumcpfruser.S | 0 arch/cris/{ => arch-v10}/lib/dmacopy.c | 2 +- arch/cris/{ => arch-v10}/lib/dram_init.S | 35 +- arch/cris/{ => arch-v10}/lib/hw_settings.S | 2 +- arch/cris/{ => arch-v10}/lib/memset.c | 0 arch/cris/{ => arch-v10}/lib/old_checksum.c | 4 +- arch/cris/{ => arch-v10}/lib/string.c | 0 arch/cris/{ => arch-v10}/lib/usercopy.c | 166 +- arch/cris/{ => arch-v10}/mm/Makefile | 3 +- arch/cris/arch-v10/mm/fault.c | 175 ++ arch/cris/arch-v10/mm/init.c | 265 +++ arch/cris/{ => arch-v10}/mm/tlb.c | 159 +- arch/cris/arch-v10/output_arch.ld | 2 + arch/cris/{ => arch-v10}/vmlinux.lds.S | 36 +- arch/cris/defconfig | 80 - arch/cris/drivers/axisflashmap.c | 361 --- arch/cris/drivers/bluetooth/Makefile | 25 - arch/cris/drivers/gpio.c | 460 ---- arch/cris/drivers/ide.c | 877 ------- arch/cris/drivers/lpslave/Makefile | 15 - arch/cris/drivers/lpslave/bintocarr.pl | 30 - arch/cris/drivers/lpslave/e100lpslave.README | 54 - arch/cris/drivers/lpslave/e100lpslave.S | 429 ---- arch/cris/drivers/lpslave/e100lpslave.h | 2 - arch/cris/drivers/lpslave/e100lpslaveld | 22 - arch/cris/drivers/lpslave/e100lpslavenet.c | 1012 -------- arch/cris/drivers/parport.c | 572 ----- arch/cris/drivers/sync_serial.c | 900 ------- arch/cris/drivers/usb-host.c | 2516 -------------------- arch/cris/drivers/usb-host.h | 243 -- arch/cris/kernel/Makefile | 34 +- arch/cris/kernel/entryoffsets.c | 62 - arch/cris/kernel/irq.c | 284 +-- arch/cris/kernel/ksyms.c | 19 +- arch/cris/kernel/module.c | 106 + arch/cris/kernel/process.c | 304 +-- arch/cris/kernel/ptrace.c | 443 +--- arch/cris/kernel/setup.c | 132 +- arch/cris/kernel/sys_cris.c | 34 +- arch/cris/kernel/time.c | 696 ++---- arch/cris/kernel/traps.c | 143 +- arch/cris/mm/Makefile | 1 + arch/cris/mm/extable.c | 111 +- arch/cris/mm/fault.c | 174 +- arch/cris/mm/init.c | 700 ++---- arch/cris/mm/ioremap.c | 18 +- arch/cris/mm/tlb.c | 473 +--- arch/i386/Kconfig | 8 + arch/i386/kernel/cpu/common.c | 10 +- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 4 +- arch/i386/kernel/entry.S | 1 + arch/i386/kernel/io_apic.c | 2 +- arch/i386/kernel/irq.c | 3 +- arch/i386/kernel/nmi.c | 2 - arch/i386/kernel/time.c | 29 +- arch/i386/kernel/timers/timer.c | 15 +- arch/i386/kernel/timers/timer_cyclone.c | 4 +- arch/i386/kernel/timers/timer_tsc.c | 17 +- arch/i386/lib/delay.c | 2 +- arch/i386/mm/pageattr.c | 82 +- arch/i386/mm/pgtable.c | 2 +- arch/i386/oprofile/init.c | 2 +- arch/i386/oprofile/op_model_p4.c | 2 +- arch/i386/pci/direct.c | 2 +- arch/i386/pci/irq.c | 16 +- arch/i386/pci/legacy.c | 26 +- arch/ia64/Kconfig | 27 - arch/ia64/hp/common/sba_iommu.c | 4 +- arch/ia64/hp/sim/hpsim_irq.c | 2 +- arch/ia64/hp/sim/simscsi.c | 1 + arch/ia64/ia32/binfmt_elf32.c | 3 +- arch/ia64/ia32/sys_ia32.c | 33 +- arch/ia64/kernel/entry.S | 2 +- arch/ia64/kernel/entry.h | 1 - arch/ia64/kernel/fsys.S | 4 +- arch/ia64/kernel/ptrace.c | 36 +- arch/ia64/kernel/sys_ia64.c | 34 +- arch/ia64/kernel/unwind.c | 19 +- arch/ia64/mm/init.c | 6 +- arch/ia64/pci/pci.c | 33 +- arch/ia64/sn/io/Makefile | 2 +- arch/ia64/sn/io/ate_utils.c | 204 -- arch/ia64/sn/io/hwgfs/ramfs.c | 2 +- arch/ia64/sn/io/machvec/iomv.c | 4 + arch/ia64/sn/io/machvec/pci_dma.c | 15 +- arch/ia64/sn/io/sgi_if.c | 40 - arch/ia64/sn/io/sn2/Makefile | 2 +- arch/ia64/sn/io/sn2/l1.c | 293 --- arch/ia64/sn/io/sn2/module.c | 15 - arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c | 70 +- arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c | 113 +- arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c | 5 - arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c | 12 +- arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c | 23 +- arch/ia64/sn/io/sn2/pciio.c | 165 +- arch/ia64/sn/io/sn2/shub.c | 6 +- arch/ia64/sn/io/sn2/shuberror.c | 2 +- arch/ia64/sn/kernel/irq.c | 3 + arch/ia64/sn/kernel/setup.c | 12 +- arch/ia64/sn/kernel/sn2/prominfo_proc.c | 4 + arch/ia64/vmlinux.lds.S | 2 +- arch/m68knommu/Kconfig | 20 +- arch/m68knommu/kernel/time.c | 3 +- arch/m68knommu/platform/5282/config.c | 2 +- arch/m68knommu/platform/5282/pit.c | 2 +- arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S | 7 + arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S | 8 + arch/m68knommu/platform/5307/MP3/crt0_ram.S | 8 + arch/m68knommu/platform/5307/NETtel/crt0_ram.S | 8 + arch/m68knommu/platform/5307/ints.c | 13 +- arch/m68knommu/platform/68328/ints.c | 4 +- arch/m68knommu/platform/68360/config.c | 5 - arch/m68knommu/platform/68VZ328/de2/config.c | 14 +- arch/m68knommu/vmlinux.lds.S | 4 +- arch/mips/au1000/common/time.c | 9 +- arch/mips/baget/irq.c | 4 +- arch/mips/defconfig-lasat200 | 2 +- arch/mips/galileo-boards/ev96100/time.c | 2 +- arch/mips/kernel/irq.c | 2 +- arch/mips/kernel/offset.c | 2 - arch/mips/kernel/syscalls.h | 1 + arch/mips/kernel/sysirix.c | 5 +- arch/mips/kernel/time.c | 10 +- arch/mips/lasat/interrupt.c | 2 +- arch/mips/mips-boards/sead/sead_time.c | 4 +- arch/mips/sgi-ip22/ip22-int.c | 2 +- arch/mips/sgi-ip22/ip22-time.c | 7 +- arch/mips/sgi-ip27/ip27-timer.c | 5 +- arch/mips/sgi-ip32/ip32-timer.c | 2 +- arch/mips/sibyte/sb1250/irq.c | 2 +- arch/mips/sibyte/sb1250/smp.c | 2 +- arch/mips64/kernel/irq.c | 2 +- arch/mips64/kernel/offset.c | 2 - arch/mips64/kernel/scall_64.S | 19 +- arch/mips64/kernel/scall_n32.S | 19 +- arch/mips64/kernel/scall_o32.S | 1 + arch/mips64/kernel/time.c | 10 +- arch/parisc/kernel/smp.c | 2 +- arch/parisc/oprofile/init.c | 2 +- arch/ppc/Kconfig | 25 +- arch/ppc/boot/common/Makefile | 3 +- arch/ppc/boot/common/ns16550.c | 5 - arch/ppc/boot/common/serial_stub.c | 28 + arch/ppc/boot/simple/Makefile | 33 +- arch/ppc/boot/simple/direct.S | 15 - arch/ppc/boot/simple/m8260_tty.c | 5 - arch/ppc/boot/simple/m8xx_tty.c | 5 - arch/ppc/configs/adir_defconfig | 2 - arch/ppc/configs/apus_defconfig | 2 - arch/ppc/configs/common_defconfig | 2 - arch/ppc/configs/ev64260_defconfig | 2 - arch/ppc/configs/gemini_defconfig | 2 - arch/ppc/configs/ibmchrp_defconfig | 2 - arch/ppc/configs/k2_defconfig | 2 - arch/ppc/configs/lopec_defconfig | 2 - arch/ppc/configs/mcpn765_defconfig | 2 - arch/ppc/configs/menf1_defconfig | 1 - arch/ppc/configs/mvme5100_defconfig | 2 - arch/ppc/configs/pcore_defconfig | 2 - arch/ppc/configs/pmac_defconfig | 2 - arch/ppc/configs/power3_defconfig | 2 - arch/ppc/configs/pplus_defconfig | 2 - arch/ppc/configs/prpmc750_defconfig | 2 - arch/ppc/configs/prpmc800_defconfig | 2 - arch/ppc/configs/sandpoint_defconfig | 24 +- arch/ppc/configs/spruce_defconfig | 2 - arch/ppc/configs/zx4500_defconfig | 560 ----- arch/ppc/defconfig | 2 - arch/ppc/kernel/ppc-stub.c | 10 - arch/ppc/kernel/ppc_ksyms.c | 2 + arch/ppc/kernel/setup.c | 2 + arch/ppc/platforms/Makefile | 3 +- arch/ppc/platforms/menf1.h | 24 - arch/ppc/platforms/menf1_pci.c | 98 - arch/ppc/platforms/menf1_setup.c | 283 --- arch/ppc/platforms/sandpoint.c | 719 ++++++ arch/ppc/platforms/sandpoint.h | 56 +- arch/ppc/platforms/sandpoint_pci.c | 181 -- arch/ppc/platforms/sandpoint_serial.h | 49 - arch/ppc/platforms/sandpoint_setup.c | 643 ----- arch/ppc/platforms/zx4500.h | 68 - arch/ppc/platforms/zx4500_pci.c | 138 -- arch/ppc/platforms/zx4500_serial.h | 46 - arch/ppc/platforms/zx4500_setup.c | 359 --- arch/ppc/syslib/Makefile | 7 +- arch/ppc/syslib/gen550_dbg.c | 174 ++ arch/ppc/syslib/gen550_kgdb.c | 84 + arch/ppc/syslib/open_pic.c | 106 +- arch/ppc64/mm/init.c | 4 +- arch/ppc64/mm/numa.c | 16 +- arch/ppc64/oprofile/init.c | 2 +- arch/s390/kernel/compat_exec.c | 3 +- arch/s390/kernel/setup.c | 2 +- arch/sh/kernel/cpu/sh4/pci-sh7751.c | 2 +- arch/sparc64/Kconfig | 7 + arch/sparc64/boot/Makefile | 6 +- arch/sparc64/kernel/irq.c | 4 +- arch/sparc64/kernel/process.c | 2 + arch/sparc64/kernel/smp.c | 2 +- arch/sparc64/kernel/sparc64_ksyms.c | 13 + arch/sparc64/kernel/traps.c | 5 +- arch/sparc64/lib/Makefile | 2 +- .../asm-sparc64/xor.h => arch/sparc64/lib/xor.S | 54 +- arch/sparc64/oprofile/init.c | 2 +- arch/um/kernel/process_kern.c | 3 +- arch/x86_64/ia32/ia32_binfmt.c | 4 +- arch/x86_64/kernel/setup64.c | 2 +- arch/x86_64/mm/init.c | 2 +- arch/x86_64/mm/numa.c | 2 +- drivers/acpi/sleep/main.c | 2 +- drivers/base/class.c | 20 + drivers/base/firmware_class.c | 4 +- drivers/block/Makefile | 8 +- drivers/block/as-iosched.c | 1837 ++++++++++++++ drivers/block/cciss.c | 5 +- drivers/block/elevator.c | 33 +- drivers/block/floppy.c | 2 +- drivers/block/genhd.c | 4 +- drivers/block/ll_rw_blk.c | 499 +++- drivers/char/agp/amd-k8-agp.c | 8 + drivers/char/agp/via-agp.c | 55 +- drivers/char/pcmcia/synclink_cs.c | 24 +- drivers/char/synclink.c | 21 +- drivers/char/synclinkmp.c | 25 +- drivers/cpufreq/Makefile | 7 +- drivers/cpufreq/proc_intf.c | 2 + drivers/eisa/eisa-bus.c | 234 +- drivers/eisa/eisa.ids | 6 + drivers/eisa/pci_eisa.c | 3 +- drivers/eisa/virtual_root.c | 15 + drivers/ide/ide-probe.c | 20 +- drivers/ide/ppc/pmac.c | 2 + drivers/ieee1394/sbp2.c | 2 + drivers/macintosh/macserial.c | 19 +- drivers/message/i2o/i2o_scsi.c | 1 + drivers/mtd/mtd_blkdevs.c | 3 +- drivers/net/8139too.c | 2 +- drivers/net/e100/e100_main.c | 4 +- drivers/net/e1000/e1000.h | 1 - drivers/net/e1000/e1000_ethtool.c | 5 +- drivers/net/e1000/e1000_hw.c | 59 +- drivers/net/e1000/e1000_hw.h | 18 + drivers/net/e1000/e1000_main.c | 186 +- drivers/net/irda/irtty-sir.c | 30 +- drivers/net/irda/sir_dev.c | 22 +- drivers/net/irda/sir_kthread.c | 45 +- drivers/net/ppp_generic.c | 6 +- drivers/net/sunhme.c | 6 + drivers/net/via-rhine.c | 36 +- drivers/net/wan/comx.c | 4 +- drivers/net/wan/hdlc_generic.c | 7 +- drivers/parisc/eisa.c | 24 +- drivers/parisc/eisa_enumerator.c | 9 +- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/cpci_hotplug_pci.c | 2 +- drivers/pci/hotplug/ibmphp_core.c | 6 +- drivers/pci/pci-sysfs.c | 105 + drivers/pci/pci.h | 1 - drivers/pci/probe.c | 25 +- drivers/pci/search.c | 30 +- drivers/pnp/interface.c | 22 +- drivers/pnp/manager.c | 37 +- drivers/pnp/resource.c | 8 + drivers/pnp/support.c | 24 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_scan.c | 2 +- drivers/serial/68328serial.c | 1 - drivers/serial/8250_cs.c | 2 +- drivers/serial/core.c | 6 +- drivers/serial/mcfserial.c | 1 - fs/adfs/adfs.h | 2 +- fs/adfs/dir.c | 2 +- fs/affs/namei.c | 4 +- fs/afs/dir.c | 10 +- fs/afs/mntpt.c | 4 +- fs/aio.c | 2 +- fs/attr.c | 3 - fs/autofs/root.c | 8 +- fs/autofs4/root.c | 14 +- fs/befs/linuxvfs.c | 4 +- fs/bfs/dir.c | 5 +- fs/binfmt_flat.c | 507 ++-- fs/block_dev.c | 10 +- fs/buffer.c | 15 + fs/cifs/CHANGES | 10 + fs/cifs/Makefile | 2 +- fs/cifs/README | 146 +- fs/cifs/TODO | 22 +- fs/cifs/cifs_unicode.c | 2 +- fs/cifs/cifsencrypt.c | 140 ++ fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsfs.h | 10 +- fs/cifs/cifsglob.h | 3 + fs/cifs/cifspdu.h | 8 +- fs/cifs/cifsproto.h | 8 +- fs/cifs/cifssmb.c | 12 +- fs/cifs/connect.c | 23 +- fs/cifs/dir.c | 7 +- fs/cifs/inode.c | 6 +- fs/cifs/smbdes.c | 2 +- fs/cifs/smbencrypt.c | 121 +- fs/cifs/transport.c | 23 +- fs/cifs/xattr.c | 56 + fs/coda/dir.c | 14 +- fs/coda/file.c | 11 +- fs/coda/pioctl.c | 6 +- fs/cramfs/inode.c | 2 +- fs/devfs/base.c | 6 +- fs/dquot.c | 17 +- fs/efs/namei.c | 2 +- fs/eventpoll.c | 30 +- fs/exec.c | 57 +- fs/ext2/acl.c | 153 +- fs/ext2/acl.h | 3 +- fs/ext2/ext2.h | 10 + fs/ext2/ialloc.c | 87 +- fs/ext2/namei.c | 4 +- fs/ext2/super.c | 3 + fs/ext2/xattr.c | 240 +- fs/ext2/xattr_user.c | 16 +- fs/ext3/acl.c | 153 +- fs/ext3/acl.h | 3 +- fs/ext3/inode.c | 101 +- fs/ext3/namei.c | 5 +- fs/ext3/super.c | 3 + fs/ext3/xattr.c | 281 ++- fs/ext3/xattr_user.c | 16 +- fs/freevxfs/vxfs_lookup.c | 5 +- fs/fs-writeback.c | 2 + fs/hfs/dir.c | 2 +- fs/hfs/dir_cap.c | 4 +- fs/hfs/dir_dbl.c | 10 +- fs/hfs/dir_nat.c | 4 +- fs/hfs/sysdep.c | 4 +- fs/hpfs/dir.c | 2 +- fs/hpfs/hpfs_fn.h | 4 +- fs/hpfs/namei.c | 4 +- fs/hugetlbfs/inode.c | 2 +- fs/intermezzo/dcache.c | 2 +- fs/intermezzo/dir.c | 17 +- fs/intermezzo/file.c | 2 +- fs/intermezzo/intermezzo_fs.h | 2 +- fs/intermezzo/vfs.c | 8 +- fs/isofs/namei.c | 2 +- fs/jbd/commit.c | 21 +- fs/jbd/transaction.c | 35 +- fs/jffs/inode-v23.c | 5 +- fs/jffs2/dir.c | 9 +- fs/jfs/acl.c | 2 +- fs/jfs/inode.c | 2 +- fs/jfs/jfs_acl.h | 2 +- fs/jfs/jfs_btree.h | 2 +- fs/jfs/jfs_dmap.c | 148 +- fs/jfs/jfs_dtree.c | 40 +- fs/jfs/jfs_extent.c | 32 +- fs/jfs/jfs_filsys.h | 5 +- fs/jfs/jfs_imap.c | 111 +- fs/jfs/jfs_incore.h | 48 +- fs/jfs/jfs_logmgr.c | 58 +- fs/jfs/jfs_logmgr.h | 6 +- fs/jfs/jfs_mount.c | 45 +- fs/jfs/jfs_txnmgr.c | 12 +- fs/jfs/jfs_unicode.c | 12 +- fs/jfs/jfs_xtree.c | 36 +- fs/jfs/namei.c | 78 +- fs/jfs/resize.c | 4 +- fs/jfs/super.c | 41 +- fs/jfs/xattr.c | 32 +- fs/libfs.c | 2 +- fs/minix/namei.c | 5 +- fs/msdos/namei.c | 5 +- fs/namei.c | 93 +- fs/namespace.c | 2 +- fs/ncpfs/dir.c | 17 +- fs/ncpfs/ioctl.c | 22 +- fs/nfs/dir.c | 73 +- fs/nfs/file.c | 5 +- fs/nfsd/nfsfh.c | 2 +- fs/nfsd/vfs.c | 8 +- fs/ntfs/namei.c | 3 +- fs/open.c | 21 +- fs/openpromfs/inode.c | 9 +- fs/proc/base.c | 16 +- fs/proc/generic.c | 2 +- fs/proc/proc_misc.c | 9 +- fs/proc/root.c | 16 +- fs/qnx4/namei.c | 5 +- fs/ramfs/inode.c | 3 +- fs/reiserfs/namei.c | 5 +- fs/romfs/inode.c | 2 +- fs/smbfs/dir.c | 13 +- fs/smbfs/file.c | 2 +- fs/sysfs/bin.c | 25 +- fs/sysfs/dir.c | 22 + fs/sysfs/file.c | 9 + fs/sysv/namei.c | 4 +- fs/udf/file.c | 2 +- fs/udf/namei.c | 5 +- fs/ufs/namei.c | 5 +- fs/umsdos/dir.c | 4 +- fs/umsdos/emd.c | 2 +- fs/umsdos/namei.c | 4 +- fs/umsdos/rdir.c | 4 +- fs/vfat/namei.c | 9 +- fs/xattr.c | 4 - fs/xfs/linux/xfs_globals.c | 14 +- fs/xfs/linux/xfs_iops.c | 43 +- fs/xfs/linux/xfs_linux.h | 14 +- fs/xfs/linux/xfs_super.c | 10 +- fs/xfs/linux/xfs_syncd.c | 86 - fs/xfs/linux/xfs_sysctl.c | 40 +- fs/xfs/linux/xfs_sysctl.h | 23 +- fs/xfs/pagebuf/page_buf.c | 39 +- fs/xfs/pagebuf/page_buf_internal.h | 21 +- fs/xfs/xfs_vfsops.c | 3 - include/asm-alpha/div64.h | 15 +- include/asm-alpha/machvec.h | 2 +- include/asm-alpha/mmu_context.h | 15 +- include/asm-alpha/mmzone.h | 3 +- include/asm-arm/mmu_context.h | 4 +- include/asm-arm26/arch.h | 62 - include/asm-arm26/bug.h | 11 +- include/asm-arm26/bugs.h | 2 +- include/asm-arm26/div64.h | 15 +- include/asm-arm26/ecard.h | 3 + include/asm-arm26/mach-types.h | 1 + include/asm-arm26/mmu_context.h | 4 +- include/asm-arm26/pgalloc.h | 4 +- include/asm-arm26/pgtable.h | 2 +- include/asm-arm26/statfs.h | 21 +- include/asm-arm26/thread_info.h | 2 +- include/asm-cris/arch-v10/bitops.h | 73 + include/asm-cris/arch-v10/byteorder.h | 25 + include/asm-cris/arch-v10/cache.h | 8 + include/asm-cris/arch-v10/checksum.h | 29 + include/asm-cris/arch-v10/delay.h | 20 + include/asm-cris/{ => arch-v10}/dma.h | 21 +- include/asm-cris/{ => arch-v10}/elf.h | 70 +- include/asm-cris/{ => arch-v10}/io.h | 124 +- include/asm-cris/{ => arch-v10}/irq.h | 37 +- include/asm-cris/{ => arch-v10}/mmu.h | 48 +- include/asm-cris/arch-v10/offset.h | 33 + include/asm-cris/arch-v10/page.h | 31 + include/asm-cris/arch-v10/pgtable.h | 19 + include/asm-cris/arch-v10/processor.h | 62 + include/asm-cris/{ => arch-v10}/ptrace.h | 24 +- include/asm-cris/{ => arch-v10}/sv_addr.agh | 40 +- include/asm-cris/{ => arch-v10}/sv_addr_ag.h | 30 +- include/asm-cris/{ => arch-v10}/svinto.h | 3 + include/asm-cris/arch-v10/system.h | 62 + include/asm-cris/arch-v10/thread_info.h | 12 + include/asm-cris/arch-v10/timex.h | 30 + include/asm-cris/arch-v10/tlb.h | 13 + include/asm-cris/{ => arch-v10}/uaccess.h | 447 +--- include/asm-cris/arch-v10/unistd.h | 148 ++ include/asm-cris/arch-v10/user.h | 46 + include/asm-cris/atomic.h | 88 +- include/asm-cris/axisflashmap.h | 19 - include/asm-cris/bitops.h | 176 +- include/asm-cris/byteorder.h | 23 +- include/asm-cris/cache.h | 8 +- include/{asm-i386 => asm-cris}/cacheflush.h | 11 +- include/asm-cris/checksum.h | 35 +- include/asm-cris/current.h | 10 +- include/asm-cris/delay.h | 25 +- include/asm-cris/div64.h | 17 +- include/asm-cris/dma.h | 72 +- include/asm-cris/elf.h | 182 +- include/asm-cris/etraxgpio.h | 69 +- include/asm-cris/fasttimer.h | 42 + include/{asm-i386 => asm-cris}/hardirq.h | 21 +- include/asm-cris/hdreg.h | 11 - include/asm-cris/ide.h | 103 - include/asm-cris/io.h | 347 +-- include/asm-cris/ioctls.h | 3 + include/asm-cris/ipc.h | 1 + include/asm-cris/irq.h | 214 +- include/asm-cris/kmap_types.h | 25 + include/asm-cris/mman.h | 3 + include/asm-cris/mmu.h | 72 +- include/asm-cris/mmu_context.h | 6 +- include/asm-cris/module.h | 13 +- include/asm-cris/page.h | 90 +- include/asm-cris/param.h | 11 +- include/asm-cris/percpu.h | 6 + include/asm-cris/pgalloc.h | 182 +- include/asm-cris/pgtable.h | 279 +-- include/asm-cris/poll.h | 1 + include/asm-cris/posix_types.h | 4 +- include/asm-cris/processor.h | 225 +- include/asm-cris/ptrace.h | 130 +- include/asm-cris/rs485.h | 20 + include/asm-cris/rtc.h | 175 +- include/asm-cris/scatterlist.h | 2 + include/asm-cris/semaphore-helper.h | 24 +- include/asm-cris/semaphore.h | 28 +- include/asm-cris/setup.h | 408 +--- include/asm-cris/signal.h | 14 +- include/asm-cris/smp_lock.h | 73 - include/asm-cris/sync_serial.h | 97 - include/asm-cris/system.h | 250 +- include/asm-cris/termbits.h | 41 +- include/asm-cris/termios.h | 1 + include/asm-cris/thread_info.h | 100 + include/asm-cris/timex.h | 60 +- include/asm-cris/tlb.h | 16 + include/asm-cris/tlbflush.h | 43 + include/asm-cris/uaccess.h | 1538 ++++-------- include/{asm-i386 => asm-cris}/unistd.h | 142 +- include/asm-cris/user.h | 44 +- include/asm-generic/div64.h | 54 + include/asm-h8300/div64.h | 14 +- include/asm-h8300/flat.h | 17 +- include/asm-h8300/mmu_context.h | 4 +- include/asm-i386/cacheflush.h | 5 + include/asm-i386/hardirq.h | 2 - include/asm-i386/mmu_context.h | 11 +- include/asm-i386/mmzone.h | 5 +- include/asm-i386/timer.h | 13 + include/asm-i386/unistd.h | 3 +- include/asm-ia64/div64.h | 21 +- include/asm-ia64/mmu_context.h | 4 +- include/asm-ia64/processor.h | 2 +- include/asm-ia64/sn/ate_utils.h | 51 - include/asm-ia64/sn/clksupport.h | 7 + include/asm-ia64/sn/fetchop.h | 12 +- include/asm-ia64/sn/module.h | 3 - include/asm-ia64/sn/pci/pcibr_private.h | 11 +- include/asm-ia64/sn/pci/pciio.h | 3 +- include/asm-ia64/sn/pci/pciio_private.h | 2 +- include/asm-ia64/sn/sn2/io.h | 62 +- include/asm-ia64/sn/sn_sal.h | 79 +- include/asm-ia64/sn/systeminfo.h | 73 - include/asm-ia64/unistd.h | 2 +- include/asm-m68k/div64.h | 9 - include/asm-m68k/mmu_context.h | 6 +- include/asm-m68knommu/div64.h | 14 +- include/asm-m68knommu/flat.h | 8 +- include/asm-m68knommu/io.h | 9 +- include/asm-m68knommu/mmu_context.h | 4 +- include/asm-m68knommu/page.h | 2 +- include/asm-m68knommu/semaphore.h | 2 +- include/asm-m68knommu/uaccess.h | 21 +- include/asm-mips/cacheflush.h | 6 +- include/asm-mips/hardirq.h | 2 - include/asm-mips/mmu_context.h | 5 +- include/asm-mips/unistd.h | 3 +- include/asm-mips64/cacheflush.h | 6 +- include/asm-mips64/hardirq.h | 2 - include/asm-mips64/mmu_context.h | 5 +- include/asm-mips64/mmzone.h | 2 +- include/asm-mips64/r4kcache.h | 18 +- include/asm-mips64/unistd.h | 9 +- include/asm-parisc/div64.h | 55 +- include/asm-parisc/mmu_context.h | 6 +- include/asm-ppc/div64.h | 24 +- include/asm-ppc/mmu_context.h | 4 +- include/asm-ppc/serial.h | 4 +- include/asm-ppc64/div64.h | 19 +- include/asm-ppc64/mmu_context.h | 8 +- include/asm-ppc64/mmzone.h | 1 - include/asm-s390/div64.h | 8 +- include/asm-s390/mmu_context.h | 8 +- include/asm-sh/div64.h | 21 +- include/asm-sh/mmu_context.h | 10 +- include/asm-sparc/div64.h | 12 +- include/asm-sparc/mmu_context.h | 8 +- include/asm-sparc64/div64.h | 15 +- include/asm-sparc64/hardirq.h | 8 +- include/asm-sparc64/mmu_context.h | 6 +- include/asm-sparc64/xor.h | 438 +--- include/asm-um/mmu_context.h | 6 +- include/asm-v850/div64.h | 12 +- include/asm-v850/flat.h | 117 +- include/asm-v850/mmu_context.h | 4 +- include/asm-x86_64/div64.h | 15 +- include/asm-x86_64/mmu_context.h | 9 +- include/asm-x86_64/mmzone.h | 3 +- include/linux/acct.h | 2 +- include/linux/affs_fs.h | 4 +- include/linux/blkdev.h | 92 +- include/linux/buffer_head.h | 7 + include/linux/coda_linux.h | 2 +- include/linux/compat_ioctl.h | 2 +- include/linux/compiler.h | 18 + include/linux/cpufreq.h | 73 +- include/linux/dcache.h | 3 +- include/linux/device.h | 13 +- include/linux/efs_fs.h | 2 +- include/linux/eisa.h | 21 +- include/linux/elevator.h | 17 +- include/linux/eventpoll.h | 35 +- include/linux/ext3_fs.h | 6 +- include/linux/ext3_fs_i.h | 10 + include/linux/flat.h | 20 +- include/linux/fs.h | 14 +- include/linux/hfs_fs.h | 2 +- include/linux/interrupt.h | 4 +- include/linux/ioport.h | 1 + include/linux/irq_cpustat.h | 4 - include/linux/iso_fs.h | 2 +- include/linux/kernel_stat.h | 3 +- include/linux/kobject.h | 2 + include/linux/mm.h | 26 +- include/linux/mman.h | 3 +- include/linux/mmzone.h | 7 +- include/linux/msdos_fs.h | 8 +- include/linux/namei.h | 17 +- include/linux/netdevice.h | 8 +- include/linux/nfs_fs.h | 2 +- include/linux/pci.h | 2 +- include/linux/pci_ids.h | 1 + include/linux/proc_fs.h | 4 +- include/linux/qnx4_fs.h | 5 +- include/linux/quota.h | 10 + include/linux/sched.h | 5 + include/linux/security.h | 16 + include/linux/sem.h | 1 - include/linux/slab.h | 4 + include/linux/sysfs.h | 5 + include/linux/umsdos_fs.p | 4 +- include/linux/xfrm.h | 9 +- include/net/addrconf.h | 2 + include/net/ipv6.h | 4 +- include/net/pkt_sched.h | 2 +- include/net/tcp.h | 7 - include/net/xfrm.h | 13 +- init/Kconfig | 3 +- ipc/sem.c | 95 +- kernel/acct.c | 26 +- kernel/cpufreq.c | 115 +- kernel/exit.c | 17 +- kernel/fork.c | 3 +- kernel/ksyms.c | 3 +- kernel/sched.c | 25 +- kernel/signal.c | 61 +- kernel/softirq.c | 30 +- kernel/suspend.c | 43 +- kernel/sysctl.c | 4 +- kernel/timer.c | 16 +- kernel/user.c | 1 - lib/Makefile | 2 +- lib/div64.c | 52 + lib/kobject.c | 15 + mm/bootmem.c | 6 +- mm/filemap.c | 62 +- mm/mmap.c | 71 +- mm/mprotect.c | 2 +- mm/mremap.c | 19 +- mm/nommu.c | 30 +- mm/page_alloc.c | 27 +- mm/readahead.c | 35 +- mm/shmem.c | 12 +- mm/slab.c | 226 +- mm/swap.c | 2 + mm/swapfile.c | 6 +- net/atm/clip.c | 58 +- net/bluetooth/hci_sock.c | 1 + net/bluetooth/rfcomm/sock.c | 1 + net/core/dev.c | 2 +- net/core/neighbour.c | 4 +- net/ipv4/igmp.c | 4 +- net/ipv4/ip_gre.c | 7 +- net/ipv4/ipconfig.c | 4 + net/ipv4/ipip.c | 6 + net/ipv4/raw.c | 2 +- net/ipv4/tcp_input.c | 21 + net/ipv6/addrconf.c | 91 +- net/ipv6/anycast.c | 2 +- net/ipv6/ip6_flowlabel.c | 2 +- net/ipv6/ip6_output.c | 2 +- net/ipv6/ip6_tunnel.c | 223 +- net/ipv6/mcast.c | 4 +- net/ipv6/proc.c | 2 +- net/ipv6/raw.c | 3 +- net/ipv6/route.c | 2 + net/ipv6/sit.c | 6 + net/ipv6/tcp_ipv6.c | 22 +- net/key/af_key.c | 11 +- net/netsyms.c | 1 + net/packet/af_packet.c | 15 +- net/sched/sch_atm.c | 7 +- net/sched/sch_cbq.c | 7 +- net/sched/sch_dsmark.c | 9 +- net/sched/sch_fifo.c | 7 +- net/sched/sch_gred.c | 16 +- net/sched/sch_htb.c | 11 +- net/sched/sch_ingress.c | 2 +- net/sched/sch_prio.c | 8 +- net/sched/sch_red.c | 8 +- net/sched/sch_sfq.c | 9 +- net/sched/sch_tbf.c | 232 +- net/socket.c | 4 +- net/unix/af_unix.c | 2 +- net/wanrouter/wanmain.c | 2 + net/xfrm/xfrm_policy.c | 120 +- net/xfrm/xfrm_state.c | 46 +- net/xfrm/xfrm_user.c | 56 +- scripts/ver_linux | 3 + security/capability.c | 65 + security/dummy.c | 52 + usr/Makefile | 8 +- usr/initramfs_data.scr | 4 - 786 files changed, 20520 insertions(+), 26851 deletions(-) delete mode 100644 arch/arm26/Config.help delete mode 100644 arch/arm26/config.in delete mode 100644 arch/arm26/kernel/arch.c delete mode 100644 arch/arm26/machine/arch.c rewrite arch/cris/Kconfig (70%) copy arch/cris/{ => arch-v10}/Kconfig (64%) rename arch/cris/{ => arch-v10}/README.mm (99%) rename arch/cris/{ => arch-v10}/boot/Makefile (100%) rename arch/cris/{ => arch-v10}/boot/compressed/Makefile (100%) rename arch/cris/{ => arch-v10}/boot/compressed/README (95%) rename arch/cris/{ => arch-v10}/boot/compressed/decompress.ld (95%) rename arch/cris/{ => arch-v10}/boot/compressed/head.S (98%) rename arch/cris/{ => arch-v10}/boot/compressed/misc.c (97%) rename arch/cris/{ => arch-v10}/boot/rescue/Makefile (100%) rename arch/cris/{ => arch-v10}/boot/rescue/head.S (96%) rename arch/cris/{ => arch-v10}/boot/rescue/kimagerescue.S (98%) rename arch/cris/{ => arch-v10}/boot/rescue/rescue.ld (100%) rename arch/cris/{ => arch-v10}/boot/rescue/testrescue.S (85%) rename arch/cris/{ => arch-v10}/boot/tools/build.c (100%) copy arch/cris/{ => arch-v10}/defconfig (100%) rename arch/cris/{ => arch-v10}/drivers/Kconfig (50%) rename arch/cris/{ => arch-v10}/drivers/Makefile (60%) create mode 100644 arch/cris/arch-v10/drivers/axisflashmap.c rename arch/cris/{ => arch-v10}/drivers/ds1302.c (86%) rename arch/cris/{ => arch-v10}/drivers/eeprom.c (95%) rename arch/cris/{ => arch-v10}/drivers/ethernet.c (64%) create mode 100644 arch/cris/arch-v10/drivers/gpio.c rename arch/cris/{ => arch-v10}/drivers/i2c.c (82%) rename arch/cris/{ => arch-v10}/drivers/i2c.h (86%) create mode 100644 arch/cris/arch-v10/drivers/pcf8563.c rename arch/cris/{ => arch-v10}/drivers/serial.c (71%) rename arch/cris/{ => arch-v10}/drivers/serial.h (90%) create mode 100644 arch/cris/arch-v10/kernel/Makefile create mode 100644 arch/cris/arch-v10/kernel/asm-offsets.c rename arch/cris/{ => arch-v10}/kernel/debugport.c (64%) rename arch/cris/{ => arch-v10}/kernel/entry.S (76%) create mode 100644 arch/cris/arch-v10/kernel/fasttimer.c rename arch/cris/{ => arch-v10}/kernel/head.S (97%) create mode 100644 arch/cris/arch-v10/kernel/irq.c rename arch/cris/{ => arch-v10}/kernel/kgdb.c (99%) create mode 100644 arch/cris/arch-v10/kernel/process.c copy arch/cris/{ => arch-v10}/kernel/ptrace.c (53%) create mode 100644 arch/cris/arch-v10/kernel/setup.c rename arch/cris/{ => arch-v10}/kernel/shadows.c (94%) rename arch/cris/{ => arch-v10}/kernel/signal.c (91%) copy arch/cris/{ => arch-v10}/kernel/time.c (56%) create mode 100644 arch/cris/arch-v10/kernel/traps.c rename arch/cris/{ => arch-v10}/lib/Makefile (98%) rename arch/cris/{ => arch-v10}/lib/checksum.S (97%) rename arch/cris/{ => arch-v10}/lib/checksumcopy.S (97%) rename arch/cris/{ => arch-v10}/lib/csumcpfruser.S (100%) rename arch/cris/{ => arch-v10}/lib/dmacopy.c (93%) rename arch/cris/{ => arch-v10}/lib/dram_init.S (82%) rename arch/cris/{ => arch-v10}/lib/hw_settings.S (95%) rename arch/cris/{ => arch-v10}/lib/memset.c (100%) rename arch/cris/{ => arch-v10}/lib/old_checksum.c (94%) rename arch/cris/{ => arch-v10}/lib/string.c (100%) rename arch/cris/{ => arch-v10}/lib/usercopy.c (80%) copy arch/cris/{ => arch-v10}/mm/Makefile (58%) create mode 100644 arch/cris/arch-v10/mm/fault.c create mode 100644 arch/cris/arch-v10/mm/init.c copy arch/cris/{ => arch-v10}/mm/tlb.c (64%) create mode 100644 arch/cris/arch-v10/output_arch.ld rename arch/cris/{ => arch-v10}/vmlinux.lds.S (86%) delete mode 100644 arch/cris/drivers/axisflashmap.c delete mode 100644 arch/cris/drivers/bluetooth/Makefile delete mode 100644 arch/cris/drivers/gpio.c delete mode 100644 arch/cris/drivers/ide.c delete mode 100644 arch/cris/drivers/lpslave/Makefile delete mode 100644 arch/cris/drivers/lpslave/bintocarr.pl delete mode 100644 arch/cris/drivers/lpslave/e100lpslave.README delete mode 100644 arch/cris/drivers/lpslave/e100lpslave.S delete mode 100644 arch/cris/drivers/lpslave/e100lpslave.h delete mode 100644 arch/cris/drivers/lpslave/e100lpslaveld delete mode 100644 arch/cris/drivers/lpslave/e100lpslavenet.c delete mode 100644 arch/cris/drivers/parport.c delete mode 100644 arch/cris/drivers/sync_serial.c delete mode 100644 arch/cris/drivers/usb-host.c delete mode 100644 arch/cris/drivers/usb-host.h rewrite arch/cris/kernel/Makefile (82%) delete mode 100644 arch/cris/kernel/entryoffsets.c create mode 100644 arch/cris/kernel/module.c rewrite arch/cris/kernel/ptrace.c (79%) rewrite arch/cris/kernel/time.c (73%) rewrite arch/cris/mm/extable.c (62%) rewrite arch/cris/mm/init.c (61%) rewrite arch/cris/mm/tlb.c (66%) delete mode 100644 arch/ia64/sn/io/ate_utils.c delete mode 100644 arch/ia64/sn/io/sn2/l1.c create mode 100644 arch/ppc/boot/common/serial_stub.c delete mode 100644 arch/ppc/boot/simple/direct.S delete mode 100644 arch/ppc/configs/zx4500_defconfig delete mode 100644 arch/ppc/platforms/menf1.h delete mode 100644 arch/ppc/platforms/menf1_pci.c delete mode 100644 arch/ppc/platforms/menf1_setup.c create mode 100644 arch/ppc/platforms/sandpoint.c delete mode 100644 arch/ppc/platforms/sandpoint_pci.c delete mode 100644 arch/ppc/platforms/sandpoint_serial.h delete mode 100644 arch/ppc/platforms/sandpoint_setup.c delete mode 100644 arch/ppc/platforms/zx4500.h delete mode 100644 arch/ppc/platforms/zx4500_pci.c delete mode 100644 arch/ppc/platforms/zx4500_serial.h delete mode 100644 arch/ppc/platforms/zx4500_setup.c create mode 100644 arch/ppc/syslib/gen550_dbg.c create mode 100644 arch/ppc/syslib/gen550_kgdb.c copy include/asm-sparc64/xor.h => arch/sparc64/lib/xor.S (82%) create mode 100644 drivers/block/as-iosched.c create mode 100644 fs/cifs/cifsencrypt.c create mode 100644 fs/cifs/xattr.c delete mode 100644 fs/xfs/linux/xfs_syncd.c delete mode 100644 include/asm-arm26/arch.h create mode 100644 include/asm-cris/arch-v10/bitops.h create mode 100644 include/asm-cris/arch-v10/byteorder.h create mode 100644 include/asm-cris/arch-v10/cache.h create mode 100644 include/asm-cris/arch-v10/checksum.h create mode 100644 include/asm-cris/arch-v10/delay.h copy include/asm-cris/{ => arch-v10}/dma.h (63%) copy include/asm-cris/{ => arch-v10}/elf.h (56%) copy include/asm-cris/{ => arch-v10}/io.h (77%) copy include/asm-cris/{ => arch-v10}/irq.h (92%) copy include/asm-cris/{ => arch-v10}/mmu.h (54%) create mode 100644 include/asm-cris/arch-v10/offset.h create mode 100644 include/asm-cris/arch-v10/page.h create mode 100644 include/asm-cris/arch-v10/pgtable.h create mode 100644 include/asm-cris/arch-v10/processor.h copy include/asm-cris/{ => arch-v10}/ptrace.h (92%) rename include/asm-cris/{ => arch-v10}/sv_addr.agh (99%) rename include/asm-cris/{ => arch-v10}/sv_addr_ag.h (76%) rename include/asm-cris/{ => arch-v10}/svinto.h (95%) create mode 100644 include/asm-cris/arch-v10/system.h create mode 100644 include/asm-cris/arch-v10/thread_info.h create mode 100644 include/asm-cris/arch-v10/timex.h create mode 100644 include/asm-cris/arch-v10/tlb.h copy include/asm-cris/{ => arch-v10}/uaccess.h (58%) create mode 100644 include/asm-cris/arch-v10/unistd.h create mode 100644 include/asm-cris/arch-v10/user.h copy include/{asm-i386 => asm-cris}/cacheflush.h (68%) rewrite include/asm-cris/dma.h (86%) rewrite include/asm-cris/elf.h (64%) create mode 100644 include/asm-cris/fasttimer.h copy include/{asm-i386 => asm-cris}/hardirq.h (84%) delete mode 100644 include/asm-cris/hdreg.h delete mode 100644 include/asm-cris/ide.h rewrite include/asm-cris/io.h (80%) rewrite include/asm-cris/irq.h (96%) create mode 100644 include/asm-cris/kmap_types.h rewrite include/asm-cris/mmu.h (95%) create mode 100644 include/asm-cris/percpu.h rewrite include/asm-cris/pgalloc.h (90%) rewrite include/asm-cris/processor.h (62%) rewrite include/asm-cris/ptrace.h (93%) create mode 100644 include/asm-cris/rs485.h rewrite include/asm-cris/rtc.h (75%) rewrite include/asm-cris/setup.h (99%) delete mode 100644 include/asm-cris/smp_lock.h delete mode 100644 include/asm-cris/sync_serial.h rewrite include/asm-cris/system.h (67%) create mode 100644 include/asm-cris/thread_info.h rewrite include/asm-cris/timex.h (65%) create mode 100644 include/asm-cris/tlbflush.h rewrite include/asm-cris/uaccess.h (62%) copy include/{asm-i386 => asm-cris}/unistd.h (70%) create mode 100644 include/asm-generic/div64.h rewrite include/asm-ia64/div64.h (100%) delete mode 100644 include/asm-ia64/sn/ate_utils.h delete mode 100644 include/asm-ia64/sn/systeminfo.h rewrite include/asm-parisc/div64.h (100%) rewrite include/asm-ppc/div64.h (100%) rewrite include/asm-ppc64/div64.h (100%) rewrite include/asm-sh/div64.h (100%) rewrite include/asm-sparc64/xor.h (85%) create mode 100644 lib/div64.c delete mode 100644 usr/initramfs_data.scr diff --git a/CREDITS b/CREDITS index 984802bbf1d..81f244e5ab8 100644 --- a/CREDITS +++ b/CREDITS @@ -828,8 +828,8 @@ W: http://www.xenotime.net/linux/linux.html W: http://www.linux-usb.org D: Linux-USB subsystem, USB core/UHCI/printer/storage drivers D: x86 SMP, ACPI, bootflag hacking -S: 15275 SW Koll Parkway, Suite H -S: Beaverton, Oregon 97006 +S: 12725 SW Millikan Way, Suite 400 +S: Beaverton, Oregon 97005 S: USA N: Bob Dunlop @@ -2228,8 +2228,8 @@ N: Patrick Mochel E: mochel@osdl.org E: mochelp@infinity.powertie.org D: PCI Power Management, ACPI work -S: 15275 SW Koll Parkway, Suite H -S: Beaverton, OR 97006 +S: 12725 SW Millikan Way, Suite 400 +S: Beaverton, Oregon 97005 S: USA N: Eberhard Moenkeberg @@ -3046,12 +3046,10 @@ S: Sevilla 41005 S: Spain N: Linus Torvalds -E: torvalds@transmeta.com -W: http://www.cs.helsinki.fi/Linus.Torvalds -P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8 +E: torvalds@osdl.org D: Original kernel hacker -S: 3990 Freedom Circle -S: Santa Clara, California 95054 +S: 12725 SW Millikan Way, Suite 400 +S: Beaverton, Oregon 97005 S: USA N: Marcelo W. Tosatti diff --git a/Documentation/Changes b/Documentation/Changes index ce9a364bd56..112c2d885d8 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -58,6 +58,7 @@ o jfsutils 1.0.14 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs o xfsprogs 2.1.0 # xfs_db -V o pcmcia-cs 3.1.21 # cardmgr -V +o quota-tools 3.09 # quota -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version o procps 2.0.9 # ps --version @@ -194,6 +195,14 @@ PCMCIA (PC Card) support is now partially implemented in the main kernel source. Pay attention when you recompile your kernel ;-). Also, be sure to upgrade to the latest pcmcia-cs release. +Quota-tools +----------- + +Support for 32 bit uid's and gid's is required if you want to use +the newer version 2 quota format. Quota-tools version 3.07 and +newer has this support. Use the recommended version or newer +from the table above. + Intel IA32 microcode -------------------- @@ -328,6 +337,10 @@ Pcmcia-cs --------- o +Quota-tools +---------- +o + Jade ---- o diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers index c127eff47bd..820e0734ae0 100644 --- a/Documentation/SubmittingDrivers +++ b/Documentation/SubmittingDrivers @@ -41,7 +41,7 @@ Linux 2.4: Linux 2.5: The same rules apply as 2.4 except that you should follow linux-kernel to track changes in API's. The final contact point for Linux 2.5 - submissions is Linus Torvalds . + submissions is Linus Torvalds . What Criteria Determine Acceptance ---------------------------------- diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 72b97d4c821..029e4281aa7 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -105,7 +105,7 @@ linux-kernel@vger.kernel.org. Most kernel developers monitor this e-mail list, and can comment on your changes. Linus Torvalds is the final arbiter of all changes accepted into the -Linux kernel. His e-mail address is torvalds@transmeta.com. He gets +Linux kernel. His e-mail address is . He gets a lot of e-mail, so typically you should do your best to -avoid- sending him e-mail. diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt index fc206075944..76934ca5030 100644 --- a/Documentation/cpu-freq/user-guide.txt +++ b/Documentation/cpu-freq/user-guide.txt @@ -21,6 +21,8 @@ Contents: 1.1 ARM 1.2 x86 1.3 sparc64 +1.4 ppc +1.5 SuperH 2. "Policy" / "Governor"? 2.1 Policy @@ -77,6 +79,20 @@ cpufreq: UltraSPARC-III +1.4 ppc +------- + +Several "PowerBook" and "iBook2" notebooks are supported. + + +1.5 SuperH +---------- + +The following SuperH processors are supported by cpufreq: + +SH-3 +SH-4 + 2. "Policy" / "Governor" ? ========================== diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt index c27a2676dce..8c8388da868 100644 --- a/Documentation/eisa.txt +++ b/Documentation/eisa.txt @@ -46,12 +46,14 @@ root of an EISA bus. The eisa_root_device structure holds a reference to this device, as well as some parameters for probing purposes. struct eisa_root_device { - struct list_head node; - struct device *dev; /* Pointer to bridge device */ - struct resource *res; - unsigned long bus_base_addr; - int slots; /* Max slot number */ - int bus_nr; /* Set by eisa_root_register */ + struct device *dev; /* Pointer to bridge device */ + struct resource *res; + unsigned long bus_base_addr; + int slots; /* Max slot number */ + int force_probe; /* Probe even when no slot 0 */ + u64 dma_mask; /* from bridge device */ + int bus_nr; /* Set by eisa_root_register */ + struct resource eisa_root_res; /* ditto */ }; node : used for eisa_root_register internal purpose @@ -59,6 +61,8 @@ dev : pointer to the root device res : root device I/O resource bus_base_addr : slot 0 address on this bus slots : max slot number to probe +force_probe : Probe even when slot 0 is empty (no EISA mainboard) +dma_mask : Default DMA mask. Usualy the bridge device dma_mask. bus_nr : unique bus id, set by eisa_root_register ** Driver : @@ -87,7 +91,7 @@ driver : a generic driver, such as described in Documentation/driver-model/driver.txt. Only .name, .probe and .remove members are mandatory. -An example is the 3c509 driver : +An example is the 3c59x driver : static struct eisa_device_id vortex_eisa_ids[] = { { "TCM5920", EISA_3C592_OFFSET }, @@ -116,15 +120,20 @@ encapsulated in a 'struct eisa_device' described as follows : struct eisa_device { struct eisa_device_id id; int slot; - unsigned long base_addr; - struct resource res; + int state; + unsigned long base_addr; + struct resource res[EISA_MAX_RESOURCES]; + u64 dma_mask; struct device dev; /* generic device */ }; id : EISA id, as read from device. id.driver_data is set from the matching driver EISA id. slot : slot number which the device was detected on -res : I/O resource allocated to this device +state : set of flags indicating the state of the device. Current + flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED. +res : set of four 256 bytes I/O regions allocated to this device +dma_mask: DMA mask set from the parent device. dev : generic device (see Documentation/driver-model/device.txt) You can get the 'struct eisa_device' from 'struct device' using the @@ -140,6 +149,32 @@ void *eisa_get_drvdata (struct eisa_device *edev): Gets the pointer previously stored into the device's driver_data area. +int eisa_get_region_index (void *addr); + +Returns the region number (0 <= x < EISA_MAX_RESOURCES) of a given +address. + +** Kernel parameters : + +eisa_bus.enable_dev : + +A comma-separated list of slots to be enabled, even if the firmware +set the card as disabled. The driver must be able to properly +initialize the device in such conditions. + +eisa_bus.disable_dev : + +A comma-separated list of slots to be enabled, even if the firmware +set the card as enabled. The driver won't be called to handle this +device. + +virtual_root.force_probe : + +Force the probing code to probe EISA slots even when it cannot find an +EISA compliant mainboard (nothing appears on slot 0). Defaultd to 0 +(don't force), and set to 1 (force probing) when either +CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set. + ** Random notes : Converting an EISA driver to the new API mostly involves *deleting* @@ -156,10 +191,13 @@ Unfortunately, most drivers are doing the probing by themselves, and expect to have explored the whole machine when they exit their probe routine. +For example, switching your favorite EISA SCSI card to the "hotplug" +model is "the right thing"(tm). + ** Thanks : I'd like to thank the following people for their help : - Xavier Benigni for lending me a wonderful Alpha Jensen, - James Bottomley, Jeff Garzik for getting this stuff into the kernel, - Andries Brouwer for contributing numerous EISA ids, -- Catrin Jones for coping with too many machines at home +- Catrin Jones for coping with far too many machines at home. diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 03f43b68e80..969c8726f20 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -68,8 +68,8 @@ setattr: yes permission: no getattr: no setxattr: yes -getxattr: yes -listxattr: yes +getxattr: no +listxattr: no removexattr: yes Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on victim. @@ -318,7 +318,7 @@ poll: no ioctl: yes (see below) mmap: no open: maybe (see below) -flush: yes +flush: no release: no fsync: yes (see below) fasync: yes (see below) diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt index bdb8ccab7a8..cbece1f3100 100644 --- a/Documentation/filesystems/jfs.txt +++ b/Documentation/filesystems/jfs.txt @@ -23,6 +23,15 @@ resize=value Resize the volume to blocks. JFS only supports read-write. The resize keyword with no value will grow the volume to the full size of the partition. +nointegrity Do not write to the journal. The primary use of this option + is to allow for higher performance when restoring a volume + from backup media. The integrity of the volume is not + guaranteed if the system abnormally abends. + +integrity Default. Commit metadata changes to the journal. Use this + option to remount a volume where the nointegrity option was + previously specified in order to restore normal behavior. + JFS TODO list: Plans for our near term development items diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt index 33538b8704f..947a56bd633 100644 --- a/Documentation/filesystems/xfs.txt +++ b/Documentation/filesystems/xfs.txt @@ -14,8 +14,8 @@ for further details. This implementation is on-disk compatible with the IRIX version of XFS. -Options -======= +Mount Options +============= When mounting an XFS filesystem, the following options are accepted. @@ -107,3 +107,66 @@ When mounting an XFS filesystem, the following options are accepted. Don't check for double mounted file systems using the file system uuid. This is useful to mount LVM snapshot volumes. +sysctls +======= + +The following sysctls are available for the XFS filesystem: + + fs.xfs.stats_clear (Min: 0 Default: 0 Max: 1) + Setting this to "1" clears accumulated XFS statistics + in /proc/fs/xfs/stat. It then immediately reset to "0". + + fs.xfs.sync_interval (Min: HZ Default: 30*HZ Max: 60*HZ) + The interval at which the xfssyncd thread for xfs filesystems + flushes metadata out to disk. This thread will flush log + activity out, and do some processing on unlinked inodes + + fs.xfs.error_level (Min: 0 Default: 3 Max: 11) + A volume knob for error reporting when internal errors occur. + This will generate detailed messages & backtraces for filesystem + shutdowns, for example. Current threshold values are: + + XFS_ERRLEVEL_OFF: 0 + XFS_ERRLEVEL_LOW: 1 + XFS_ERRLEVEL_HIGH: 5 + + fs.xfs.panic_mask (Min: 0 Default: 0 Max: 127) + Causes certain error conditions to call BUG(). Value is a bitmask; + AND together the tags which represent errors which should cause panics: + + XFS_NO_PTAG 0LL + XFS_PTAG_IFLUSH 0x0000000000000001LL + XFS_PTAG_LOGRES 0x0000000000000002LL + XFS_PTAG_AILDELETE 0x0000000000000004LL + XFS_PTAG_ERROR_REPORT 0x0000000000000008LL + XFS_PTAG_SHUTDOWN_CORRUPT 0x0000000000000010LL + XFS_PTAG_SHUTDOWN_IOERROR 0x0000000000000020LL + XFS_PTAG_SHUTDOWN_LOGERROR 0x0000000000000040LL + + This option is intended for debugging only. + + fs.xfs.irix_symlink_mode (Min: 0 Default: 0 Max: 1) + Controls whether symlinks are created with mode 0777 (default) + or whether their mode is affected by the umask (irix mode). + + fs.xfs.irix_sgid_inherit (Min: 0 Default: 0 Max: 1) + Controls files created in SGID directories. + If the group ID of the new file does not match the effective group + ID or one of the supplementary group IDs of the parent dir, the + ISGID bit is cleared if the irix_sgid_inherit compatibility sysctl + is set. + + fs.xfs.restrict_chown (Min: 0 Default: 1 Max: 1) + Controls whether unprivileged users can use chown to "give away" + a file to another user. + + vm.pagebuf.stats_clear (Min: 0 Default: 0 Max: 1) + Setting this to "1" clears accumulated pagebuf statistics + in /proc/fs/pagebuf/stat. It then immediately reset to "0". + + vm.pagebuf.flush_age (Min: 1*HZ Default: 15*HZ Max: 300*HZ) + The age at which dirty metadata buffers are flushed to disk + + vm.pagebuf.flush_int (Min: HZ/2 Default: HZ Max: 30*HZ) + The interval at which the list of dirty metadata buffers is + scanned. diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index d9f25e1d8ca..53b58a6ace6 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -52,7 +52,7 @@ latter, man ksymoops for details. Full Information ---------------- -From: Linus Torvalds +From: Linus Torvalds How to track down an Oops.. [originally a mail to linux-kernel] diff --git a/Documentation/pci.txt b/Documentation/pci.txt index 15c52173d04..d30dc107ac6 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt @@ -7,14 +7,14 @@ The world of PCI is vast and it's full of (mostly unpleasant) surprises. Different PCI devices have different requirements and different bugs -- because of this, the PCI support layer in Linux kernel is not as trivial as one would wish. This short pamphlet tries to help all potential driver -authors to find their way through the deep forests of PCI handling. +authors find their way through the deep forests of PCI handling. 0. Structure of PCI drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ There exist two kinds of PCI drivers: new-style ones (which leave most of probing for devices to the PCI layer and support online insertion and removal -of devices [thus supporting PCI, hot-pluggable PCI and CardBus in single +of devices [thus supporting PCI, hot-pluggable PCI and CardBus in a single driver]) and old-style ones which just do all the probing themselves. Unless you have a very good reason to do so, please don't use the old way of probing in any new code. After the driver finds the devices it wishes to operate @@ -174,7 +174,7 @@ which enables the bus master bit in PCI_COMMAND register and also fixes the latency timer value if it's set to something bogus by the BIOS. If you want to use the PCI Memory-Write-Invalidate transaction, -call pci_set_mwi(). This enables bit PCI_COMMAND bit for Mem-Wr-Inval +call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval and also ensures that the cache line size register is set correctly. Make sure to check the return value of pci_set_mwi(), not all architectures may support Memory-Write-Invalidate. @@ -236,7 +236,7 @@ pci_clear_mwi() Disable Memory-Write-Invalidate transactions. 7. Miscellaneous hints ~~~~~~~~~~~~~~~~~~~~~~ When displaying PCI slot names to the user (for example when a driver wants -to tell the user what card has it found), please use pci_dev->slot_name +to tell the user what card has it found), please use pci_name(pci_dev) for this purpose. Always refer to the PCI devices by a pointer to the pci_dev structure. @@ -248,6 +248,10 @@ can be pretty complex. If you're going to use PCI bus mastering DMA, take a look at Documentation/DMA-mapping.txt. +Don't try to turn on Fast Back to Back writes in your driver. All devices +on the bus need to be capable of doing it, so this is something which needs +to be handled by platform and generic code, not individual drivers. + 8. Obsolete functions ~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS index ba868a2c57e..01e7f857ef3 100644 --- a/Documentation/usb/CREDITS +++ b/Documentation/usb/CREDITS @@ -21,7 +21,7 @@ difficult to maintain, add yourself with a patch if desired. Bill Ryder Thomas Sailer Gregory P. Smith - Linus Torvalds + Linus Torvalds Roman Weissgaerber diff --git a/MAINTAINERS b/MAINTAINERS index 01282a2f9d7..34ae054fba6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -245,6 +245,21 @@ M: jschlst@samba.org L: linux-atalk@lists.netspace.org S: Maintained +ARM26 ARCHITECTURE +P: Ian Molton +M: spyro@f2s.com +S: Maintained + +ARM26/ARCHIMEDES +P: Ian Molton +M: spyro@f2s.com +S: Maintained + +ARM26/A5000 +P: John Appleby +M: john@dnsworld.co.uk +S: Maintained + ARM MFM AND FLOPPY DRIVERS P: Dave Gilbert M: linux@treblig.org @@ -1265,8 +1280,8 @@ L: linux-hams@vger.kernel.org S: Maintained NETWORK BLOCK DEVICE -P: Pavel Machek -M: pavel@atrey.karlin.mff.cuni.cz +P: Paul Clements +M: Paul.Clements@steeleye.com S: Maintained NETWORK DEVICE DRIVERS @@ -2095,11 +2110,10 @@ L: user-mode-linux-user@lists.sourceforge.net W: http://user-mode-linux.sourceforge.net S: Maintained -VFAT FILESYSTEM: -P: Gordon Chaffee -M: chaffee@cs.berkeley.edu +FAT/VFAT/MSDOS FILESYSTEM: +P: OGAWA Hirofumi +M: hirofumi@mail.parknet.co.jp L: linux-kernel@vger.kernel.org -W: http://bmrc.berkeley.edu/people/chaffee S: Maintained VIA 82Cxxx AUDIO DRIVER diff --git a/Makefile b/Makefile index 7925a53a76c..3d682d0b284 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 74 +SUBLEVEL = 75 EXTRAVERSION = # *DOCUMENTATION* diff --git a/README b/README index 03d964c00e3..edcf4a39cd4 100644 --- a/README +++ b/README @@ -225,10 +225,8 @@ IF SOMETHING GOES WRONG: the file MAINTAINERS to see if there is a particular person associated with the part of the kernel that you are having trouble with. If there isn't anyone listed there, then the second best thing is to mail - them to me (torvalds@transmeta.com), and possibly to any other - relevant mailing-list or to the newsgroup. The mailing-lists are - useful especially for SCSI and networking problems, as I can't test - either of those personally anyway. + them to me (torvalds@osdl.org), and possibly to any other relevant + mailing-list or to the newsgroup. - In all bug-reports, *please* tell what kernel you are talking about, how to duplicate the problem, and what your setup is (use your common diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c index 5a7ad83d367..3100bb87bd5 100644 --- a/arch/alpha/mm/numa.c +++ b/arch/alpha/mm/numa.c @@ -338,7 +338,7 @@ void __init mem_init(void) lmem_map = node_mem_map(nid); pfn = NODE_DATA(nid)->node_start_pfn; - for (i = 0; i < node_size(nid); i++, pfn++) + for (i = 0; i < node_spanned_pages(nid); i++, pfn++) if (page_is_ram(pfn) && PageReserved(lmem_map+i)) reservedpages++; } @@ -372,7 +372,7 @@ show_mem(void) printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); for (nid = 0; nid < numnodes; nid++) { struct page * lmem_map = node_mem_map(nid); - i = node_size(nid); + i = node_spanned_pages(nid); while (i-- > 0) { total++; if (PageReserved(lmem_map+i)) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 2fbcb7f5766..90dcf272009 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -79,7 +79,7 @@ void show_mem(void) struct page *page, *end; page = NODE_MEM_MAP(node); - end = page + NODE_DATA(node)->node_size; + end = page + NODE_DATA(node)->node_spanned_pages; do { total++; @@ -576,7 +576,7 @@ void __init mem_init(void) for (node = 0; node < numnodes; node++) { pg_data_t *pgdat = NODE_DATA(node); - if (pgdat->node_size != 0) + if (pgdat->node_spanned_pages != 0) totalram_pages += free_all_bootmem_node(pgdat); } diff --git a/arch/arm26/Config.help b/arch/arm26/Config.help deleted file mode 100644 index a2a7f13d4ef..00000000000 --- a/arch/arm26/Config.help +++ /dev/null @@ -1,387 +0,0 @@ -CONFIG_ARM - The ARM series is a line of low-power-consumption RISC chip designs - licensed by ARM ltd and targeted at embedded applications. - -CONFIG_IDE - If you say Y here, your kernel will be able to manage low cost mass - storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CD-ROM drives. - - If your system is pure SCSI and doesn't use these interfaces, you - can say N here. - - Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard - for mass storage units such as hard disks. It was designed by - Western Digital and Compaq Computer in 1984. It was then named - ST506. Quite a number of disks use the IDE interface. - - AT Attachment (ATA) is the superset of the IDE specifications. - ST506 was also called ATA-1. - - Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is - ATA-3. It provides support for larger disks (up to 8.4GB by means of - the LBA standard), more disks (4 instead of 2) and for other mass - storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is - ATA-4 and provides faster (and more CPU friendly) transfer modes - than previous PIO (Programmed processor Input/Output) from previous - ATA/IDE standards by means of fast DMA controllers. - - ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CD-ROM drives, similar in many respects to the SCSI protocol. - - SMART IDE (Self Monitoring, Analysis and Reporting Technology) was - designed in order to prevent data corruption and disk crash by - detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this standard. - The kernel itself don't manage this; however there are quite a - number of user programs such as smart that can query the status of - SMART parameters disk. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ide.o. - - For further information, please read . - - If unsure, say Y. - -CONFIG_ISA - Find out whether you have ISA slots on your motherboard. ISA is the - name of a bus system, i.e. the way the CPU talks to the other stuff - inside your box. Other bus systems are PCI, EISA, MicroChannel - (MCA) or VESA. ISA is an older system, now being displaced by PCI; - newer boards don't support it. If you have ISA, say Y, otherwise N. - -CONFIG_PREEMPT - This option reduces the latency of the kernel when reacting to - real-time or interactive events by allowing a low priority process to - be preempted even if it is in kernel mode executing a system call. - This allows applications to run more reliably even when the system is - under load. - - Say Y here if you are building a kernel for a desktop, embedded - or real-time system. Say N if you are unsure. - -CONFIG_MCA - MicroChannel Architecture is found in some IBM PS/2 machines and - laptops. It is a bus system similar to PCI or ISA. See - (and especially the web page given - there) before attempting to build an MCA bus kernel. - -CONFIG_EISA - The Extended Industry Standard Architecture (EISA) bus was - developed as an open alternative to the IBM MicroChannel bus. - - The EISA bus provided some of the features of the IBM MicroChannel - bus while maintaining backward compatibility with cards made for - the older ISA bus. The EISA bus saw limited use between 1988 and - 1995 when it was made obsolete by the PCI bus. - - Say Y here if you are building a kernel for an EISA-based machine. - - Otherwise, say N. - -CONFIG_HOTPLUG - Say Y here if you want to plug devices into your computer while - the system is running, and be able to use them quickly. In many - cases, the devices can likewise be unplugged at any time too. - - One well known example of this is PCMCIA- or PC-cards, credit-card - size devices such as network cards, modems or hard drives which are - plugged into slots found on all modern laptop computers. Another - example, used on modern desktops as well as laptops, is USB. - - Enable HOTPLUG and KMOD, and build a modular kernel. Get agent - software (at ) and install it. - Then your kernel will automatically call out to a user mode "policy - agent" (/sbin/hotplug) to load modules and set up software needed - to use devices as you hotplug them. - -CONFIG_KCORE_ELF - If you enabled support for /proc file system then the file - /proc/kcore will contain the kernel core image. This can be used - in gdb: - - $ cd /usr/src/linux ; gdb vmlinux /proc/kcore - - You have two choices here: ELF and A.OUT. Selecting ELF will make - /proc/kcore appear in ELF core format as defined by the Executable - and Linking Format specification. Selecting A.OUT will choose the - old "a.out" format which may be necessary for some old versions - of binutils or on some architectures. - - This is especially useful if you have compiled the kernel with the - "-g" option to preserve debugging information. It is mainly used - for examining kernel data structures on the live kernel so if you - don't understand what this means or are not a kernel hacker, just - leave it at its default value ELF. - -CONFIG_KCORE_AOUT - Not necessary unless you're using a very out-of-date binutils - version. You probably want KCORE_ELF. - -CONFIG_BINFMT_ELF - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf.o. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -CONFIG_BINFMT_AOUT - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout.o. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -CONFIG_BINFMT_MISC - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc.o. If you - don't know what to answer at this point, say Y. - -CONFIG_SCSI - If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or - any other SCSI device under Linux, say Y and make sure that you know - the name of your SCSI host adapter (the card inside your computer - that "speaks" the SCSI protocol, also called SCSI controller), - because you will be asked for it. - - You also need to say Y here if you want support for the parallel - port version of the 100 MB IOMEGA ZIP drive. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called scsi_mod.o. If you want to compile it as - a module, say M here and read and - . However, do not compile this as a - module if your root file system (the one containing the directory /) - is located on a SCSI device. - -CONFIG_NETDEVICES - You can say N here if you don't intend to connect your Linux box to - any other computer at all or if all your connections will be over a - telephone line with a modem either via UUCP (UUCP is a protocol to - forward mail and news between unix hosts over telephone lines; read - the UUCP-HOWTO, available from - ) or dialing up a shell - account or a BBS, even using term (term is a program which gives you - almost full Internet connectivity if you have a regular dial up - shell account on some Internet connected Unix computer. Read - ). - - You'll have to say Y if your computer contains a network card that - you want to use under Linux (make sure you know its name because you - will be asked for it and read the Ethernet-HOWTO (especially if you - plan to use more than one network card under Linux)) or if you want - to use SLIP (Serial Line Internet Protocol is the protocol used to - send Internet traffic over telephone lines or null modem cables) or - CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better - and newer replacement for SLIP) or PLIP (Parallel Line Internet - Protocol is mainly used to create a mini network by connecting the - parallel ports of two local machines) or AX.25/KISS (protocol for - sending Internet traffic over amateur radio links). - - Make sure to read the NET-3-HOWTO. Eventually, you will have to read - Olaf Kirch's excellent and free book "Network Administrator's - Guide", to be found in . If - unsure, say Y. - -CONFIG_MAGIC_SYSRQ - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -CONFIG_ARCH_ARCA5K - This selects support for 'ARM26' CPUs (ARM 2 and 3) - -CONFIG_ARCH_A5K - Say Y here to to support the Acorn A5000. Linux can support the - internal IDE disk and CD-ROM interface, serial and parallel port, - and the floppy drive. Note that on some A5000s the floppy is - plugged into the wrong socket on the motherboard. - -CONFIG_ARCH_ARC - The Acorn Archimedes was an personal computer based on an 8MHz ARM2 - processor, released in 1987. It supported 512K of RAM and 2 800K - floppy disks. Picture and more detailed specifications at - . - -CONFIG_PAGESIZE_16 - Say Y here if your Archimedes or A5000 system has only 2MB of - memory, otherwise say N. The resulting kernel will not run on a - machine with 4MB of memory. - -CONFIG_FPE_NWFPE - Say Y to include the NWFPE floating point emulator in the kernel. - This is necessary to run most binaries. Linux does not currently - support floating point hardware so you need to say Y here even if - your machine has an FPA or floating point co-processor podule. - - It is also possible to say M to build the emulator as a module - (nwfpe.o) or indeed to leave it out altogether. However, unless you - know what you are doing this can easily render your machine - unbootable. Saying Y is the safe option. - - You may say N here if you are going to load the Acorn FPEmulator - early in the bootup. - -CONFIG_FPE_FASTFPE - Say Y here to include the FAST floating point emulator in the kernel. - This is an experimental much faster emulator which now also has full - precision for the mantissa. It does not support any exceptions. - It is very simple, and approximately 3-6 times faster than NWFPE. - - It should be sufficient for most programs. It may be not suitable - for scientific calculations, but you have to check this for yourself. - If you do not feel you need a faster FP emulation you should better - choose NWFPE. - - It is also possible to say M to build the emulator as a module - (fastfpe.o). But keep in mind that you should only load the FP - emulator early in the bootup. You should never change from NWFPE to - FASTFPE or vice versa in an active system! - -CONFIG_DEBUG_ERRORS - This option controls verbose debugging information which can be - printed when the kernel detects an internal error. This debugging - information is useful to kernel hackers when tracking down problems, - but mostly meaningless to other people. It's safe to say Y unless - you are concerned with the code size or don't want to see these - messages. - -CONFIG_NO_FRAME_POINTER - If you say Y here, the resulting kernel will be slightly smaller and - faster. However, when a problem occurs with the kernel, the - information that is reported is severely limited. Most people - should say N here. - -CONFIG_DEBUG_USER - When a user program crashes due to an exception, the kernel can - print a brief message explaining what the problem was. This is - sometimes helpful for debugging but serves no purpose on a - production system. Most people should say N here. - -CONFIG_DEBUG_INFO - Say Y here to include source-level debugging information in the - `vmlinux' binary image. This is handy if you want to use gdb or - addr2line to debug the kernel. It has no impact on the in-memory - footprint of the running kernel but it can increase the amount of - time and disk space needed for compilation of the kernel. If in - doubt say N. - -CONFIG_DEBUG_LL - Say Y here to include definitions of printascii, printchar, printhex - in the kernel. This is helpful if you are debugging code that - executes before the console is initialized. - -CONFIG_NO_PGT_CACHE - Normally the kernel maintains a `quicklist' of preallocated - pagetable structures in order to increase performance. On machines - with very few pages this may however be a loss. Say Y here to - disable the pgtable cache. - -CONFIG_ARTHUR - Say Y here to include the kernel code necessary if you want to run - Acorn RISC OS/Arthur binaries under Linux. This code is still very - experimental; if this sounds frightening, say N and sleep in peace. - You can also say M here to compile this support as a module (which - will be called arthur.o). - -CONFIG_CMDLINE - On some architectures (EBSA110 and CATS), there is currently no way - for the boot loader to pass arguments to the kernel. For these - architectures, you should supply some command-line options at build - time by entering them here. As a minimum, you should specify the - memory size and the root device (e.g., mem=64M root=/dev/nfs). - -CONFIG_DEBUG_KERNEL - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -CONFIG_DEBUG_SLAB - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. - -CONFIG_DEBUG_SPINLOCK - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -CONFIG_DEBUG_BUGVERBOSE - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -CONFIG_ZBOOT_ROM - Say Y here if you intend to execute your compressed kernel image (zImage) - directly from ROM or flash. If unsure, say N. - -CONFIG_ZBOOT_ROM_TEXT - The base address for zImage. Unless you have special requirements, you - should not change this value. - -CONFIG_ZBOOT_ROM_BSS - The base address of 64KiB of read/write memory, which must be available - while the decompressor is running. Unless you have special requirements, - you should not change this value. - diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index b62382271da..31d2e5de2c3 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -8,15 +8,8 @@ mainmenu "Linux Kernel Configuration" config ARM bool default y - help - The ARM series is a line of low-power-consumption RISC chip designs - licensed by ARM ltd and targeted at embedded applications and - handhelds such as the Compaq IPAQ. ARM-based PCs are no longer - manufactured, but legacy ARM-based PC hardware remains popular in - Europe. There is an ARM Linux project with a web page at - . - -config ARCH_ARCA5K + +config ARM26 bool default y @@ -67,25 +60,25 @@ comment "Archimedes/A5000 Implementations (select only ONE)" config ARCH_ARC bool "Archimedes" - depends on ARCH_ARCA5K help - The Acorn Archimedes was an personal computer based on an 8K ARM2 - processor, released in 1987. It supported 512K of RAM and 2 800K - floppy disks. Picture and more detailed specifications at - . + Say Y to support the Acorn Archimedes. + + The Acorn Archimedes was an personal computer based on an 8MHz ARM2 + processor, released in 1987. It supported up to 16MB of RAM in + later models and floppy, harddisc, ethernet etc. config ARCH_A5K bool "A5000" - depends on ARCH_ARCA5K help - Say Y here to to support the Acorn A5000. Linux can support the + Say Y here to to support the Acorn A5000. + + Linux can support the internal IDE disk and CD-ROM interface, serial and parallel port, and the floppy drive. Note that on some A5000s the floppy is plugged into the wrong socket on the motherboard. config PAGESIZE_16 - bool "2MB physical memory" - depends on ARCH_ARCA5K + bool "2MB physical memory (broken)" help Say Y here if your Archimedes or A5000 system has only 2MB of memory, otherwise say N. The resulting kernel will not run on a @@ -186,81 +179,7 @@ config KCORE_AOUT endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" @@ -311,59 +230,8 @@ source "net/Kconfig" source "net/irda/Kconfig" -menu "ATA/ATAPI/MFM/RLL support" - -config IDE - tristate "ATA/ATAPI/MFM/RLL support" - ---help--- - If you say Y here, your kernel will be able to manage low cost mass - storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CD-ROM drives. - - If your system is pure SCSI and doesn't use these interfaces, you - can say N here. - - Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard - for mass storage units such as hard disks. It was designed by - Western Digital and Compaq Computer in 1984. It was then named - ST506. Quite a number of disks use the IDE interface. - - AT Attachment (ATA) is the superset of the IDE specifications. - ST506 was also called ATA-1. - - Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is - ATA-3. It provides support for larger disks (up to 8.4GB by means of - the LBA standard), more disks (4 instead of 2) and for other mass - storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is - ATA-4 and provides faster (and more CPU friendly) transfer modes - than previous PIO (Programmed processor Input/Output) from previous - ATA/IDE standards by means of fast DMA controllers. - - ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CD-ROM drives, similar in many respects to the SCSI protocol. - - SMART IDE (Self Monitoring, Analysis and Reporting Technology) was - designed in order to prevent data corruption and disk crash by - detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this standard. - The kernel itself don't manage this; however there are quite a - number of user programs such as smart that can query the status of - SMART parameters disk. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ide. - - For further information, please read . - - If unsure, say Y. - source "drivers/ide/Kconfig" -endmenu - - source "drivers/scsi/Kconfig" source "drivers/isdn/Kconfig" diff --git a/arch/arm26/config.in b/arch/arm26/config.in deleted file mode 100644 index 006a435d759..00000000000 --- a/arch/arm26/config.in +++ /dev/null @@ -1,151 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/config-language.txt. -# -mainmenu_name "Linux Kernel Configuration" - -define_bool CONFIG_ARM y -define_bool CONFIG_EISA n -define_bool CONFIG_SBUS n -define_bool CONFIG_MCA n -define_bool CONFIG_UID16 y -define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y -define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n -define_bool CONFIG_GENERIC_BUST_SPINLOCK n -define_bool CONFIG_GENERIC_ISA_DMA n - -source init/Config.in - -mainmenu_option next_comment -comment 'System Type' - -define_bool CONFIG_ARCH_ARCA5K -bool ' Archimedes' CONFIG_ARCH_ARC -bool ' A5000' CONFIG_ARCH_A5K - -# Definitions to make life easier -define_bool CONFIG_ARCH_ACORN y -define_bool CONFIG_CPU_32 n -define_bool CONFIG_CPU_26 y -bool '2MB physical memory' CONFIG_PAGESIZE_16 - -endmenu - -mainmenu_option next_comment -comment 'General setup' - -define_bool CONFIG_FIQ y - -# Compressed boot loader in ROM. Yes, we really want to ask about -# TEXT and BSS so we preserve their values in the config files. -bool 'Compressed boot loader in ROM/flash' CONFIG_ZBOOT_ROM -hex 'Compressed ROM boot loader base address' CONFIG_ZBOOT_ROM_TEXT 0 -hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 - -comment 'At least one math emulation must be selected' -define_bool CONFIG_FPE_NWFPE y -choice 'Kernel core (/proc/kcore) format' \ - "ELF CONFIG_KCORE_ELF \ - A.OUT CONFIG_KCORE_AOUT" ELF -tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT -tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF -tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC -string 'Default kernel command string' CONFIG_CMDLINE "" - -define_bool CONFIG_ALIGNMENT_TRAP n -endmenu - -source drivers/parport/Config.in -source drivers/pnp/Config.in -source drivers/block/Config.in -source drivers/md/Config.in -source drivers/acorn/block/Config.in - -if [ "$CONFIG_NET" = "y" ]; then - source net/Config.in - - mainmenu_option next_comment - comment 'Network device support' - - bool 'Network device support' CONFIG_NETDEVICES - if [ "$CONFIG_NETDEVICES" = "y" ]; then - source drivers/net/Config.in - fi - endmenu -fi - -mainmenu_option next_comment -comment 'ATA/ATAPI/MFM/RLL support' - -tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE - -if [ "$CONFIG_IDE" != "n" ]; then - source drivers/ide/Config.in -else - define_bool CONFIG_BLK_DEV_HD n -fi -endmenu - -mainmenu_option next_comment -comment 'SCSI support' - -tristate 'SCSI support' CONFIG_SCSI -endmenu - -source drivers/isdn/Config.in - -# -# input before char - char/joystick depends on it. As does USB. -# -source drivers/input/Config.in - -source drivers/char/Config.in -if [ "$CONFIG_BUSMOUSE" = "y" ]; then - define_bool CONFIG_KBDMOUSE y -fi - -source drivers/media/Config.in - -source fs/Config.in - -if [ "$CONFIG_VT" = "y" ]; then - mainmenu_option next_comment - comment 'Console drivers' - source drivers/video/Config.in - endmenu -fi - -mainmenu_option next_comment -comment 'Sound' - -tristate 'Sound card support' CONFIG_SOUND -if [ "$CONFIG_SOUND" != "n" ]; then - source sound/Config.in -fi -endmenu - -source drivers/misc/Config.in -source drivers/usb/Config.in - -mainmenu_option next_comment -comment 'Kernel hacking' - -# Always compile kernel with framepointer (until 2.4 real comes out) -# Bug reports aren't much use without this. -bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER -bool 'Verbose user fault messages' CONFIG_DEBUG_USER -bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO - -bool 'Kernel debugging' CONFIG_DEBUG_KERNEL -dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL -dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL -dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL -dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL -dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL -dep_bool ' Verbose kernel error messages' CONFIG_DEBUG_ERRORS $CONFIG_DEBUG_KERNEL -# These options are only for real kernel hackers who want to get their hands dirty. -dep_bool ' Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL -endmenu - -source security/Config.in -source lib/Config.in diff --git a/arch/arm26/kernel/Makefile b/arch/arm26/kernel/Makefile index 01b44b589dc..59a75ea9a8d 100644 --- a/arch/arm26/kernel/Makefile +++ b/arch/arm26/kernel/Makefile @@ -6,7 +6,7 @@ ENTRY_OBJ = entry.o # Object file lists. -obj-y := arch.o compat.o dma.o entry.o irq.o \ +obj-y := compat.o dma.o entry.o irq.o \ process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ time.o traps.o ecard.o time-acorn.o dma.o \ ecard.o fiq.o time.o diff --git a/arch/arm26/kernel/arch.c b/arch/arm26/kernel/arch.c deleted file mode 100644 index 186de4fd6be..00000000000 --- a/arch/arm26/kernel/arch.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * linux/arch/arm/kernel/arch.c - * - * Architecture specific fixups. - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -unsigned int vram_size; - - -unsigned int memc_ctrl_reg; -unsigned int number_mfm_drives; - -static int __init parse_tag_acorn(const struct tag *tag) -{ - memc_ctrl_reg = tag->u.acorn.memc_control_reg; - number_mfm_drives = tag->u.acorn.adfsdrives; - return 0; -} - -__tagtable(ATAG_ACORN, parse_tag_acorn); - diff --git a/arch/arm26/kernel/asm-offsets.c b/arch/arm26/kernel/asm-offsets.c index 1e876488473..b8d0442de9b 100644 --- a/arch/arm26/kernel/asm-offsets.c +++ b/arch/arm26/kernel/asm-offsets.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995-2001 Russell King * 2001-2002 Keith Owens - * 2003-? Ian Molton + * 2003 Ian Molton * * Generate definitions needed by assembly language modules. * This code generates raw asm output which is post-processed to extract diff --git a/arch/arm26/kernel/compat.c b/arch/arm26/kernel/compat.c index 0f8644fe6a8..e3717ab1c04 100644 --- a/arch/arm26/kernel/compat.c +++ b/arch/arm26/kernel/compat.c @@ -26,7 +26,7 @@ #include #include -#include +//#include //#include /* diff --git a/arch/arm26/kernel/dma.c b/arch/arm26/kernel/dma.c index a6ae4e23651..b4b8c7c4bbe 100644 --- a/arch/arm26/kernel/dma.c +++ b/arch/arm26/kernel/dma.c @@ -2,7 +2,7 @@ * linux/arch/arm/kernel/dma.c * * Copyright (C) 1995-2000 Russell King - * 2003-? Ian Molton + * 2003 Ian Molton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c index d69497a9281..b57a2e6b87e 100644 --- a/arch/arm26/kernel/ecard.c +++ b/arch/arm26/kernel/ecard.c @@ -11,9 +11,8 @@ * Find all installed expansion cards, and handle interrupts from them. * * Created from information from Acorns RiscOS3 PRMs - * - * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether - * podule slot. + * 15-Jun-2003 IM Modified from ARM32 (RiscPC capable) version + * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. * 12-Sep-1997 RMK Created new handling of interrupt enables/disables * - cards can now register their own routine to control @@ -21,10 +20,7 @@ * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled * on reset from Linux. (Caused cards not to respond * under RiscOS without hard reset). - * 15-Feb-1998 RMK Added DMA support - * 12-Sep-1998 RMK Added EASI support - * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. - * 17-Apr-1999 RMK Support for EASI Type C cycles. + * */ #define ECARD_C @@ -527,8 +523,7 @@ static int ecard_prints(char *buffer, ecard_t *ec) { char *start = buffer; - buffer += sprintf(buffer, " %d: %s ", ec->slot_no, - ec->type == ECARD_EASI ? "EASI" : " "); + buffer += sprintf(buffer, " %d: ", ec->slot_no); if (ec->cid.id == 0) { struct in_chunk_dir incd; @@ -674,7 +669,7 @@ ecard_probe(int slot, card_type_t type) memset(ec, 0, sizeof(ecard_t)); ec->slot_no = slot; - ec->type = type; + ec->type = type; ec->irq = NO_IRQ; ec->fiq = NO_IRQ; ec->dma = NO_DMA; @@ -770,9 +765,8 @@ static int __init ecard_init(void) printk("Probing expansion cards\n"); - for (slot = 0; slot < 8; slot ++) { - if (ecard_probe(slot, ECARD_EASI) == -ENODEV) - ecard_probe(slot, ECARD_IOC); + for (slot = 0; slot < 4; slot ++) { + ecard_probe(slot, ECARD_IOC); } irqhw = ecard_probeirqhw(); diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c index 3b4965a2819..ddd2ea591af 100644 --- a/arch/arm26/kernel/irq.c +++ b/arch/arm26/kernel/irq.c @@ -41,7 +41,7 @@ * not be set too low to prevent false triggering. Conversely, if it * is set too high, then you could miss a stuck IRQ. * - * Maybe we ought to set a timer and re-enable the IRQ at a later time? + * FIXME Maybe we ought to set a timer and re-enable the IRQ at a later time? */ #define MAX_IRQ_CNT 100000 @@ -49,7 +49,6 @@ static volatile unsigned long irq_err_count; static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; struct irqdesc irq_desc[NR_IRQS]; -void (*init_arch_irq)(void) __initdata = NULL; /* * Dummy mask/unmask handler @@ -88,7 +87,6 @@ void disable_irq(unsigned int irq) { struct irqdesc *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); if (!desc->depth++) desc->enabled = 0; @@ -114,7 +112,7 @@ void enable_irq(unsigned int irq) spin_lock_irqsave(&irq_controller_lock, flags); if (unlikely(!desc->depth)) { printk("enable_irq(%u) unbalanced from %p\n", irq, - __builtin_return_address(0)); + __builtin_return_address(0)); //FIXME bum addresses reported - why? } else if (!--desc->depth) { desc->probing = 0; desc->enabled = 1; @@ -187,7 +185,6 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) unsigned int status; spin_unlock(&irq_controller_lock); - if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -700,6 +697,6 @@ void __init init_IRQ(void) for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) *desc = bad_irq_desc; - init_arch_irq(); + arc_init_irq(); init_dma(); } diff --git a/arch/arm26/kernel/process.c b/arch/arm26/kernel/process.c index 6a4283a3019..bf8e0367be8 100644 --- a/arch/arm26/kernel/process.c +++ b/arch/arm26/kernel/process.c @@ -227,7 +227,9 @@ extern void free_page_8k(unsigned long page); #define ll_alloc_task_struct() ((struct thread_info *)get_page_8k(GFP_KERNEL)) #define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) -struct thread_info *alloc_thread_info(void) +//FIXME - do we use *task param below looks like we dont, which is ok? +//FIXME - if EXTRA_TASK_STRUCT is zero we can optimise the below away permanently. *IF* its supposed to be zero. +struct thread_info *alloc_thread_info(struct task_struct *task) { struct thread_info *thread = NULL; diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c index f4523c16ae0..a5e07d757be 100644 --- a/arch/arm26/kernel/setup.c +++ b/arch/arm26/kernel/setup.c @@ -30,7 +30,6 @@ #include #include -#include #include #ifndef MEM_SIZE @@ -66,6 +65,8 @@ unsigned int system_rev; unsigned int system_serial_low; unsigned int system_serial_high; unsigned int elf_hwcap; +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; struct processor processor; @@ -147,33 +148,6 @@ static void __init setup_processor(void) cpu_proc_init(); } -static struct machine_desc * __init setup_machine(unsigned int nr) -{ - extern struct machine_desc __arch_info_begin, __arch_info_end; - struct machine_desc *list; - - /* - * locate architecture in the list of supported architectures. - */ - for (list = &__arch_info_begin; list < &__arch_info_end; list++) - if (list->nr == nr) - break; - - /* - * If the architecture type is not recognised, then we - * can co nothing... - */ - if (list >= &__arch_info_end) { - printk("Architecture configuration botched (nr %d), unable " - "to continue.\n", nr); - while (1); - } - - printk("Machine: %s\n", list->name); - - return list; -} - /* * Initial parsing of the command line. We need to pick out the * memory size. We look for mem=size@start, where start and size @@ -239,7 +213,7 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) } static void __init -request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) +request_standard_resources(struct meminfo *mi) { struct resource *res; int i; @@ -274,22 +248,18 @@ request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) request_resource(res, &kernel_data); } - if (mdesc->video_start) { +/* FIXME - needed? if (mdesc->video_start) { video_ram.start = mdesc->video_start; video_ram.end = mdesc->video_end; request_resource(&iomem_resource, &video_ram); - } + }*/ /* * Some machines don't have the possibility of ever - * possessing lp0, lp1 or lp2 + * possessing lp1 or lp2 */ - if (mdesc->reserve_lp0) + if (0) /* FIXME - need to do this for A5k at least */ request_resource(&ioport_resource, &lp0); - if (mdesc->reserve_lp1) - request_resource(&ioport_resource, &lp1); - if (mdesc->reserve_lp2) - request_resource(&ioport_resource, &lp2); } /* @@ -359,6 +329,15 @@ static int __init parse_tag_videotext(const struct tag *tag) __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); #endif +static int __init parse_tag_acorn(const struct tag *tag) +{ + memc_ctrl_reg = tag->u.acorn.memc_control_reg; + number_mfm_drives = tag->u.acorn.adfsdrives; + return 0; +} + +__tagtable(ATAG_ACORN, parse_tag_acorn); + static int __init parse_tag_ramdisk(const struct tag *tag) { setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, @@ -467,15 +446,18 @@ static struct init_tags { void __init setup_arch(char **cmdline_p) { struct tag *tags = (struct tag *)&init_tags; - struct machine_desc *mdesc; char *from = default_command_line; setup_processor(); - mdesc = setup_machine(machine_arch_type); - machine_name = mdesc->name; + if(machine_arch_type == MACH_TYPE_A5K) + machine_name = "A5000"; + else if(machine_arch_type == MACH_TYPE_ARCHIMEDES) + machine_name = "Archimedes"; + else + machine_name = "UNKNOWN"; - if (mdesc->param_offset) - tags = (struct tag *)mdesc->param_offset; //FIXME - ugly? + //FIXME - this may need altering when we get ROM images working + tags = (struct tag *)0x0207c000; /* * If we have the old style parameters, convert them to @@ -501,12 +483,7 @@ void __init setup_arch(char **cmdline_p) parse_cmdline(&meminfo, cmdline_p, from); bootmem_init(&meminfo); paging_init(&meminfo); - request_standard_resources(&meminfo, mdesc); - - /* - * Set up various architecture-specific pointers - */ - init_arch_irq = mdesc->init_irq; + request_standard_resources(&meminfo); #ifdef CONFIG_VT #if defined(CONFIG_DUMMY_CONSOLE) diff --git a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c index eaf86c9fedd..d0e1bc6cf47 100644 --- a/arch/arm26/kernel/traps.c +++ b/arch/arm26/kernel/traps.c @@ -175,6 +175,11 @@ void show_trace_task(struct task_struct *tsk) } } +/* FIXME - this is probably wrong.. */ +void show_stack(struct task_struct *task, unsigned long *sp) { + dump_mem("Stack: ", (unsigned long)sp, 8192+(unsigned long)task->thread_info); +} + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; /* @@ -497,7 +502,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) die_if_kernel("unknown data abort code", regs, instr); } -void __bug(const char *file, int line, void *data) +volatile void __bug(const char *file, int line, void *data) { printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); if (data) diff --git a/arch/arm26/lib/Makefile b/arch/arm26/lib/Makefile index d327dc7f385..d05d6b0fd3e 100644 --- a/arch/arm26/lib/Makefile +++ b/arch/arm26/lib/Makefile @@ -4,9 +4,7 @@ # Copyright (C) 1995-2000 Russell King # -L_TARGET := lib.a - -obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ +lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ copy_page.o delay.o findbit.o memchr.o memcpy.o \ memset.o memzero.o setbit.o \ @@ -16,15 +14,12 @@ obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ ucmpdi2.o udivdi3.o lib1funcs.o ecard.o io-acorn.o \ floppydma.o io-readsb.o io-writesb.o io-writesl.o \ uaccess-kernel.o uaccess-user.o io-readsw-armv3.o \ - io-writesw-armv3.o io-readsl-armv3.o - -obj-m := -obj-n := - -obj-$(CONFIG_VT)+= kbd.o + io-writesw-armv3.o io-readsl-armv3.o ecard.o \ + io-acorn.o floppydma.o -obj-y += ecard.o io-acorn.o floppydma.o +lib-n := +lib-$(CONFIG_VT)+= kbd.o csumpartialcopy.o: csumpartialcopygeneric.S csumpartialcopyuser.o: csumpartialcopygeneric.S diff --git a/arch/arm26/machine/Makefile b/arch/arm26/machine/Makefile index f1211f9c982..84642febab4 100644 --- a/arch/arm26/machine/Makefile +++ b/arch/arm26/machine/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := arch.o dma.o irq.o oldlatches.o \ +obj-y := dma.o irq.o oldlatches.o \ small_page.o extra-y := head.o diff --git a/arch/arm26/machine/arch.c b/arch/arm26/machine/arch.c deleted file mode 100644 index 410c2852afa..00000000000 --- a/arch/arm26/machine/arch.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * linux/arch/arm26/mach-arc/arch.c - * - * Copyright (C) 1998-2001 Russell King - * Copyright (C) 2003 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Architecture specific fixups. - */ -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -extern void arc_init_irq(void); - -#ifdef CONFIG_ARCH_ARC -MACHINE_START(ARCHIMEDES, "Acorn-Archimedes") -#elif defined(CONFIG_ARCH_A5K) -MACHINE_START(A5K, "Acorn-A5000") -#endif - MAINTAINER("Ian Molton") - BOOT_PARAMS(0x0207c000) - INITIRQ(arc_init_irq) -MACHINE_END - diff --git a/arch/arm26/machine/irq.c b/arch/arm26/machine/irq.c index 1c5f88fb2e5..158a7d29efb 100644 --- a/arch/arm26/machine/irq.c +++ b/arch/arm26/machine/irq.c @@ -73,7 +73,6 @@ static struct irqchip arc_a_chip = { static void arc_mask_irq_b(unsigned int irq) { unsigned int val, mask; - mask = 1 << (irq & 7); val = ioc_readb(IOC_IRQMASKB); ioc_writeb(val & ~mask, IOC_IRQMASKB); @@ -94,7 +93,7 @@ static struct irqchip arc_b_chip = { .unmask = arc_unmask_irq_b, }; -/* FIXME - JMA none of these functions are used in arm26 +/* FIXME - JMA none of these functions are used in arm26 currently static void arc_mask_irq_fiq(unsigned int irq) { unsigned int val, mask; @@ -124,6 +123,7 @@ void __init arc_init_irq(void) { unsigned int irq, flags; + /* Disable all IOC interrupt sources */ ioc_writeb(0, IOC_IRQMASKA); ioc_writeb(0, IOC_IRQMASKB); ioc_writeb(0, IOC_FIQMASK); diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c index c2105fb1a84..989f08c19c6 100644 --- a/arch/arm26/mm/init.c +++ b/arch/arm26/mm/init.c @@ -32,7 +32,7 @@ #include #include -#include +//#include #include #define TABLE_SIZE PTRS_PER_PTE * sizeof(pte_t)) @@ -68,7 +68,7 @@ void show_mem(void) page = NODE_MEM_MAP(0); - end = page + NODE_DATA(0)->node_size; + end = page + NODE_DATA(0)->node_spanned_pages; do { total++; @@ -353,7 +353,7 @@ void __init mem_init(void) max_mapnr = virt_to_page(high_memory) - mem_map; /* this will put all unused low memory onto the freelists */ - if (pgdat->node_size != 0) + if (pgdat->node_spanned_pages != 0) totalram_pages += free_all_bootmem_node(pgdat); printk(KERN_INFO "Memory:"); diff --git a/arch/arm26/mm/mm-memc.c b/arch/arm26/mm/mm-memc.c index 15ec20e2750..6b3d3ae806f 100644 --- a/arch/arm26/mm/mm-memc.c +++ b/arch/arm26/mm/mm-memc.c @@ -70,11 +70,9 @@ void free_pgd_slow(pgd_t *pgd) pgd_t *get_pgd_slow(struct mm_struct *mm) { - void *pg2k; pgd_t *new_pgd, *init_pgd; pmd_t *new_pmd, *init_pmd; pte_t *new_pte, *init_pte; - struct mm_struct bob; new_pgd = alloc_pgd_table(); if (!new_pgd) diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig dissimilarity index 70% index b092fb53d4c..05fb1fe7620 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -1,624 +1,261 @@ -# -# For a description of the syntax of this configuration file, -# see the Configure script. -# - -mainmenu "Linux/CRIS Kernel Configuration" - -config MMU - bool - default y - -config UID16 - bool - default y - -config RWSEM_GENERIC_SPINLOCK - bool - default y - -config RWSEM_XCHGADD_ALGORITHM - bool - -source "init/Kconfig" - - -menu "General setup" - -source "fs/Kconfig.binfmt" - -config ETRAX_KGDB - bool "Use kernel gdb debugger" - ---help--- - The CRIS version of gdb can be used to remotely debug a running - Linux kernel via the serial debug port. Provided you have gdb-cris - installed, run gdb-cris vmlinux, then type - - (gdb) set remotebaud 115200 <- kgdb uses 115200 as default - (gdb) target remote /dev/ttyS0 <- maybe you use another port - - This should connect you to your booted kernel (or boot it now if you - didn't before). The kernel halts when it boots, waiting for gdb if - this option is turned on! - -config ETRAX_WATCHDOG - bool "Enable Etrax100 watchdog" - help - Enable the built-in watchdog timer support on Etrax100 embedded - network computers. - -config ETRAX_WATCHDOG_NICE_DOGGY - bool "Disable watchdog during Oops printouts" - depends on ETRAX_WATCHDOG - help - By enabling this you make sure that the watchdog does not bite while - printing oopses. Recommended for development systems but not for - production releases. - -endmenu - - -menu "Hardware setup" - -choice - prompt "Processor type" - default ETRAX100LX - -config ETRAX100LX - bool "Etrax-100-LX-v1" - help - Support version 1 of the Etrax 100LX. - -config ETRAX100LX_V2 - bool "Etrax-100-LX-v2" - help - Support version 2 of the Etrax 100LX. - -config SVINTO_SIM - bool "Etrax-100-LX-for-xsim-simulator" - help - Support the xsim ETRAX Simulator. - -endchoice - -# Etrax100 LX v1 has a MMU "feature" requiring a low mapping -config CRIS_LOW_MAP - bool - depends on ETRAX100LX - default y - -config ETRAX_DRAM_VIRTUAL_BASE - hex - default "c0000000" if !ETRAX100LX - default "60000000" if ETRAX100LX - -config ETRAX_DRAM_SIZE - int "DRAM size (dec, in MB)" - default "8" - help - Size of DRAM (decimal in MB) typically 2, 8 or 16. - -config ETRAX_FLASH_BUSWIDTH - int "Buswidth of flash in bytes" - default "2" - help - Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. - -config ETRAX_ROOT_DEVICE - string "Root device name" - default "/dev/mtdblock3" - help - Specifies the device that should be mounted as root file system - when booting from flash. The axisflashmap driver adds an additional - mtd partition for the appended root file system image, so this option - should normally be the mtdblock device for the partition after the - last partition in the partition table. - -choice - prompt "Product LED port" - default ETRAX_PA_LEDS - -config ETRAX_PA_LEDS - bool "Port-PA-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - , and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on port PA. Some products - put the leds on PB or a memory-mapped latch (CSP0) instead. - -config ETRAX_PB_LEDS - bool "Port-PB-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - , and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on port PB. Some products - put the leds on PA or a memory-mapped latch (CSP0) instead. - -config ETRAX_CSP0_LEDS - bool "Port-CSP0-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - , and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on a memory-mapped latch - using chip select CSP0, this is mapped at 0x90000000. - Some products put the leds on PA or PB instead. - -config ETRAX_NO_LEDS - bool "None" - help - Select this option if you don't have any LED at all. - -endchoice - -config ETRAX_LED1G - int "First green LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the first green LED. - Most Axis products use bit 2 here. - -config ETRAX_LED1R - int "First red LED bit" - depends on !ETRAX_NO_LEDS - default "3" - help - Bit to use for the first red LED. - Most Axis products use bit 3 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED2G - int "Second green LED bit" - depends on !ETRAX_NO_LEDS - default "4" - help - Bit to use for the second green LED. The "Active" LED. - Most Axis products use bit 4 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED2R - int "Second red LED bit" - depends on !ETRAX_NO_LEDS - default "5" - help - Bit to use for the second red LED. - Most Axis products use bit 5 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED3G - int "Third green LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the third green LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED3R - int "Third red LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the third red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED4R - int "Fourth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fourth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED4G - int "Fourth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fourth green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED5R - int "Fifth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fifth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED5G - int "Fifth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fifth green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED6R - int "Sixth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the sixth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED6G - int "Sixth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the sixth green LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED7R - int "Seventh red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the seventh red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED7G - int "Seventh green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the seventh green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED8Y - int "Eigth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the eighth yellow LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED9Y - int "Ninth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the ninth yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED10Y - int "Tenth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the tenth yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED11Y - int "Eleventh yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the eleventh yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED12R - int "Twelfth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the twelfth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -choice - prompt "Product debug-port" - default ETRAX_DEBUG_PORT0 - -config ETRAX_DEBUG_PORT0 - bool "Serial-0" - help - Choose a serial port for the ETRAX debug console. Default to - port 0. - -config ETRAX_DEBUG_PORT1 - bool "Serial-1" - help - Use serial port 1 for the console. - -config ETRAX_DEBUG_PORT2 - bool "Serial-2" - help - Use serial port 2 for the console. - -config ETRAX_DEBUG_PORT3 - bool "Serial-3" - help - Use serial port 3 for the console. - -config ETRAX_DEBUG_PORT_NULL - bool "disabled" - help - Disable serial-port debugging. - -endchoice - -choice - prompt "Product rescue-port" - default ETRAX_RESCUE_SER0 - -config ETRAX_RESCUE_SER0 - bool "Serial-0" - help - Select one of the four serial ports as a rescue port. The default - is port 0. - -config ETRAX_RESCUE_SER1 - bool "Serial-1" - help - Use serial port 1 as the rescue port. - -config ETRAX_RESCUE_SER2 - bool "Serial-2" - help - Use serial port 2 as the rescue port. - -config ETRAX_RESCUE_SER3 - bool "Serial-3" - help - Use serial port 3 as the rescue port. - -endchoice - -config ETRAX_DEF_R_WAITSTATES - hex "R_WAITSTATES" - default "95a6" - help - Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a - good choice for most Axis products... - -config ETRAX_DEF_R_BUS_CONFIG - hex "R_BUS_CONFIG" - default "104" - help - Assorted bits controlling write mode, DMA burst length etc. 104 is - a good choice for most Axis products... - -config ETRAX_SDRAM - bool "SDRAM support" - help - Enable this if you use SDRAM chips and configure - R_SDRAM_CONFIG and R_SDRAM_TIMING as well. - -config ETRAX_DEF_R_DRAM_CONFIG - hex "R_DRAM_CONFIG" - depends on !ETRAX_SDRAM - default "1a200040" - help - The R_DRAM_CONFIG register specifies everything on how the DRAM - chips in the system are connected to the Etrax CPU. This is - different depending on the manufacturer, chip type and number of - chips. So this value often needs to be different for each Axis - product. - -config ETRAX_DEF_R_DRAM_TIMING - hex "R_DRAM_TIMING" - depends on !ETRAX_SDRAM - default "5611" - help - Different DRAM chips have different speeds. Current Axis products - use 50ns DRAM chips which can use the timing: 5611. - -config ETRAX_DEF_R_SDRAM_CONFIG - hex "R_SDRAM_CONFIG" - depends on ETRAX_SDRAM - default "d2fa7878" - help - The R_SDRAM_CONFIG register specifies everything on how the SDRAM - chips in the system are connected to the Etrax CPU. This is - different depending on the manufacturer, chip type and number of - chips. So this value often needs to be different for each Axis - product. - -config ETRAX_DEF_R_SDRAM_TIMING - hex "R_SDRAM_TIMING" - depends on ETRAX_SDRAM - default "80004801" - help - Different SDRAM chips have different timing. - -config ETRAX_DEF_R_PORT_PA_DIR - hex "R_PORT_PA_DIR" - default "1c" - help - Configures the direction of general port A bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_R_PORT_PA_DATA - hex "R_PORT_PA_DATA" - default "00" - help - Configures the initial data for the general port A bits. Most - products should use 00 here. - -config ETRAX_DEF_R_PORT_PB_CONFIG - hex "R_PORT_PB_CONFIG" - default "00" - help - Configures the type of the general port B bits. 1 is chip select, - 0 is port. Most products should use 00 here. - -config ETRAX_DEF_R_PORT_PB_DIR - hex "R_PORT_PB_DIR" - default "00" - help - Configures the direction of general port B bits. 1 is out, 0 is in. - This is often totally different depending on the product used. Bits - 0 and 1 on port PB are usually used for I2C communication, but the - kernel I2C driver sets the appropriate directions itself so you - don't need to take that into consideration when setting this option. - If you don't know what to use, it is always safe to put all as - inputs. - -config ETRAX_DEF_R_PORT_PB_DATA - hex "R_PORT_PB_DATA" - default "ff" - help - Configures the initial data for the general port A bits. Most - products should use FF here. - -config ETRAX_SOFT_SHUTDOWN - bool "Software Shutdown Support" - help - Enable this if Etrax is used with a power-supply that can be turned - off and on with PS_ON signal. Gives the possibility to detect - powerbutton and then do a power off after unmounting disks. - -config ETRAX_SHUTDOWN_BIT - int "Shutdown bit on port CSP0" - depends on ETRAX_SOFT_SHUTDOWN - default "12" - help - Configure what pin on CSPO-port that is used for controlling power - supply. - -config ETRAX_POWERBUTTON_BIT - int "Power button bit on port G" - depends on ETRAX_SOFT_SHUTDOWN - default "25" - help - Configure where power button is connected. - -endmenu - -source "drivers/base/Kconfig" - -# bring in Etrax built-in drivers -source "arch/cris/drivers/Kconfig" - -# standard linux drivers -source "drivers/mtd/Kconfig" - -source "drivers/parport/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/ieee1394/Kconfig" - -source "drivers/message/i2o/Kconfig" - -source "net/Kconfig" - -source "net/ax25/Kconfig" - -source "net/irda/Kconfig" - -source "drivers/isdn/Kconfig" - -source "drivers/telephony/Kconfig" - -source "drivers/cdrom/Kconfig" - -# -# input before char - char/joystick depends on it. As does USB. -# -source "drivers/input/Kconfig" - -source "drivers/char/Kconfig" - -#source drivers/misc/Config.in -source "drivers/media/Kconfig" - -source "fs/Kconfig" - - -menu "Sound" - -config SOUND - tristate "Sound card support" - ---help--- - If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - . General information about - the modular sound system is contained in the files - . The file - contains some slightly - outdated but still useful information as well. - - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - ), then you need to - compile the sound card support as a module ( = code which can be - inserted in and removed from the running kernel whenever you want) - and load that module after the PnP configuration is finished. To do - this, say M here and read as well - as ; the module will be - called soundcore. - - I'm told that even without a sound card, you can make your computer - say more than an occasional beep, by programming the PC speaker. - Kernel patches and supporting utilities to do that are in the pcsp - package, available at . - -source "sound/Kconfig" - -endmenu - -source "drivers/usb/Kconfig" - - -menu "Kernel hacking" - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -config PROFILE - bool "Kernel profiling support" - -config PROFILE_SHIFT - int "Profile shift count" - depends on PROFILE - default "2" - -endmenu - -source "security/Kconfig" - -source "crypto/Kconfig" - -source "lib/Kconfig" - +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# + +mainmenu "Linux/CRIS Kernel Configuration" + +config MMU + bool + default y + +config UID16 + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + +source "init/Kconfig" + + +menu "General setup" + +source "fs/Kconfig.binfmt" + +config ETRAX_KGDB + bool "Use kernel gdb debugger" + ---help--- + The CRIS version of gdb can be used to remotely debug a running + Linux kernel via the serial debug port. Provided you have gdb-cris + installed, run gdb-cris vmlinux, then type + + (gdb) set remotebaud 115200 <- kgdb uses 115200 as default + (gdb) target remote /dev/ttyS0 <- maybe you use another port + + This should connect you to your booted kernel (or boot it now if you + didn't before). The kernel halts when it boots, waiting for gdb if + this option is turned on! + +config ETRAX_WATCHDOG + bool "Enable ETRAX watchdog" + help + Enable the built-in watchdog timer support on ETRAX based embedded + network computers. + +config ETRAX_WATCHDOG_NICE_DOGGY + bool "Disable watchdog during Oops printouts" + depends on ETRAX_WATCHDOG + help + By enabling this you make sure that the watchdog does not bite while + printing oopses. Recommended for development systems but not for + production releases. + +config ETRAX_FAST_TIMER + bool "Enable ETRAX fast timer API" + help + This options enables the API to a fast timer implementation using + timer1 to get sub jiffie resolution timers (primarily one-shot + timers). + This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +endmenu + + +menu "Hardware setup" + +choice + prompt "Processor type" + default ETRAX100LX + +config ETRAX100LX + bool "ETRAX-100LX-v1" + help + Support version 1 of the ETRAX 100LX. + +config ETRAX100LX_V2 + bool "ETRAX-100LX-v2" + help + Support version 2 of the ETRAX 100LX. + +config SVINTO_SIM + bool "ETRAX-100LX-for-xsim-simulator" + help + Support the xsim ETRAX Simulator. + +config ETRAX200LX + bool "ETRAX-200LX-V32" + help + Support CRIS V32. + +endchoice + +config ETRAX_ARCH_V10 + bool + default y if ETRAX100LX || ETRAX100LX_V2 + default n if !(ETRAX100LX || ETRAX100LX_V2) + +config ETRAX_ARCH_V32 + bool + default y if ETRAX200LX + default n if !(ETRAX200LX) + +config ETRAX_DRAM_SIZE + int "DRAM size (dec, in MB)" + default "8" + help + Size of DRAM (decimal in MB) typically 2, 8 or 16. + +config ETRAX_FLASH_BUSWIDTH + int "Buswidth of flash in bytes" + default "2" + help + Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. + +config ETRAX_ROOT_DEVICE + string "Root device name" + default "/dev/mtdblock3" + help + Specifies the device that should be mounted as root file system + when booting from flash. The axisflashmap driver adds an additional + mtd partition for the appended root file system image, so this option + should normally be the mtdblock device for the partition after the + last partition in the partition table. + +# duplicate choice configs are not yet supported, so the followinguse +# doesn't work: + +source arch/cris/arch-v10/Kconfig + +endmenu + +# bring in ETRAX built-in drivers +menu "Drivers for built-in interfaces" + +source arch/cris/arch-v10/drivers/Kconfig + +endmenu + +source "drivers/base/Kconfig" + +# bring in Etrax built-in drivers +source "arch/cris/drivers/Kconfig" + +# standard linux drivers +source "drivers/mtd/Kconfig" + +source "drivers/parport/Kconfig" + +source "drivers/pnp/Kconfig" + +source "drivers/block/Kconfig" + +source "drivers/md/Kconfig" + +source "drivers/ide/Kconfig" + +source "drivers/scsi/Kconfig" + +source "drivers/ieee1394/Kconfig" + +source "drivers/message/i2o/Kconfig" + +source "net/Kconfig" + +source "net/ax25/Kconfig" + +source "net/irda/Kconfig" + +source "drivers/isdn/Kconfig" + +source "drivers/telephony/Kconfig" + +source "drivers/cdrom/Kconfig" + +# +# input before char - char/joystick depends on it. As does USB. +# +source "drivers/input/Kconfig" + +source "drivers/char/Kconfig" + +#source drivers/misc/Config.in +source "drivers/media/Kconfig" + +source "fs/Kconfig" + + +menu "Sound" + +config SOUND + tristate "Sound card support" + ---help--- + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. Be sure to have all the information + about your sound card and its configuration down (I/O port, + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available from + . General information about + the modular sound system is contained in the files + . The file + contains some slightly + outdated but still useful information as well. + + If you have a PnP sound card and you want to configure it at boot + time using the ISA PnP tools (read + ), then you need to + compile the sound card support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + and load that module after the PnP configuration is finished. To do + this, say M here and read as well + as ; the module will be + called soundcore. + + I'm told that even without a sound card, you can make your computer + say more than an occasional beep, by programming the PC speaker. + Kernel patches and supporting utilities to do that are in the pcsp + package, available at . + +source "sound/Kconfig" + +endmenu + +source "drivers/usb/Kconfig" + + +menu "Kernel hacking" + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +config PROFILE + bool "Kernel profiling support" + +config PROFILE_SHIFT + int "Profile shift count" + depends on PROFILE + default "2" + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff --git a/arch/cris/Makefile b/arch/cris/Makefile index 94c3671bdf5..3a1a7d91972 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2002/01/21 15:21:23 bjornw Exp $ +# $Id: Makefile,v 1.15 2003/07/04 12:47:53 tobiasa Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -13,37 +13,40 @@ # A bug in ld prevents us from having a (constant-value) symbol in a # "ORIGIN =" or "LENGTH =" expression. -LD = $(CROSS_COMPILE)ld -mcrislinux +arch-y := v10 +arch-$(CONFIG_ETRAX_ARCH_V10) := v10 + +# No config avaiable for make clean etc +ifneq ($(arch-y),) +SARCH := arch-$(arch-y) +else +SARCH := +endif -# objcopy is used to make binary images from the resulting linked file +LD = $(CROSS_COMPILE)ld -mcrislinux +LDFLAGS_BLOB := --format binary --oformat elf32-cris \ + -T arch/cris/$(SARCH)/output_arch.ld OBJCOPYFLAGS := -O binary -R .note -R .comment -S -# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others +AFLAGS_vmlinux.lds.o = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) +AFLAGS += -mlinux -CFLAGS := $(CFLAGS) -mlinux -pipe +CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif -AFLAGS += -mlinux +HEAD := arch/$(ARCH)/$(SARCH)/kernel/head.o -HEAD := arch/cris/kernel/head.o - -ifdef CONFIG_ETRAX_AXISFLASHMAP -# only build this if axis flash map is used, because they depend on -# each others config options -SUBDIRS += arch/cris/boot/rescue -endif LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) -core-y += arch/cris/kernel/ arch/cris/mm/ -drivers-y += arch/cris/drivers/ -libs-y += arch/cris/lib/lib.a $(LIBGCC) - -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ +core-y += arch/$(ARCH)/$(SARCH)/kernel/ arch/$(ARCH)/$(SARCH)/mm/ +drivers-y += arch/$(ARCH)/$(SARCH)/drivers/ +libs-y += arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC) vmlinux.bin: vmlinux $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin @@ -65,20 +68,43 @@ cramfs: clinux: vmlinux.bin decompress.bin rescue.bin decompress.bin: FORCE - @make -C arch/cris/boot/compressed decompress.bin + @make -C arch/$(ARCH)/boot/compressed decompress.bin rescue.bin: FORCE - @make -C arch/cris/boot/rescue rescue.bin + @make -C arch/$(ARCH)/boot/rescue rescue.bin -zImage: vmlinux.bin +zImage: vmlinux.bin rescue.bin ## zImage - Compressed kernel (gzip) - @$(MAKEBOOT) zImage + @make -C arch/$(ARCH)/boot/ zImage compressed: zImage +archmrproper: archclean: - @$(MAKEBOOT) clean + $(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/$(ARCH)/boot rm -f timage vmlinux.bin cramfs.img rm -rf $(LD_SCRIPT).tmp -archmrproper: +prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \ + include/asm-$(ARCH)/$(SARCH)/offset.h + +# Create some links to make all tools happy +arch/$(ARCH)/.links: + @ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers + @ln -sfn $(SARCH)/boot arch/$(ARCH)/boot + @ln -sfn $(SARCH)/lib arch/$(ARCH)/lib + @ln -sfn $(SARCH)/vmlinux.lds.S arch/$(ARCH)/vmlinux.lds.S + @touch $@ + +# Create link to sub arch includes +include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h) + @echo ' Making asm-$(ARCH)/arch -> asm-$(ARCH)/$(SARCH) symlink' + @rm -f include/asm-$(ARCH)/arch + @ln -sf $(SARCH) include/asm-$(ARCH)/arch + @touch $@ + +arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/$(SARCH)/offset.h: arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s + $(call filechk,gen-asm-offsets) diff --git a/arch/cris/Kconfig b/arch/cris/arch-v10/Kconfig similarity index 64% copy from arch/cris/Kconfig copy to arch/cris/arch-v10/Kconfig index b092fb53d4c..2ca64cc40c6 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/arch-v10/Kconfig @@ -1,127 +1,24 @@ -# -# For a description of the syntax of this configuration file, -# see the Configure script. -# - -mainmenu "Linux/CRIS Kernel Configuration" - -config MMU - bool - default y - -config UID16 - bool - default y - -config RWSEM_GENERIC_SPINLOCK - bool - default y - -config RWSEM_XCHGADD_ALGORITHM - bool - -source "init/Kconfig" - - -menu "General setup" - -source "fs/Kconfig.binfmt" - -config ETRAX_KGDB - bool "Use kernel gdb debugger" - ---help--- - The CRIS version of gdb can be used to remotely debug a running - Linux kernel via the serial debug port. Provided you have gdb-cris - installed, run gdb-cris vmlinux, then type - - (gdb) set remotebaud 115200 <- kgdb uses 115200 as default - (gdb) target remote /dev/ttyS0 <- maybe you use another port - - This should connect you to your booted kernel (or boot it now if you - didn't before). The kernel halts when it boots, waiting for gdb if - this option is turned on! - -config ETRAX_WATCHDOG - bool "Enable Etrax100 watchdog" - help - Enable the built-in watchdog timer support on Etrax100 embedded - network computers. - -config ETRAX_WATCHDOG_NICE_DOGGY - bool "Disable watchdog during Oops printouts" - depends on ETRAX_WATCHDOG - help - By enabling this you make sure that the watchdog does not bite while - printing oopses. Recommended for development systems but not for - production releases. - -endmenu - - -menu "Hardware setup" - -choice - prompt "Processor type" - default ETRAX100LX - -config ETRAX100LX - bool "Etrax-100-LX-v1" - help - Support version 1 of the Etrax 100LX. - -config ETRAX100LX_V2 - bool "Etrax-100-LX-v2" - help - Support version 2 of the Etrax 100LX. - -config SVINTO_SIM - bool "Etrax-100-LX-for-xsim-simulator" - help - Support the xsim ETRAX Simulator. - -endchoice - -# Etrax100 LX v1 has a MMU "feature" requiring a low mapping +# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping config CRIS_LOW_MAP bool - depends on ETRAX100LX + depends on ETRAX_ARCH_V10 && ETRAX100LX default y config ETRAX_DRAM_VIRTUAL_BASE hex + depends on ETRAX_ARCH_V10 default "c0000000" if !ETRAX100LX default "60000000" if ETRAX100LX -config ETRAX_DRAM_SIZE - int "DRAM size (dec, in MB)" - default "8" - help - Size of DRAM (decimal in MB) typically 2, 8 or 16. - -config ETRAX_FLASH_BUSWIDTH - int "Buswidth of flash in bytes" - default "2" - help - Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. - -config ETRAX_ROOT_DEVICE - string "Root device name" - default "/dev/mtdblock3" - help - Specifies the device that should be mounted as root file system - when booting from flash. The axisflashmap driver adds an additional - mtd partition for the appended root file system image, so this option - should normally be the mtdblock device for the partition after the - last partition in the partition table. - choice prompt "Product LED port" + depends on ETRAX_ARCH_V10 default ETRAX_PA_LEDS config ETRAX_PA_LEDS bool "Port-PA-LEDs" help - The Etrax network driver is responsible for flashing LED's when + The ETRAX network driver is responsible for flashing LED's when packets arrive and are sent. It uses macros defined in , and those macros are defined after what YOU choose in this option. The actual bits used are configured @@ -131,7 +28,7 @@ config ETRAX_PA_LEDS config ETRAX_PB_LEDS bool "Port-PB-LEDs" help - The Etrax network driver is responsible for flashing LED's when + The ETRAX network driver is responsible for flashing LED's when packets arrive and are sent. It uses macros defined in , and those macros are defined after what YOU choose in this option. The actual bits used are configured @@ -141,7 +38,7 @@ config ETRAX_PB_LEDS config ETRAX_CSP0_LEDS bool "Port-CSP0-LEDs" help - The Etrax network driver is responsible for flashing LED's when + The ETRAX network driver is responsible for flashing LED's when packets arrive and are sent. It uses macros defined in , and those macros are defined after what YOU choose in this option. The actual bits used are configured @@ -158,7 +55,7 @@ endchoice config ETRAX_LED1G int "First green LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "2" help Bit to use for the first green LED. @@ -166,7 +63,7 @@ config ETRAX_LED1G config ETRAX_LED1R int "First red LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "3" help Bit to use for the first red LED. @@ -176,7 +73,7 @@ config ETRAX_LED1R config ETRAX_LED2G int "Second green LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "4" help Bit to use for the second green LED. The "Active" LED. @@ -186,7 +83,7 @@ config ETRAX_LED2G config ETRAX_LED2R int "Second red LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "5" help Bit to use for the second red LED. @@ -196,7 +93,7 @@ config ETRAX_LED2R config ETRAX_LED3G int "Third green LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "2" help Bit to use for the third green LED. The "Drive" LED. @@ -205,7 +102,7 @@ config ETRAX_LED3G config ETRAX_LED3R int "Third red LED bit" - depends on !ETRAX_NO_LEDS + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS default "2" help Bit to use for the third red LED. @@ -331,6 +228,7 @@ config ETRAX_LED12R choice prompt "Product debug-port" + depends on ETRAX_ARCH_V10 default ETRAX_DEBUG_PORT0 config ETRAX_DEBUG_PORT0 @@ -363,6 +261,7 @@ endchoice choice prompt "Product rescue-port" + depends on ETRAX_ARCH_V10 default ETRAX_RESCUE_SER0 config ETRAX_RESCUE_SER0 @@ -390,6 +289,7 @@ endchoice config ETRAX_DEF_R_WAITSTATES hex "R_WAITSTATES" + depends on ETRAX_ARCH_V10 default "95a6" help Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a @@ -397,6 +297,7 @@ config ETRAX_DEF_R_WAITSTATES config ETRAX_DEF_R_BUS_CONFIG hex "R_BUS_CONFIG" + depends on ETRAX_ARCH_V10 default "104" help Assorted bits controlling write mode, DMA burst length etc. 104 is @@ -404,24 +305,25 @@ config ETRAX_DEF_R_BUS_CONFIG config ETRAX_SDRAM bool "SDRAM support" + depends on ETRAX_ARCH_V10 help Enable this if you use SDRAM chips and configure R_SDRAM_CONFIG and R_SDRAM_TIMING as well. config ETRAX_DEF_R_DRAM_CONFIG hex "R_DRAM_CONFIG" - depends on !ETRAX_SDRAM + depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM default "1a200040" help The R_DRAM_CONFIG register specifies everything on how the DRAM - chips in the system are connected to the Etrax CPU. This is + chips in the system are connected to the ETRAX CPU. This is different depending on the manufacturer, chip type and number of chips. So this value often needs to be different for each Axis product. config ETRAX_DEF_R_DRAM_TIMING hex "R_DRAM_TIMING" - depends on !ETRAX_SDRAM + depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM default "5611" help Different DRAM chips have different speeds. Current Axis products @@ -429,24 +331,25 @@ config ETRAX_DEF_R_DRAM_TIMING config ETRAX_DEF_R_SDRAM_CONFIG hex "R_SDRAM_CONFIG" - depends on ETRAX_SDRAM + depends on ETRAX_ARCH_V10 && ETRAX_SDRAM default "d2fa7878" help The R_SDRAM_CONFIG register specifies everything on how the SDRAM - chips in the system are connected to the Etrax CPU. This is + chips in the system are connected to the ETRAX CPU. This is different depending on the manufacturer, chip type and number of chips. So this value often needs to be different for each Axis product. config ETRAX_DEF_R_SDRAM_TIMING hex "R_SDRAM_TIMING" - depends on ETRAX_SDRAM + depends on ETRAX_ARCH_V10 && ETRAX_SDRAM default "80004801" help Different SDRAM chips have different timing. config ETRAX_DEF_R_PORT_PA_DIR hex "R_PORT_PA_DIR" + depends on ETRAX_ARCH_V10 default "1c" help Configures the direction of general port A bits. 1 is out, 0 is in. @@ -460,6 +363,7 @@ config ETRAX_DEF_R_PORT_PA_DIR config ETRAX_DEF_R_PORT_PA_DATA hex "R_PORT_PA_DATA" + depends on ETRAX_ARCH_V10 default "00" help Configures the initial data for the general port A bits. Most @@ -467,6 +371,7 @@ config ETRAX_DEF_R_PORT_PA_DATA config ETRAX_DEF_R_PORT_PB_CONFIG hex "R_PORT_PB_CONFIG" + depends on ETRAX_ARCH_V10 default "00" help Configures the type of the general port B bits. 1 is chip select, @@ -474,6 +379,7 @@ config ETRAX_DEF_R_PORT_PB_CONFIG config ETRAX_DEF_R_PORT_PB_DIR hex "R_PORT_PB_DIR" + depends on ETRAX_ARCH_V10 default "00" help Configures the direction of general port B bits. 1 is out, 0 is in. @@ -486,6 +392,7 @@ config ETRAX_DEF_R_PORT_PB_DIR config ETRAX_DEF_R_PORT_PB_DATA hex "R_PORT_PB_DATA" + depends on ETRAX_ARCH_V10 default "ff" help Configures the initial data for the general port A bits. Most @@ -493,8 +400,9 @@ config ETRAX_DEF_R_PORT_PB_DATA config ETRAX_SOFT_SHUTDOWN bool "Software Shutdown Support" + depends on ETRAX_ARCH_V10 help - Enable this if Etrax is used with a power-supply that can be turned + Enable this if ETRAX is used with a power-supply that can be turned off and on with PS_ON signal. Gives the possibility to detect powerbutton and then do a power off after unmounting disks. @@ -512,113 +420,3 @@ config ETRAX_POWERBUTTON_BIT default "25" help Configure where power button is connected. - -endmenu - -source "drivers/base/Kconfig" - -# bring in Etrax built-in drivers -source "arch/cris/drivers/Kconfig" - -# standard linux drivers -source "drivers/mtd/Kconfig" - -source "drivers/parport/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/ieee1394/Kconfig" - -source "drivers/message/i2o/Kconfig" - -source "net/Kconfig" - -source "net/ax25/Kconfig" - -source "net/irda/Kconfig" - -source "drivers/isdn/Kconfig" - -source "drivers/telephony/Kconfig" - -source "drivers/cdrom/Kconfig" - -# -# input before char - char/joystick depends on it. As does USB. -# -source "drivers/input/Kconfig" - -source "drivers/char/Kconfig" - -#source drivers/misc/Config.in -source "drivers/media/Kconfig" - -source "fs/Kconfig" - - -menu "Sound" - -config SOUND - tristate "Sound card support" - ---help--- - If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - . General information about - the modular sound system is contained in the files - . The file - contains some slightly - outdated but still useful information as well. - - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - ), then you need to - compile the sound card support as a module ( = code which can be - inserted in and removed from the running kernel whenever you want) - and load that module after the PnP configuration is finished. To do - this, say M here and read as well - as ; the module will be - called soundcore. - - I'm told that even without a sound card, you can make your computer - say more than an occasional beep, by programming the PC speaker. - Kernel patches and supporting utilities to do that are in the pcsp - package, available at . - -source "sound/Kconfig" - -endmenu - -source "drivers/usb/Kconfig" - - -menu "Kernel hacking" - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -config PROFILE - bool "Kernel profiling support" - -config PROFILE_SHIFT - int "Profile shift count" - depends on PROFILE - default "2" - -endmenu - -source "security/Kconfig" - -source "crypto/Kconfig" - -source "lib/Kconfig" - diff --git a/arch/cris/README.mm b/arch/cris/arch-v10/README.mm similarity index 99% rename from arch/cris/README.mm rename to arch/cris/arch-v10/README.mm index 195ca898b55..6f08903f313 100644 --- a/arch/cris/README.mm +++ b/arch/cris/arch-v10/README.mm @@ -3,8 +3,8 @@ Memory management for CRIS/MMU HISTORY: $Log: README.mm,v $ -Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -Import of Linux 2.5.1 +Revision 1.1 2001/12/17 13:59:27 bjornw +Initial revision Revision 1.1 2000/07/10 16:25:21 bjornw Initial revision diff --git a/arch/cris/boot/Makefile b/arch/cris/arch-v10/boot/Makefile similarity index 100% rename from arch/cris/boot/Makefile rename to arch/cris/arch-v10/boot/Makefile diff --git a/arch/cris/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile similarity index 100% rename from arch/cris/boot/compressed/Makefile rename to arch/cris/arch-v10/boot/compressed/Makefile diff --git a/arch/cris/boot/compressed/README b/arch/cris/arch-v10/boot/compressed/README similarity index 95% rename from arch/cris/boot/compressed/README rename to arch/cris/arch-v10/boot/compressed/README index 349eb2ab466..48b3db9924b 100644 --- a/arch/cris/boot/compressed/README +++ b/arch/cris/arch-v10/boot/compressed/README @@ -1,6 +1,6 @@ Creation of the self-extracting compressed kernel image (vmlinuz) ----------------------------------------------------------------- -$Id: README,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +$Id: README,v 1.1 2001/12/17 13:59:27 bjornw Exp $ This can be slightly confusing because it's a process with many steps. diff --git a/arch/cris/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld similarity index 95% rename from arch/cris/boot/compressed/decompress.ld rename to arch/cris/arch-v10/boot/compressed/decompress.ld index 24be5492497..0b0a14fe617 100644 --- a/arch/cris/boot/compressed/decompress.ld +++ b/arch/cris/arch-v10/boot/compressed/decompress.ld @@ -13,6 +13,7 @@ SECTIONS _stext = . ; *(.text) *(.rodata) + *(.rodata.*) _etext = . ; } > dram .data : diff --git a/arch/cris/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S similarity index 98% rename from arch/cris/boot/compressed/head.S rename to arch/cris/arch-v10/boot/compressed/head.S index 84719ff1440..4cbdd4b1d9d 100644 --- a/arch/cris/boot/compressed/head.S +++ b/arch/cris/arch-v10/boot/compressed/head.S @@ -10,7 +10,7 @@ #include #define ASSEMBLER_MACROS_ONLY -#include +#include #define RAM_INIT_MAGIC 0x56902387 diff --git a/arch/cris/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c similarity index 97% rename from arch/cris/boot/compressed/misc.c rename to arch/cris/arch-v10/boot/compressed/misc.c index 906610b4562..9969c6242f7 100644 --- a/arch/cris/boot/compressed/misc.c +++ b/arch/cris/arch-v10/boot/compressed/misc.c @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ + * $Id: misc.c,v 1.4 2003/04/09 05:20:45 starvik Exp $ * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. @@ -15,7 +15,7 @@ /* where the piggybacked kernel image expects itself to live. * it is the same address we use when we network load an uncompressed * image into DRAM, and it is the address the kernel is linked to live - * at by etrax100.ld. + * at by vmlinux.lds.S */ #define KERNEL_LOAD_ADR 0x40004000 @@ -23,7 +23,7 @@ #include #include -#include +#include /* * gzip declarations @@ -109,7 +109,7 @@ static void puts(const char *); extern int end; static long free_mem_ptr = (long)&end; -#include "../../../../lib/inflate.c" +#include "../../../../../lib/inflate.c" static void *malloc(int size) { diff --git a/arch/cris/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile similarity index 100% rename from arch/cris/boot/rescue/Makefile rename to arch/cris/arch-v10/boot/rescue/Makefile diff --git a/arch/cris/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S similarity index 96% rename from arch/cris/boot/rescue/head.S rename to arch/cris/arch-v10/boot/rescue/head.S index 52881742da4..8689ea972c4 100644 --- a/arch/cris/boot/rescue/head.S +++ b/arch/cris/arch-v10/boot/rescue/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.2 2001/12/18 13:35:12 bjornw Exp $ +/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $ * * Rescue code, made to reside at the beginning of the * flash-memory. when it starts, it checks a partition @@ -52,7 +52,7 @@ * * Bit 0 in flags signifies RW or RO. The rescue code only bothers * to check the checksum for RO partitions, since the others will - * change its data without updating the checksums. A 1 in bit 0 + * change their data without updating the checksums. A 1 in bit 0 * means RO, 0 means RW. That way, it is possible to set a partition * in RO mode initially, and later mark it as RW, since you can always * write 0's to the flash. @@ -60,12 +60,12 @@ * During the wait for serial input, the status LED will flash so the * user knows something went wrong. * - * Copyright (C) 1999,2001 Axis Communications AB + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB */ #include #define ASSEMBLER_MACROS_ONLY -#include +#include ;; The partitiontable is looked for at the first sector after the boot ;; sector. Sector size is 65536 bytes in all flashes we use. @@ -192,7 +192,7 @@ no_newjump: moveq -1, $r7 ploop: move.d [$r3+], $r1 ; partition offset (from ptable start) - bne notfirst ; check if its the partition containing ptable + bne notfirst ; check if it is the partition containing ptable nop ; yes.. move.d $r8, $r1 ; for its checksum check, skip the ptable move.d [$r3+], $r2 ; partition length diff --git a/arch/cris/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S similarity index 98% rename from arch/cris/boot/rescue/kimagerescue.S rename to arch/cris/arch-v10/boot/rescue/kimagerescue.S index 270774108b7..264bf7afc9a 100644 --- a/arch/cris/boot/rescue/kimagerescue.S +++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S @@ -1,4 +1,4 @@ -/* $Id: kimagerescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Rescue code to be prepended on a kimage and copied to the * rescue serial port. diff --git a/arch/cris/boot/rescue/rescue.ld b/arch/cris/arch-v10/boot/rescue/rescue.ld similarity index 100% rename from arch/cris/boot/rescue/rescue.ld rename to arch/cris/arch-v10/boot/rescue/rescue.ld diff --git a/arch/cris/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S similarity index 85% rename from arch/cris/boot/rescue/testrescue.S rename to arch/cris/arch-v10/boot/rescue/testrescue.S index f39c69e2648..566a9f34125 100644 --- a/arch/cris/boot/rescue/testrescue.S +++ b/arch/cris/arch-v10/boot/rescue/testrescue.S @@ -1,4 +1,4 @@ -/* $Id: testrescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Simple testcode to download by the rescue block. * Just lits some LEDs to show it was downloaded correctly. diff --git a/arch/cris/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c similarity index 100% rename from arch/cris/boot/tools/build.c rename to arch/cris/arch-v10/boot/tools/build.c diff --git a/arch/cris/defconfig b/arch/cris/arch-v10/defconfig similarity index 100% copy from arch/cris/defconfig copy to arch/cris/arch-v10/defconfig diff --git a/arch/cris/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig similarity index 50% rename from arch/cris/drivers/Kconfig rename to arch/cris/arch-v10/drivers/Kconfig index fef010d3722..7b0684d07fc 100644 --- a/arch/cris/drivers/Kconfig +++ b/arch/cris/arch-v10/drivers/Kconfig @@ -1,8 +1,6 @@ - -menu "Drivers for ETRAX 100LX built-in interfaces" - config ETRAX_ETHERNET bool "Ethernet support" + depends on ETRAX_ARCH_V10 help This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet controller. @@ -45,51 +43,39 @@ choice config ETRAX_NETWORK_LED_ON_WHEN_LINK bool "LED_on_when_link" help - Selecting LED_on_when_link will light the LED when there is a - connection and will flash off when there is activity. + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. - Selecting LED_on_when_activity will light the LED only when + Selecting LED_on_when_activity will light the LED only when there is activity. - This setting will also affect the behaviour of other activity LEDs - e.g. Bluetooth. + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY bool "LED_on_when_activity" help - Selecting LED_on_when_link will light the LED when there is a - connection and will flash off when there is activity. + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. - Selecting LED_on_when_activity will light the LED only when + Selecting LED_on_when_activity will light the LED only when there is activity. - This setting will also affect the behaviour of other activity LEDs - e.g. Bluetooth. + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. endchoice -config ETRAX_ETHERNET_LPSLAVE - bool "Etrax Ethernet slave support (over lp0/1)" - help - This option enables a slave ETRAX 100 or ETRAX 100LX, connected to a - master ETRAX 100 or ETRAX 100LX through par0 and par1, to act as an - Ethernet controller. - -config ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - bool "Slave has its own LEDs" - depends on ETRAX_ETHERNET_LPSLAVE - help - Enable if the slave has it's own LEDs. - config ETRAX_SERIAL bool "Serial-port support" + depends on ETRAX_ARCH_V10 help Enables the ETRAX 100 serial driver for ser0 (ttyS0) You probably want this enabled. -# bool ' Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n config ETRAX_SERIAL_FAST_TIMER - bool + bool "Use fast timers for serial DMA flush (experimental)" + depends on ETRAX_SERIAL help Select this to have the serial DMAs flushed at a higher rate than normally, possible by using the fast timer API, the timeout is @@ -107,7 +93,7 @@ config ETRAX_SERIAL_FLUSH_DMA_FAST config ETRAX_SERIAL_RX_TIMEOUT_TICKS int "Receive flush timeout (ticks) " - depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX100_SERIAL_FLUSH_DMA_FAST + depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX_SERIAL_FLUSH_DMA_FAST default "5" help Number of timer ticks between flush of receive fifo (1 tick = 10ms). @@ -123,41 +109,84 @@ config ETRAX_SERIAL_PORT0 Normally you want this on, unless you use external DMA 1 that uses the same DMA channels. -config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - bool "Ser0 DTR, RI, DSR, CD on PB" +choice + prompt "Ser0 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT0 + default ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" help Enables the status and control signals DTR, RI, DSR and CD on PB for ser0. +config ETRAX_SER0_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER0_DTR_ON_PA_BIT + int "Ser0 DTR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_RI_ON_PA_BIT + int "Ser0 RI on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_DSR_ON_PA_BIT + int "Ser0 DSR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_CD_ON_PA_BIT + int "Ser0 CD on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + config ETRAX_SER0_DTR_ON_PB_BIT - int "Ser0 DTR on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "4" + int "Ser0 DTR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DTR signal for serial port 0. config ETRAX_SER0_RI_ON_PB_BIT - int "Ser0 RI on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "5" + int "Ser0 RI on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the RI signal for serial port 0. config ETRAX_SER0_DSR_ON_PB_BIT - int "Ser0 DSR on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "6" + int "Ser0 DSR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DSR signal for serial port 0. config ETRAX_SER0_CD_ON_PB_BIT - int "Ser0 CD on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "7" + int "Ser0 CD on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the CD signal for serial port 0. @@ -168,41 +197,84 @@ config ETRAX_SERIAL_PORT1 help Enables the ETRAX 100 serial driver for ser1 (ttyS1). -config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - bool "Ser1 DTR, RI, DSR, CD on PB" +choice + prompt "Ser1 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT1 + default ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" help Enables the status and control signals DTR, RI, DSR and CD on PB for ser1. +config ETRAX_SER1_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER1_DTR_ON_PA_BIT + int "Ser1 DTR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_RI_ON_PA_BIT + int "Ser1 RI on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_DSR_ON_PA_BIT + int "Ser1 DSR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_CD_ON_PA_BIT + int "Ser1 CD on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + config ETRAX_SER1_DTR_ON_PB_BIT - int "Ser1 DTR on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "4" + int "Ser1 DTR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DTR signal for serial port 1. config ETRAX_SER1_RI_ON_PB_BIT - int "Ser1 RI on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "5" + int "Ser1 RI on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the RI signal for serial port 1. config ETRAX_SER1_DSR_ON_PB_BIT - int "Ser1 DSR on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "6" + int "Ser1 DSR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DSR signal for serial port 1. config ETRAX_SER1_CD_ON_PB_BIT - int "Ser1 CD on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "7" + int "Ser1 CD on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the CD signal for serial port 1. @@ -216,51 +288,153 @@ config ETRAX_SERIAL_PORT2 help Enables the ETRAX 100 serial driver for ser2 (ttyS2). -config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - bool "Ser2 DTR, RI, DSR, CD on PA" +choice + prompt "Ser2 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT2 + default ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" help Enables the status and control signals DTR, RI, DSR and CD on PA for ser2. +config ETRAX_SER2_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" + +config ETRAX_SER2_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + config ETRAX_SER2_DTR_ON_PA_BIT - int "Ser2 DTR on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "4" + int "Ser2 DTR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the DTR signal for serial port 2. config ETRAX_SER2_RI_ON_PA_BIT - int "Ser2 RI on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "5" + int "Ser2 RI on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the RI signal for serial port 2. config ETRAX_SER2_DSR_ON_PA_BIT - int "Ser2 DSR on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "6" + int "Ser2 DSR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the DTR signal for serial port 2. config ETRAX_SER2_CD_ON_PA_BIT - int "Ser2 CD on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "7" + int "Ser2 CD on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the CD signal for serial port 2. +config ETRAX_SER2_DTR_ON_PB_BIT + int "Ser2 DTR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_RI_ON_PB_BIT + int "Ser2 RI on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_DSR_ON_PB_BIT + int "Ser2 DSR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_CD_ON_PB_BIT + int "Ser2 CD on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + config ETRAX_SERIAL_PORT3 bool "Serial port 3 enabled" depends on ETRAX_SERIAL help Enables the ETRAX 100 serial driver for ser3 (ttyS3). +choice + prompt "Ser3 DTR, RI, DSR and CD assignment" + depends on ETRAX_SERIAL_PORT3 + default ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" + +config ETRAX_SER3_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER3_DTR_ON_PA_BIT + int "Ser3 DTR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_RI_ON_PA_BIT + int "Ser3 RI on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DSR_ON_PA_BIT + int "Ser3 DSR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_CD_ON_PA_BIT + int "Ser3 CD on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DTR_ON_PB_BIT + int "Ser3 DTR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_RI_ON_PB_BIT + int "Ser3 RI on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DSR_ON_PB_BIT + int "Ser3 DSR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_CD_ON_PB_BIT + int "Ser3 CD on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + config ETRAX_RS485 bool "RS-485 support" depends on ETRAX_SERIAL @@ -272,7 +446,7 @@ config ETRAX_RS485_ON_PA bool "RS-485 mode on PA" depends on ETRAX_RS485 help - Control Driver Output Enable on RS485 tranceiver using a pin on PA + Control Driver Output Enable on RS485 transceiver using a pin on PA port: Axis 2400/2401 uses PA 3. @@ -281,7 +455,7 @@ config ETRAX_RS485_ON_PA_BIT depends on ETRAX_RS485_ON_PA default "3" help - Control Driver Output Enable on RS485 tranceiver using a this bit + Control Driver Output Enable on RS485 transceiver using a this bit on PA port. config ETRAX_RS485_DISABLE_RECEIVER @@ -292,299 +466,9 @@ config ETRAX_RS485_DISABLE_RECEIVER loopback. Not all products are able to do this in software only. Axis 2400/2401 must disable receiver. -config ETRAX_SYNCHRONOUS_SERIAL - bool "Synchronous serial port support" - help - This option enables support for the ETRAX 100LX built-in - synchronous serial ports. These ports are used for continuous - streamed data like audio. The default setting is compatible - with the STA 013 MP3 decoder, but can easily be tuned to fit - any other audio encoder/decoder and SPI. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT0 - bool "Synchronous serial port 0 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL - help - Enables the ETRAX 100LX synchronous serial port 0 (syncser0). - -config ETRAX_SYNCHRONOUS_SERIAL0_DMA - bool "Synchronous serial port 0 uses DMA" - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0 - help - Makes synchronous serial port 0 use DMA. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT1 - bool "Synchronous serial port 1 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL - help - Enables the ETRAX 100LX synchronous serial port 1 (syncser1). - -config ETRAX_SYNCHRONOUS_SERIAL1_DMA - bool "Synchronous serial port 1 uses DMA" - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1 - help - Makes synchronous serial port 1 use DMA. - -config ETRAX_PARPORT - bool "Parallel port support" - help - Say Y here to enable the ETRAX on-board parallel ports. - -config ETRAX_PARALLEL_PORT0 - bool "Parallel port 0 enabled" - depends on ETRAX_PARPORT - help - Say Y here to enable parallel port 0. - -config ETRAX_PARALLEL_PORT1 - bool "Parallel port 1 enabled" - depends on ETRAX_PARPORT - help - Say Y here to enable parallel port 1. - -# here we define the CONFIG_'s necessary to enable parallel port support -config PARPORT - tristate - depends on ETRAX_PARPORT - default y - ---help--- - If you want to use devices connected to your machine's parallel port - (the connector at the computer with 25 holes), e.g. printer, ZIP - drive, PLIP link (Parallel Line Internet Protocol is mainly used to - create a mini network by connecting the parallel ports of two local - machines) etc., then you need to say Y here; please read - and - . - - For extensive information about drivers for many devices attaching - to the parallel port see on - the WWW. - - It is possible to share a single parallel port among several devices - and it is safe to compile all the corresponding drivers into the - kernel. If you want to compile parallel port support as a module - ( = code which can be inserted in and removed from the running - kernel whenever you want), say M here and read - . The module will be called - parport. If you have more than one parallel port and want to - specify which port and IRQ to be used by this driver at module load - time, take a look at . - - If unsure, say Y. - -config PARPORT_1284 - bool - depends on ETRAX_PARPORT - default y - help - If you have a printer that supports status readback or device ID, or - want to use a device that uses enhanced parallel port transfer modes - such as EPP and ECP, say Y here to enable advanced IEEE 1284 - transfer modes. Also say Y if you want device ID information to - appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. - -config PRINTER - tristate - depends on ETRAX_PARPORT - default y - ---help--- - If you intend to attach a printer to the parallel port of your Linux - box (as opposed to using a serial printer; if the connector at the - printer has 9 or 25 holes ["female"], then it's serial), say Y. - Also read the Printing-HOWTO, available from - . - - It is possible to share one parallel port among several devices - (e.g. printer and ZIP drive) and it is safe to compile the - corresponding drivers into the kernel. If you want to compile this - driver as a module however ( = code which can be inserted in and - removed from the running kernel whenever you want), say M here and - read and - . The module will be called lp. - - If you have several parallel ports, you can specify which ports to - use with the "lp" kernel command line option. (Try "man bootparam" - or see the documentation of your boot loader (lilo or loadlin) about - how to pass options to the kernel at boot time.) The syntax of the - "lp" command line option can be found in . - - If you have more than 8 printers, you need to increase the LP_NO - macro in lp.c and the PARPORT_MAX macro in parport.h. - -config ETRAX_IDE - bool "ATA/IDE support" - help - Enable this to get support for ATA/IDE. You can't use parallel - ports or SCSI ports at the same time. - -# here we should add the CONFIG_'s necessary to enable the basic -# general ide drivers so the common case does not need to go -# into that config submenu. enable disk and CD support. others -# need to go fiddle in the submenu.. -config IDE - tristate - depends on ETRAX_IDE - default y - ---help--- - If you say Y here, your kernel will be able to manage low cost mass - storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CD-ROM drives. - - If your system is pure SCSI and doesn't use these interfaces, you - can say N here. - - Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard - for mass storage units such as hard disks. It was designed by - Western Digital and Compaq Computer in 1984. It was then named - ST506. Quite a number of disks use the IDE interface. - - AT Attachment (ATA) is the superset of the IDE specifications. - ST506 was also called ATA-1. - - Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is - ATA-3. It provides support for larger disks (up to 8.4GB by means of - the LBA standard), more disks (4 instead of 2) and for other mass - storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is - ATA-4 and provides faster (and more CPU friendly) transfer modes - than previous PIO (Programmed processor Input/Output) from previous - ATA/IDE standards by means of fast DMA controllers. - - ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CD-ROM drives, similar in many respects to the SCSI protocol. - - SMART IDE (Self Monitoring, Analysis and Reporting Technology) was - designed in order to prevent data corruption and disk crash by - detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this standard. - The kernel itself don't manage this; however there are quite a - number of user programs such as smart that can query the status of - SMART parameters disk. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ide. - - For further information, please read . - - If unsure, say Y. - -config BLK_DEV_IDE - tristate - depends on ETRAX_IDE - default y - ---help--- - If you say Y here, you will use the full-featured IDE driver to - control up to ten ATA/IDE interfaces, each being able to serve a - "master" and a "slave" device, for a total of up to twenty ATA/IDE - disk/cdrom/tape/floppy drives. - - Useful information about large (>540 MB) IDE disks, multiple - interfaces, what to do if ATA/IDE devices are not automatically - detected, sound card ATA/IDE ports, module support, and other - topics, is contained in . For detailed - information about hard drives, consult the Disk-HOWTO and the - Multi-Disk-HOWTO, available from - . - - To fine-tune ATA/IDE drive/interface parameters for improved - performance, look for the hdparm package at - . - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called ide-mod. - Do not compile this driver as a module if your root file system (the - one containing the directory /) is located on an IDE device. - - If you have one or more IDE drives, say Y or M here. If your system - has no IDE drives, or if memory requirements are really tight, you - could say N here, and select the "Old hard disk driver" below - instead to save about 13 KB of memory in the kernel. - -config BLK_DEV_IDEDISK - tristate - depends on ETRAX_IDE - default y - ---help--- - This will include enhanced support for MFM/RLL/IDE hard disks. If - you have a MFM/RLL/IDE disk, and there is no special reason to use - the old hard disk driver instead, say Y. If you have an SCSI-only - system, you can say N here. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ide-disk. Do not compile this driver as a module - if your root file system (the one containing the directory /) is - located on the IDE disk. If unsure, say Y. - -config BLK_DEV_IDECD - tristate - depends on ETRAX_IDE - default y - ---help--- - If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is - a newer protocol used by IDE CD-ROM and TAPE drives, similar to the - SCSI protocol. Most new CD-ROM drives use ATAPI, including the - NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI - double(2X) or better speed drives. - - If you say Y here, the CD-ROM drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar (check the boot messages with dmesg). If this is your only - CD-ROM drive, you can say N to all other CD-ROM options, but be sure - to say Y or M to "ISO 9660 CD-ROM file system support". - - Note that older versions of LILO (LInux LOader) cannot properly deal - with IDE/ATAPI CD-ROMs, so install LILO 16 or higher, available from - . - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called ide-cd. - -config BLK_DEV_IDEDMA - bool - depends on ETRAX_IDE - default y - -config ETRAX_IDE_DELAY - int "Delay for drives to regain consciousness" - depends on ETRAX_IDE - default "15" - help - Sets the time to wait for disks to regain consciousness after reset. - -choice - prompt "IDE reset pin" - depends on ETRAX_IDE - default ETRAX_IDE_PB7_RESET - -config ETRAX_IDE_PB7_RESET - bool "Port_PB_Bit_7" - help - Configures the pin used to reset the IDE bus. - -config ETRAX_IDE_G27_RESET - bool "Port_G_Bit_27" - help - Configures the pin used to reset the IDE bus. - -config ETRAX_IDE_CSE1_16_RESET - bool "Port_CSE1_Bit_16" - -config ETRAX_IDE_CSP0_8_RESET - bool "Port_CSP0_Bit_08" - help - Configures the pin used to reset the IDE bus. - -endchoice - config ETRAX_AXISFLASHMAP bool "Axis flash-map support" + depends on ETRAX_ARCH_V10 help This option enables MTD mapping of flash devices. Needed to use flash memories. If unsure, say Y. @@ -637,6 +521,19 @@ config MTD_CFI_AMDSTD provides support for one of those command sets, used on chips chips including the AMD Am29LV320. +config MTD_OBSOLETE_CHIPS + bool + depends on ETRAX_AXISFLASHMAP + default y + help + This option does not enable any code directly, but will allow you to + select some other chip drivers which are now considered obsolete, + because the generic CONFIG_JEDEC_PROBE code above should now detect + the chips which are supported by these drivers, and allow the generic + CFI-compatible drivers to drive the chips. Say 'N' here unless you have + already tried the CONFIG_JEDEC_PROBE method and reported its failure + to the MTD mailing list at + config MTD_AMDSTD tristate depends on ETRAX_AXISFLASHMAP @@ -695,10 +592,16 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +config MTD_CONCAT + tristate + depends on ETRAX_AXISFLASHMAP + default y + config ETRAX_I2C bool "I2C support" + depends on ETRAX_ARCH_V10 help - Enables an I2C driver on PB0 and PB1 on ETRAX100. + Enables an I2C driver on ETRAX100. EXAMPLE usage: i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); @@ -717,8 +620,23 @@ config ETRAX_I2C_USES_PB_NOT_PB_I2C I2C driver, like the DS1302 realtime-clock driver. If you are uncertain, choose Y here. +config ETRAX_I2C_DATA_PORT + int "I2C SDA bit number" + depends on ETRAX_I2C_USES_PB_NOT_PB_I2C + default "0" + help + Selects the pin on Port B where the data pin is connected + +config ETRAX_I2C_CLK_PORT + int "I2C SCL bit number" + depends on ETRAX_I2C_USES_PB_NOT_PB_I2C + default "1" + help + Select the pin on Port B where the clock pin is connected + config ETRAX_I2C_EEPROM bool "I2C EEPROM (non-volatile RAM) support" + depends on ETRAX_I2C help Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C driver. Select size option: Probed, 2k, 8k, 16k. @@ -755,8 +673,9 @@ endchoice config ETRAX_GPIO bool "GPIO support" + depends on ETRAX_ARCH_V10 ---help--- - Enables the Etrax general port device (major 120, minors 0 and 1). + Enables the ETRAX general port device (major 120, minors 0 and 1). You can use this driver to access the general port bits. It supports these ioctl's: #include @@ -778,7 +697,7 @@ config ETRAX_PA_BUTTON_BITMASK use 02 here. Use 00 if there are no buttons on PA. If the bitmask is <> 00 a button driver will be included in the gpio - driver. Etrax general I/O support must be enabled. + driver. ETRAX general I/O support must be enabled. config ETRAX_PA_CHANGEABLE_DIR hex "PA user changeable dir mask" @@ -820,71 +739,37 @@ config ETRAX_PB_CHANGEABLE_BITS Bit set = changeable. You probably want 00 here. -#bool 'ARTPEC-1 support' CONFIG_JULIETTE -# -#if [ "$CONFIG_JULIETTE" = "y" ]; then -# source arch/cris/drivers/juliette/Config.in -#fi -config ETRAX_USB_HOST - bool "USB host" +config ETRAX_RTC + bool "Real Time Clock support" + depends on ETRAX_ARCH_V10 help - This option enables the host functionality of the ETRAX 100LX - built-in USB controller. In host mode the controller is designed - for CTRL and BULK traffic only, INTR traffic may work as well - however (depending on the requirements of timeliness). - -config USB - tristate - depends on ETRAX_USB_HOST - default y - ---help--- - Universal Serial Bus (USB) is a specification for a serial bus - subsystem which offers higher speeds and more features than the - traditional PC serial port. The bus supplies power to peripherals - and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB port in a tree structure. The USB port is - the root of the tree, the peripherals are the leaves and the inner - nodes are special USB devices called hubs. Many newer PC's have USB - ports and newer peripherals such as scanners, keyboards, mice, - modems, and printers support the USB protocol and can be connected - to the PC via those ports. - - Say Y here if your computer has a USB port and you want to use USB - devices. You then need to say Y to at least one of "UHCI support" - or "OHCI support" below (the type of interface that the USB hardware - in your computer provides to the operating system) and then choose - from among the drivers for USB peripherals. You may want to check - out the information provided in and - especially the links given in . - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usbcore. If you want to compile it as a - module, say M here and read . - -config ETRAX_USB_HOST_PORT1 - bool "USB port 1 enabled" - depends on ETRAX_USB_HOST - help - This option enables port 1 of the ETRAX 100LX USB root hub (RH). - -config ETRAX_USB_HOST_PORT2 - bool "USB port 2 enabled" - depends on ETRAX_USB_HOST - help - This option enables port 2 of the ETRAX 100LX USB root hub (RH). - -config ETRAX_DS1302 - bool "DS1302 Real Time Clock support" - help - Enables the driver for the DS1302 Real-Time Clock battery-backed - chip on some products. The kernel reads the time when booting, and + Enables drivers for the Real-Time Clock battery-backed chips on + some products. The kernel reads the time when booting, and the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a rtc_time struct (see ) on the /dev/rtc device, major 121. You can check the time with cat /proc/rtc, but normal time reading should be done using libc function time and friends. +choice + prompt "RTC chip" + depends on ETRAX_RTC + default ETRAX_DS1302 + +config ETRAX_DS1302 + bool "DS1302" + help + Enables the driver for the DS1302 Real-Time Clock battery-backed + chip on some products. + +config ETRAX_PCF8563 + bool "PCF8563" + help + Enables the driver for the PCF8563 Real-Time Clock battery-backed + chip on some products. + +endchoice + config ETRAX_DS1302_RST_ON_GENERIC_PORT bool "DS1302 RST on Generic Port" depends on ETRAX_DS1302 @@ -919,5 +804,17 @@ config ETRAX_DS1302_SDABIT This is the bit number for the SDA signal line of the DS1302 RTC on Port PB. This is probably best left at 2. -endmenu +config ETRAX_DS1302_TRICKLE_CHARGE + int "DS1302 Trickle charger value" + depends on ETRAX_DS1302 + default "0" + help + This controls the initial value of the trickle charge register. + 0 = disabled (use this if you are unsure or have a non rechargable battery) + Otherwise the following values can be OR:ed together to control the + charge current: + 1 = 2kohm, 2 = 4kohm, 3 = 4kohm + 4 = 1 diode, 8 = 2 diodes + Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5 + diff --git a/arch/cris/drivers/Makefile b/arch/cris/arch-v10/drivers/Makefile similarity index 60% rename from arch/cris/drivers/Makefile rename to arch/cris/arch-v10/drivers/Makefile index 50da6d18d52..7160cdd7bdd 100644 --- a/arch/cris/drivers/Makefile +++ b/arch/cris/arch-v10/drivers/Makefile @@ -4,13 +4,11 @@ obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o obj-$(CONFIG_ETRAX_SERIAL) += serial.o -obj-$(CONFIG_ETRAX_IDE) += ide.o obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o obj-$(CONFIG_ETRAX_I2C) += i2c.o obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o obj-$(CONFIG_ETRAX_GPIO) += gpio.o -obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o -obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_ETRAX_PARPORT) += parport.o obj-$(CONFIG_ETRAX_DS1302) += ds1302.o -obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave +obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o + + diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c new file mode 100644 index 00000000000..c6f90bdcf07 --- /dev/null +++ b/arch/cris/arch-v10/drivers/axisflashmap.c @@ -0,0 +1,541 @@ +/* + * Physical mapping layer for MTD using the Axis partitiontable format + * + * Copyright (c) 2001, 2002 Axis Communications AB + * + * This file is under the GPL. + * + * First partition is always sector 0 regardless of if we find a partitiontable + * or not. In the start of the next sector, there can be a partitiontable that + * tells us what other partitions to define. If there isn't, we use a default + * partition split defined below. + * + * $Log: axisflashmap.c,v $ + * Revision 1.6 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.5 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.4 2002/11/20 11:56:10 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.3 2002/11/13 14:54:13 starvik + * Copied from linux 2.4 + * + * Revision 1.28 2002/10/01 08:08:43 jonashg + * The first partition ends at the start of the partition table. + * + * Revision 1.27 2002/08/21 09:23:13 jonashg + * Speling. + * + * Revision 1.26 2002/08/21 08:35:20 jonashg + * Cosmetic change to printouts. + * + * Revision 1.25 2002/08/21 08:15:42 jonashg + * Made it compile even without CONFIG_MTD_CONCAT defined. + * + * Revision 1.24 2002/08/20 13:12:35 jonashg + * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat + * the results. + * * Removed compile time tests concerning how the mtdram driver has been + * configured. The user will know about the misconfiguration at runtime + * instead. (The old approach made it impossible to use mtdram for anything + * else than RAM boot). + * + * Revision 1.23 2002/05/13 12:12:28 johana + * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and + * be informative at runtime. + * + * Revision 1.22 2002/05/13 10:24:44 johana + * Added #if checks on MTDRAM CONFIG + * + * Revision 1.21 2002/05/06 16:05:20 johana + * Removed debug printout. + * + * Revision 1.20 2002/05/06 16:03:00 johana + * No more cramfs as root hack in generic code. + * It's handled by axisflashmap using mtdram. + * + * Revision 1.19 2002/03/15 17:10:28 bjornw + * Changed comment about cached access since we changed this before + * + * Revision 1.18 2002/03/05 17:06:15 jonashg + * Try amd_flash probe before cfi_probe since amd_flash driver can handle two + * (or more) flash chips of different model and the cfi driver cannot. + * + * Revision 1.17 2001/11/12 19:42:38 pkj + * Fixed compiler warnings. + * + * Revision 1.16 2001/11/08 11:18:58 jonashg + * Always read from uncached address to avoid problems with flushing + * cachelines after write and MTD-erase. No performance loss have been + * seen yet. + * + * Revision 1.15 2001/10/19 12:41:04 jonashg + * Name of probe has changed in MTD. + * + * Revision 1.14 2001/09/21 07:14:10 jonashg + * Made root filesystem (cramfs) use mtdblock driver when booting from flash. + * + * Revision 1.13 2001/08/15 13:57:35 jonashg + * Entire MTD updated to the linux 2.4.7 version. + * + * Revision 1.12 2001/06/11 09:50:30 jonashg + * Oops, 2MB is 0x200000 bytes. + * + * Revision 1.11 2001/06/08 11:39:44 jonashg + * Changed sizes and offsets in axis_default_partitions to use + * CONFIG_ETRAX_PTABLE_SECTOR. + * + * Revision 1.10 2001/05/29 09:42:03 jonashg + * Use macro for end marker length instead of sizeof. + * + * Revision 1.9 2001/05/29 08:52:52 jonashg + * Gave names to the magic fours (size of the ptable end marker). + * + * Revision 1.8 2001/05/28 15:36:20 jonashg + * * Removed old comment about ptable location in flash (it's a CONFIG_ option). + * * Variable ptable was initialized twice to the same value. + * + * Revision 1.7 2001/04/05 13:41:46 markusl + * Updated according to review remarks + * + * Revision 1.6 2001/03/07 09:21:21 bjornw + * No need to waste .data + * + * Revision 1.5 2001/03/06 16:27:01 jonashg + * Probe the entire flash area for flash devices. + * + * Revision 1.4 2001/02/23 12:47:15 bjornw + * Uncached flash in LOW_MAP moved from 0xe to 0x8 + * + * Revision 1.3 2001/02/16 12:11:45 jonashg + * MTD driver amd_flash is now included in MTD CVS repository. + * (It's now in drivers/mtd). + * + * Revision 1.2 2001/02/09 11:12:22 jonashg + * Support for AMD compatible non-CFI flash chips. + * Only tested with Toshiba TC58FVT160 so far. + * + * Revision 1.1 2001/01/12 17:01:18 bjornw + * * Added axisflashmap.c, a physical mapping for MTD that reads and understands + * Axis partition-table format. + * + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_CRIS_LOW_MAP +#define FLASH_UNCACHED_ADDR KSEG_8 +#define FLASH_CACHED_ADDR KSEG_5 +#else +#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_CACHED_ADDR KSEG_F +#endif + +/* From head.S */ +extern unsigned long romfs_start, romfs_length, romfs_in_flash; + +/* Map driver functions. */ + +static __u8 flash_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 flash_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 flash_read32(struct map_info *map, unsigned long ofs) +{ + return *(volatile unsigned int *)(map->map_priv_1 + ofs); +} + +static void flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void flash_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void flash_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +/* + * The map for chip select e0. + * + * We run into tricky coherence situations if we mix cached with uncached + * accesses to we only use the uncached version here. + * + * The size field is the total size where the flash chips may be mapped on the + * chip select. MTD probes should find all devices there and it does not matter + * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD + * probes will ignore them. + * + * The start address in map_priv_1 is in virtual memory so we cannot use + * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start + * address of cse0. + */ +static struct map_info map_cse0 = { + .name = "cse0", + .size = MEM_CSE0_SIZE, + .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, + .read8 = flash_read8, + .read16 = flash_read16, + .read32 = flash_read32, + .copy_from = flash_copy_from, + .write8 = flash_write8, + .write16 = flash_write16, + .write32 = flash_write32, + .map_priv_1 = FLASH_UNCACHED_ADDR +}; + +/* + * The map for chip select e1. + * + * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong + * address, but there isn't. + */ +static struct map_info map_cse1 = { + .name = "cse1", + .size = MEM_CSE1_SIZE, + .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, + .read8 = flash_read8, + .read16 = flash_read16, + .read32 = flash_read32, + .copy_from = flash_copy_from, + .write8 = flash_write8, + .write16 = flash_write16, + .write32 = flash_write32, + .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE +}; + +/* If no partition-table was found, we use this default-set. */ +#define MAX_PARTITIONS 7 +#define NUM_DEFAULT_PARTITIONS 3 + +/* + * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the + * size of one flash block and "filesystem"-partition needs 5 blocks to be able + * to use JFFS. + */ +static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { + { + .name = "boot firmware", + .size = CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0 + }, + { + .name = "kernel", + .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), + .offset = CONFIG_ETRAX_PTABLE_SECTOR + }, + { + .name = "filesystem", + .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) + } +}; + +/* Initialize the ones normally used. */ +static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { + { + .name = "part0", + .size = CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0 + }, + { + .name = "part1", + .size = 0, + .offset = 0 + }, + { + .name = "part2", + .size = 0, + .offset = 0 + }, + { + .name = "part3", + .size = 0, + .offset = 0 + }, + { + .name = "part4", + .size = 0, + .offset = 0 + }, + { + .name = "part5", + .size = 0, + .offset = 0 + }, + { + .name = "part6", + .size = 0, + .offset = 0 + }, +}; + +/* + * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash + * chips in that order (because the amd_flash-driver is faster). + */ +static struct mtd_info *probe_cs(struct map_info *map_cs) +{ + struct mtd_info *mtd_cs = NULL; + + printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", + map_cs->name, map_cs->size, map_cs->map_priv_1); + +#ifdef CONFIG_MTD_AMDSTD + mtd_cs = do_map_probe("amd_flash", map_cs); +#endif +#ifdef CONFIG_MTD_CFI + if (!mtd_cs) { + mtd_cs = do_map_probe("cfi_probe", map_cs); + } +#endif + + return mtd_cs; +} + +/* + * Probe each chip select individually for flash chips. If there are chips on + * both cse0 and cse1, the mtd_info structs will be concatenated to one struct + * so that MTD partitions can cross chip boundries. + * + * The only known restriction to how you can mount your chips is that each + * chip select must hold similar flash chips. But you need external hardware + * to do that anyway and you can put totally different chips on cse0 and cse1 + * so it isn't really much of a restriction. + */ +static struct mtd_info *flash_probe(void) +{ + struct mtd_info *mtd_cse0; + struct mtd_info *mtd_cse1; + struct mtd_info *mtd_cse; + + mtd_cse0 = probe_cs(&map_cse0); + mtd_cse1 = probe_cs(&map_cse1); + + if (!mtd_cse0 && !mtd_cse1) { + /* No chip found. */ + return NULL; + } + + if (mtd_cse0 && mtd_cse1) { +#ifdef CONFIG_MTD_CONCAT + struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; + + /* Since the concatenation layer adds a small overhead we + * could try to figure out if the chips in cse0 and cse1 are + * identical and reprobe the whole cse0+cse1 window. But since + * flash chips are slow, the overhead is relatively small. + * So we use the MTD concatenation layer instead of further + * complicating the probing procedure. + */ + mtd_cse = mtd_concat_create(mtds, + sizeof(mtds) / sizeof(mtds[0]), + "cse0+cse1"); +#else + printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " + "(mis)configuration!\n", map_cse0.name, map_cse1.name); + mtd_cse = NULL; +#endif + if (!mtd_cse) { + printk(KERN_ERR "%s and %s: Concatenation failed!\n", + map_cse0.name, map_cse1.name); + + /* The best we can do now is to only use what we found + * at cse0. + */ + mtd_cse = mtd_cse0; + map_destroy(mtd_cse1); + } + } else { + mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1; + } + + return mtd_cse; +} + +/* + * Probe the flash chip(s) and, if it succeeds, read the partition-table + * and register the partitions with MTD. + */ +static int __init init_axis_flash(void) +{ + struct mtd_info *mymtd; + int err = 0; + int pidx = 0; + struct partitiontable_head *ptable_head; + struct partitiontable_entry *ptable; + int use_default_ptable = 1; /* Until proven otherwise. */ + const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n"; + + if (!(mymtd = flash_probe())) { + /* There's no reason to use this module if no flash chip can + * be identified. Make sure that's understood. + */ + panic("axisflashmap found no flash chip!\n"); + } + + printk("%s: 0x%08x bytes of flash memory.\n", + mymtd->name, mymtd->size); + + mymtd->owner = THIS_MODULE; + + ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); + pidx++; /* First partition is always set to the default. */ + + if ((ptable_head->magic == PARTITION_TABLE_MAGIC) + && (ptable_head->size < + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + + PARTITIONTABLE_END_MARKER_SIZE)) + && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + + ptable_head->size - + PARTITIONTABLE_END_MARKER_SIZE) + == PARTITIONTABLE_END_MARKER)) { + /* Looks like a start, sane length and end of a + * partition table, lets check csum etc. + */ + int ptable_ok = 0; + struct partitiontable_entry *max_addr = + (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head) + + ptable_head->size); + unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; + unsigned char *p; + unsigned long csum = 0; + + ptable = (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head)); + + /* Lets be PARANOID, and check the checksum. */ + p = (unsigned char*) ptable; + + while (p <= (unsigned char*)max_addr) { + csum += *p++; + csum += *p++; + csum += *p++; + csum += *p++; + } + ptable_ok = (csum == ptable_head->checksum); + + /* Read the entries and use/show the info. */ + printk(" Found a%s partition table at 0x%p-0x%p.\n", + (ptable_ok ? " valid" : "n invalid"), ptable_head, + max_addr); + + /* We have found a working bootblock. Now read the + * partition table. Scan the table. It ends when + * there is 0xffffffff, that is, empty flash. + */ + while (ptable_ok + && ptable->offset != 0xffffffff + && ptable < max_addr + && pidx < MAX_PARTITIONS) { + + axis_partitions[pidx].offset = offset + ptable->offset; + axis_partitions[pidx].size = ptable->size; + + printk(pmsg, pidx, axis_partitions[pidx].offset, + axis_partitions[pidx].size); + pidx++; + ptable++; + } + use_default_ptable = !ptable_ok; + } + + if (romfs_in_flash) { + /* Add an overlapping device for the root partition (romfs). */ + + axis_partitions[pidx].name = "romfs"; + axis_partitions[pidx].size = romfs_length; + axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; + axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; + + printk(" Adding readonly flash partition for romfs image:\n"); + printk(pmsg, pidx, axis_partitions[pidx].offset, + axis_partitions[pidx].size); + pidx++; + } + + if (use_default_ptable) { + printk(" Using default partition table.\n"); + err = add_mtd_partitions(mymtd, axis_default_partitions, + NUM_DEFAULT_PARTITIONS); + } else { + err = add_mtd_partitions(mymtd, axis_partitions, pidx); + } + + if (err) { + panic("axisflashmap could not add MTD partitions!\n"); + } + + if (!romfs_in_flash) { + /* Create an RAM device for the root partition (romfs). */ + +#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) + /* No use trying to boot this kernel from RAM. Panic! */ + printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " + "device due to kernel (mis)configuration!\n"); + panic("This kernel cannot boot from RAM!\n"); +#else + struct mtd_info *mtd_ram; + + mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), + GFP_KERNEL); + if (!mtd_ram) { + panic("axisflashmap couldn't allocate memory for " + "mtd_info!\n"); + } + + printk(" Adding RAM partition for romfs image:\n"); + printk(pmsg, pidx, romfs_start, romfs_length); + + err = mtdram_init_device(mtd_ram, (void*)romfs_start, + romfs_length, "romfs"); + if (err) { + panic("axisflashmap could not initialize MTD RAM " + "device!\n"); + } +#endif + } + + return err; +} + +/* This adds the above to the kernels init-call chain. */ +module_init(init_axis_flash); diff --git a/arch/cris/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c similarity index 86% rename from arch/cris/drivers/ds1302.c rename to arch/cris/arch-v10/drivers/ds1302.c index 23814c3843d..17506213372 100644 --- a/arch/cris/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -7,8 +7,37 @@ *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status *! *! $Log: ds1302.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.9 2003/07/04 08:27:37 starvik +*! Merge of Linux 2.5.74 +*! +*! Revision 1.8 2003/04/09 05:20:47 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.6 2003/01/09 14:42:51 starvik +*! Merge of Linux 2.5.55 +*! +*! Revision 1.4 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.3 2002/11/20 11:56:10 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.2 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers +*! +*! Revision 1.15 2002/10/11 16:14:33 johana +*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the +*! trcklecharge register. +*! +*! Revision 1.14 2002/10/10 12:15:38 magnusmn +*! Added support for having the RST signal on bit g0 +*! +*! Revision 1.13 2002/05/29 15:16:08 johana +*! Removed unused variables. +*! +*! Revision 1.12 2002/04/10 15:35:25 johana +*! Moved probe function closer to init function and marked it __init. *! *! Revision 1.11 2001/06/14 12:35:52 jonashg *! The ATA hack is back. It is unfortunately the only way to set g27 to output. @@ -85,7 +114,7 @@ *! *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +*! $Id: ds1302.c,v 1.9 2003/07/04 08:27:37 starvik Exp $ *! *!***************************************************************************/ @@ -101,7 +130,7 @@ #include #include -#include +#include #include #include @@ -232,54 +261,6 @@ ds1302_wdisable(void) stop(); } -/* Probe for the chip by writing something to its RAM and try reading it back. */ - -#define MAGIC_PATTERN 0x42 - -static int -ds1302_probe(void) -{ - int retval, res; - - TK_RST_DIR(1); - TK_SCL_DIR(1); - TK_SDA_DIR(0); - - /* Try to talk to timekeeper. */ - - ds1302_wenable(); - start(); - out_byte(0xc0); /* write RAM byte 0 */ - out_byte(MAGIC_PATTERN); /* write something magic */ - start(); - out_byte(0xc1); /* read RAM byte 0 */ - - if((res = in_byte()) == MAGIC_PATTERN) { - char buf[100]; - stop(); - ds1302_wdisable(); - printk("%s: RTC found.\n", ds1302_name); - printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", - ds1302_name, - CONFIG_ETRAX_DS1302_SDABIT, - CONFIG_ETRAX_DS1302_SCLBIT, -#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT - "GENIO", -#else - "PB", -#endif - CONFIG_ETRAX_DS1302_RSTBIT); - get_rtc_status(buf); - printk(buf); - retval = 1; - } else { - stop(); - printk("%s: RTC not found.\n", ds1302_name); - retval = 0; - } - - return retval; -} /* Read a byte from the selected register in the DS1302. */ @@ -315,8 +296,8 @@ get_rtc_time(struct rtc_time *rtc_tm) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); @@ -325,7 +306,7 @@ get_rtc_time(struct rtc_time *rtc_tm) rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); - restore_flags(flags); + local_irq_restore(flags); BCD_TO_BIN(rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_min); @@ -371,7 +352,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; unsigned int yrs; if (!capable(CAP_SYS_TIME)) @@ -414,15 +394,15 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, BIN_TO_BCD(mon); BIN_TO_BCD(yrs); - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); CMOS_WRITE(hrs, RTC_HOURS); CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); - restore_flags(flags); + local_irq_restore(flags); /* Notice that at this point, the RTC is updated but * the kernel is still running with the old time. @@ -435,7 +415,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { int tcs_val; - unsigned char save_control, save_freq_select; if (!capable(CAP_SYS_TIME)) return -EPERM; @@ -484,6 +463,56 @@ static struct file_operations rtc_fops = { .ioctl = rtc_ioctl, }; +/* Probe for the chip by writing something to its RAM and try reading it back. */ + +#define MAGIC_PATTERN 0x42 + +static int __init +ds1302_probe(void) +{ + int retval, res; + + TK_RST_DIR(1); + TK_SCL_DIR(1); + TK_SDA_DIR(0); + + /* Try to talk to timekeeper. */ + + ds1302_wenable(); + start(); + out_byte(0xc0); /* write RAM byte 0 */ + out_byte(MAGIC_PATTERN); /* write something magic */ + start(); + out_byte(0xc1); /* read RAM byte 0 */ + + if((res = in_byte()) == MAGIC_PATTERN) { + char buf[100]; + stop(); + ds1302_wdisable(); + printk("%s: RTC found.\n", ds1302_name); + printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", + ds1302_name, + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + "GENIO", +#else + "PB", +#endif + CONFIG_ETRAX_DS1302_RSTBIT); + get_rtc_status(buf); + printk(buf); + retval = 1; + } else { + stop(); + printk("%s: RTC not found.\n", ds1302_name); + retval = 0; + } + + return retval; +} + + /* Just probe for the RTC and register the device to handle the ioctl needed. */ int __init @@ -491,27 +520,47 @@ ds1302_init(void) { if (!ds1302_probe()) { #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT +#if CONFIG_ETRAX_DS1302_RSTBIT == 27 /* * The only way to set g27 to output is to enable ATA. * * Make sure that R_GEN_CONFIG is setup correct. */ genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, ata)) - | + ~IO_MASK(R_GEN_CONFIG, ata)) | (IO_STATE(R_GEN_CONFIG, ata, select))); *R_GEN_CONFIG = genconfig_shadow; - if (!ds1302_probe()) +#elif CONFIG_ETRAX_DS1302_RSTBIT == 0 + + /* Set the direction of this bit to out. */ + genconfig_shadow = ((genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, g0dir)) | + (IO_STATE(R_GEN_CONFIG, g0dir, out))); + *R_GEN_CONFIG = genconfig_shadow; +#endif + if (!ds1302_probe()) return -1; #else return -1; #endif } + /* Initialise trickle charger */ + ds1302_writereg(RTC_TRICKLECHARGER, + RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); + return 0; +} + +static int __init ds1302_register(void) +{ + ds1302_init(); if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { printk(KERN_INFO "%s: unable to get major %d for rtc\n", ds1302_name, RTC_MAJOR_NR); return -1; } - return 0; + return 0; + } + +module_init(ds1302_register); diff --git a/arch/cris/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c similarity index 95% rename from arch/cris/drivers/eeprom.c rename to arch/cris/arch-v10/drivers/eeprom.c index ae3c3788672..67523549dd9 100644 --- a/arch/cris/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -20,8 +20,24 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.9 2003/07/04 08:27:37 starvik +*! Merge of Linux 2.5.74 +*! +*! Revision 1.8 2003/04/09 05:20:47 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.6 2003/02/10 07:19:28 starvik +*! Removed misplaced ; +*! +*! Revision 1.5 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.4 2002/11/20 11:56:10 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.3 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers *! *! Revision 1.8 2001/06/15 13:24:29 jonashg *! * Added verification of pointers from userspace in read and write. @@ -74,7 +90,7 @@ #include #include #include -#include +#include #include #include "i2c.h" @@ -425,9 +441,9 @@ int __init eeprom_init(void) static int eeprom_open(struct inode * inode, struct file * file) { - if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) + if(minor(inode->i_rdev) != EEPROM_MINOR_NR) return -ENXIO; - if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) + if(major(inode->i_rdev) != EEPROM_MAJOR_NR) return -ENXIO; if( eeprom.size > 0 ) @@ -449,39 +465,36 @@ static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) * orig 1: relative from current position * orig 2: position from last eeprom address */ - loff_t ret; - - lock_kernel(); + switch (orig) { case 0: - ret = file->f_pos = offset; + file->f_pos = offset; break; case 1: - ret = file->f_pos += offset; + file->f_pos += offset; break; case 2: - ret = file->f_pos = eeprom.size - offset; + file->f_pos = eeprom.size - offset; break; default: - ret = -EINVAL; + return -EINVAL; } /* truncate position */ if (file->f_pos < 0) { - file->f_pos = 0; - ret = -EOVERFLOW; + file->f_pos = 0; + return(-EOVERFLOW); } - + if (file->f_pos >= eeprom.size) { file->f_pos = eeprom.size - 1; - ret = -EOVERFLOW; + return(-EOVERFLOW); } - unlock_kernel(); - return ( ret ); + return ( file->f_pos ); } /* Reads data from eeprom. */ @@ -500,7 +513,7 @@ static int eeprom_read_buf(loff_t addr, char * buf, int count) static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) { - int i, read=0; + int read=0; unsigned long p = file->f_pos; unsigned char page; @@ -526,7 +539,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t if(!eeprom_address(p)) { printk(KERN_INFO "%s: Read failed to address the eeprom: " - "0x%08X (%i) page: %i\n", eeprom_name, p, p, page); + "0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page); i2c_stop(); /* don't forget to wake them up */ @@ -609,7 +622,7 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, if(!eeprom_address(p)) { printk(KERN_INFO "%s: Write failed to address the eeprom: " - "0x%08X (%i) \n", eeprom_name, p, p); + "0x%08X (%i) \n", eeprom_name, (int)p, (int)p); i2c_stop(); /* don't forget to wake them up */ @@ -747,7 +760,7 @@ static int eeprom_close(struct inode * inode, struct file * file) static int eeprom_address(unsigned long addr) { - int i, j; + int i; unsigned char page, offset; page = (unsigned char) (addr >> 8); diff --git a/arch/cris/drivers/ethernet.c b/arch/cris/arch-v10/drivers/ethernet.c similarity index 64% rename from arch/cris/drivers/ethernet.c rename to arch/cris/arch-v10/drivers/ethernet.c index 9b72037ea03..6b9b40634da 100644 --- a/arch/cris/drivers/ethernet.c +++ b/arch/cris/arch-v10/drivers/ethernet.c @@ -1,14 +1,109 @@ -/* $Id: ethernet.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $ +/* $Id: ethernet.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * - * Copyright (c) 1998-2001 Axis Communications AB. + * Copyright (c) 1998-2002 Axis Communications AB. * * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). + * Revision 1.17 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.16 2003/04/24 08:28:22 starvik + * New LED behaviour: LED off when no link + * + * Revision 1.15 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.13 2003/03/06 16:11:01 henriken + * Off by one error in group address register setting. + * + * Revision 1.12 2003/02/27 17:24:19 starvik + * Corrected Rev to Revision + * + * Revision 1.11 2003/01/24 09:53:21 starvik + * Oops. Initialize GA to 0, not to 1 + * + * Revision 1.10 2003/01/24 09:50:55 starvik + * Initialize GA_0 and GA_1 to 0 to avoid matching of unwanted packets + * + * Revision 1.9 2002/12/13 07:40:58 starvik + * Added basic ethtool interface + * Handled out of memory when allocating new buffers + * + * Revision 1.8 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.7 2002/11/26 09:41:42 starvik + * Added e100_set_config (standard interface to set media type) + * Added protection against preemptive scheduling + * Added standard MII ioctls + * + * Revision 1.6 2002/11/21 07:18:18 starvik + * Timers must be initialized in 2.5.48 + * + * Revision 1.5 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.4 2002/11/18 07:26:46 starvik + * Linux 2.5 port of latest Linux 2.4 ethernet driver + * + * Revision 1.33 2002/10/02 20:16:17 hp + * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation + * + * Revision 1.32 2002/09/16 06:05:58 starvik + * Align memory returned by dev_alloc_skb + * Moved handling of sent packets to interrupt to avoid reference counting problem + * + * Revision 1.31 2002/09/10 13:28:23 larsv + * Return -EINVAL for unknown ioctls to avoid confusing tools that tests + * for supported functionality by issuing special ioctls, i.e. wireless + * extensions. + * + * Revision 1.30 2002/05/07 18:50:08 johana + * Correct spelling in comments. + * + * Revision 1.29 2002/05/06 05:38:49 starvik + * Performance improvements: + * Large packets are not copied (breakpoint set to 256 bytes) + * The cache bug workaround is delayed until half of the receive list + * has been used + * Added transmit list + * Transmit interrupts are only enabled when transmit queue is full + * + * Revision 1.28.2.1 2002/04/30 08:15:51 starvik + * Performance improvements: + * Large packets are not copied (breakpoint set to 256 bytes) + * The cache bug workaround is delayed until half of the receive list + * has been used. + * Added transmit list + * Transmit interrupts are only enabled when transmit queue is full + * + * Revision 1.28 2002/04/22 11:47:21 johana + * Fix according to 2.4.19-pre7. time_after/time_before and + * missing end of comment. + * The patch has a typo for ethernet.c in e100_clear_network_leds(), + * that is fixed here. + * + * Revision 1.27 2002/04/12 11:55:11 bjornw + * Added TODO + * + * Revision 1.26 2002/03/15 17:11:02 bjornw + * Use prepare_rx_descriptor after the CPU has touched the receiving descs + * + * Revision 1.25 2002/03/08 13:07:53 bjornw + * Unnecessary spinlock removed + * + * Revision 1.24 2002/02/20 12:57:43 fredriks + * Replaced MIN() with min(). + * + * Revision 1.23 2002/02/20 10:58:14 fredriks + * Strip the Ethernet checksum (4 bytes) before forwarding a frame to upper layers. + * + * Revision 1.22 2002/01/30 07:48:22 matsfg + * Initiate R_NETWORK_TR_CTRL * * Revision 1.21 2001/11/23 11:54:49 starvik * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list @@ -112,22 +207,25 @@ #include #include +#include +#include #include #include #include +#include -#include /* DMA and register descriptions */ +#include /* DMA and register descriptions */ #include /* LED_* I/O functions */ #include #include #include #include #include +#include //#define ETHDEBUG #define D(x) - /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -154,6 +252,11 @@ struct net_local { spinlock_t lock; }; +typedef struct etrax_eth_descr +{ + etrax_dma_descr descr; + struct sk_buff* skb; +} etrax_eth_descr; /* Duplex settings */ enum duplex @@ -165,8 +268,6 @@ enum duplex /* Dma descriptors etc. */ -#define RX_BUF_SIZE 32768 - #define MAX_MEDIA_DATA_SIZE 1518 #define MIN_PACKET_LEN 46 @@ -207,29 +308,37 @@ enum duplex #define NO_NETWORK_ACTIVITY 0 #define NETWORK_ACTIVITY 1 -#define RX_DESC_BUF_SIZE 256 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ - RX_DESC_BUF_SIZE) +#define NBR_OF_RX_DESC 64 +#define NBR_OF_TX_DESC 256 + +/* Large packets are sent directly to upper layers while small packets are */ +/* copied (to reduce memory waste). The following constant decides the breakpoint */ +#define RX_COPYBREAK 256 + +/* Due to a chip bug we need to flush the cache when descriptors are returned */ +/* to the DMA. To decrease performance impact we return descriptors in chunks. */ +/* The following constant determines the number of descriptors to return. */ +#define RX_QUEUE_THRESHOLD NBR_OF_RX_DESC/2 #define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) /* Define some macros to access ETRAX 100 registers */ -#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_FIELD(##reg##, field, val) -#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_STATE(##reg##, field, val) +#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_FIELD_(reg##_, field##_, val) +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) -static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to +static etrax_eth_descr *myNextRxDesc; /* Points to the next descriptor to to be processed */ -static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ -static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ - -static unsigned char RxBuf[RX_BUF_SIZE]; +static etrax_eth_descr *myLastRxDesc; /* The last processed descriptor */ +static etrax_eth_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); -static etrax_dma_descr TxDesc __attribute__ ((aligned(4))); +static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32))); -static struct sk_buff *tx_skb; +static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */ +static etrax_eth_descr* myLastTxDesc; /* End of send queue */ +static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ +static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); static unsigned int network_rec_config_shadow = 0; @@ -238,27 +347,29 @@ static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0); static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0); static int current_speed; /* Speed read from transceiver */ static int current_speed_selection; /* Speed selected by user */ -static int led_next_time; +static unsigned long led_next_time; static int led_active; +static int rx_queue_len; /* Duplex */ -static struct timer_list duplex_timer; +static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0); static int full_duplex; static enum duplex current_duplex; /* Index to functions, as function prototypes. */ -static int etrax_ethernet_init(struct net_device *dev); +static int etrax_ethernet_init(void); static int e100_open(struct net_device *dev); static int e100_set_mac_address(struct net_device *dev, void *addr); static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void e100_rx(struct net_device *dev); static int e100_close(struct net_device *dev); static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr); +static int e100_set_config(struct net_device* dev, struct ifmap* map); static void e100_tx_timeout(struct net_device *dev); static struct net_device_stats *e100_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -273,6 +384,7 @@ static void e100_set_duplex(enum duplex); static void e100_negotiate(void); static unsigned short e100_get_mdio_reg(unsigned char reg_num); +static void e100_set_mdio_reg(unsigned char reg, unsigned short data); static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); static void e100_send_mdio_bit(unsigned char bit); static unsigned char e100_receive_mdio_bit(void); @@ -296,15 +408,14 @@ etrax_ethernet_init(void) { struct net_device *dev; int i, err; - int anOffset = 0; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ + dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ /* now setup our etrax specific stuff */ @@ -320,35 +431,55 @@ etrax_ethernet_init(void) dev->set_multicast_list = set_multicast_list; dev->set_mac_address = e100_set_mac_address; dev->do_ioctl = e100_ioctl; + dev->set_config = e100_set_config; dev->tx_timeout = e100_tx_timeout; /* Initialise the list of Etrax DMA-descriptors */ /* Initialise receive descriptors */ - for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].ctrl = 0; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - anOffset += RX_DESC_BUF_SIZE; + for (i = 0; i < NBR_OF_RX_DESC; i++) { + /* Allocate two extra cachelines to make sure that buffer used by DMA + * does not share cacheline with any other data (to avoid cache bug) + */ + RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); + RxDescList[i].descr.ctrl = 0; + RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; + RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].descr.buf = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data)); + RxDescList[i].descr.status = 0; + RxDescList[i].descr.hw_len = 0; + prepare_rx_descriptor(&RxDescList[i].descr); } - RxDescList[i].ctrl = d_eol; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; + RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl = d_eol; + RxDescList[NBR_OF_RX_DESC - 1].descr.next = virt_to_phys(&RxDescList[0]); + rx_queue_len = 0; + + /* Initialize transmit descriptors */ + for (i = 0; i < NBR_OF_TX_DESC; i++) { + TxDescList[i].descr.ctrl = 0; + TxDescList[i].descr.sw_len = 0; + TxDescList[i].descr.next = virt_to_phys(&TxDescList[i + 1].descr); + TxDescList[i].descr.buf = 0; + TxDescList[i].descr.status = 0; + TxDescList[i].descr.hw_len = 0; + TxDescList[i].skb = 0; + } + TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl = d_eol; + TxDescList[NBR_OF_TX_DESC - 1].descr.next = virt_to_phys(&TxDescList[0].descr); + /* Initialise initial pointers */ - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myFirstTxDesc = &TxDescList[0]; + myNextTxDesc = &TxDescList[0]; + myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1]; + /* Register device */ err = register_netdev(dev); if (err) { kfree(dev); @@ -375,6 +506,10 @@ etrax_ethernet_init(void) duplex_timer.function = e100_check_duplex; add_timer(&duplex_timer); + /* Initialize group address registers to make sure that no */ + /* unwanted addresses are matched */ + *R_NETWORK_GA_0 = 0x00000000; + *R_NETWORK_GA_1 = 0x00000000; return 0; } @@ -385,9 +520,12 @@ etrax_ethernet_init(void) static int e100_set_mac_address(struct net_device *dev, void *p) { + struct net_local *np = (struct net_local *)dev->priv; struct sockaddr *addr = p; int i; + spin_lock(&np->lock); /* preemption protection */ + /* remember it */ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -412,6 +550,8 @@ e100_set_mac_address(struct net_device *dev, void *p) printk("%02X\n", dev->dev_addr[i]); + spin_unlock(&np->lock); + return 0; } @@ -462,14 +602,14 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0, + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit0; } /* allocate the irq corresponding to the transmitting DMA */ - if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0, + if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit1; } @@ -481,19 +621,6 @@ e100_open(struct net_device *dev) goto grace_exit2; } - /* - * Always allocate the DMA channels after the IRQ, - * and clean up on failure. - */ - - if (request_dma(NETWORK_TX_DMA_NBR, cardname)) { - goto grace_exit3; - } - - if (request_dma(NETWORK_RX_DMA_NBR, cardname)) { - goto grace_exit4; - } - /* give the HW an idea of what MAC address we want */ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | @@ -518,22 +645,28 @@ e100_open(struct net_device *dev) IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); + *R_NETWORK_TR_CTRL = + IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | + IO_STATE(R_NETWORK_TR_CTRL, delay, none) | + IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | + IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | + IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | + IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | + IO_STATE(R_NETWORK_TR_CTRL, crc, enable); + save_flags(flags); cli(); /* enable the irq's for ethernet DMA */ *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); + IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, overrun, set) | IO_STATE(R_IRQ_MASK0_SET, underrun, set) | IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); - tx_skb = 0; - /* make sure the irqs are cleared */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); @@ -549,6 +682,11 @@ e100_open(struct net_device *dev) *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); + /* Set up transmit DMA channel so it can be restarted later */ + + *R_DMA_CH0_FIRST = 0; + *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); + restore_flags(flags); /* We are now ready to accept transmit requeusts from @@ -558,10 +696,6 @@ e100_open(struct net_device *dev) return 0; -grace_exit4: - free_dma(NETWORK_TX_DMA_NBR); -grace_exit3: - free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); grace_exit2: free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); grace_exit1: @@ -596,9 +730,7 @@ e100_check_speed(unsigned long dummy) static void e100_negotiate(void) { - unsigned short cmd; unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); - int bitCounter; /* Discard old speed and duplex settings */ data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | @@ -637,29 +769,13 @@ e100_negotiate(void) MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; } - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | - (MDIO_ADVERTISMENT_REG<< 2); - - e100_send_mdio_cmd(cmd, 1); - - /* Data... */ - for (bitCounter=15; bitCounter>=0 ; bitCounter--) { - e100_send_mdio_bit(GET_BIT(bitCounter, data)); - } + e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data); /* Renegotiate with link partner */ data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); data |= MDIO_BC_NEGOTIATE; - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | - (MDIO_BASE_CONTROL_REG<< 2); - - e100_send_mdio_cmd(cmd, 1); - - /* Data... */ - for (bitCounter=15; bitCounter>=0 ; bitCounter--) { - e100_send_mdio_bit(GET_BIT(bitCounter, data)); - } + e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data); } static void @@ -727,6 +843,24 @@ e100_get_mdio_reg(unsigned char reg_num) } static void +e100_set_mdio_reg(unsigned char reg, unsigned short data) +{ + int bitCounter; + unsigned short cmd; + + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | + (reg << 2); + + e100_send_mdio_cmd(cmd, 1); + + /* Data... */ + for (bitCounter=15; bitCounter>=0 ; bitCounter--) { + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + } + +} + +static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd) { int bitCounter; @@ -801,6 +935,9 @@ static void e100_tx_timeout(struct net_device *dev) { struct net_local *np = (struct net_local *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&np->lock, flags); printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ problem" : "network cable problem"); @@ -818,14 +955,22 @@ e100_tx_timeout(struct net_device *dev) e100_reset_transceiver(); - /* and get rid of the packet that never got an interrupt */ - - dev_kfree_skb(tx_skb); - tx_skb = 0; - + /* and get rid of the packets that never got an interrupt */ + while (myFirstTxDesc != myNextTxDesc) + { + dev_kfree_skb(myFirstTxDesc->skb); + myFirstTxDesc->skb = 0; + myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); + } + + /* Set up transmit DMA channel so it can be restarted later */ + *R_DMA_CH0_FIRST = 0; + *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); + /* tell the upper layers we're ok again */ netif_wake_queue(dev); + spin_unlock_irqrestore(&np->lock, flags); } @@ -841,25 +986,30 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) struct net_local *np = (struct net_local *)dev->priv; int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; + unsigned long flags; #ifdef ETHDEBUG printk("send packet len %d\n", length); #endif - spin_lock_irq(&np->lock); /* protect from tx_interrupt */ + spin_lock_irqsave(&np->lock, flags); /* protect from tx_interrupt and ourself */ + + myNextTxDesc->skb = skb; - tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ dev->trans_start = jiffies; e100_hardware_send_packet(buf, length); - /* this simple TX driver has only one send-descriptor so we're full - * directly. If this had a send-ring instead, we would only do this if - * the ring got full. - */ + myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); - netif_stop_queue(dev); + /* Stop queue if full */ + if (myNextTxDesc == myFirstTxDesc) { + /* Enable transmit interrupt to wake up queue */ + *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); + *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set); + netif_stop_queue(dev); + } - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); return 0; } @@ -869,12 +1019,14 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) * Handle the network interface interrupts. */ -static void -e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t +e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; + struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK2_RD; + /* Handle received packets */ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -899,51 +1051,31 @@ e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) so we have to loop back and check if so */ } } -} - -/* the transmit dma channel interrupt - * - * this is supposed to free the skbuff which was pending during transmission, - * and inform the kernel that we can send one more buffer - */ -static void -e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - struct net_local *np = (struct net_local *)dev->priv; - - /* check for a dma0_eop interrupt */ - if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { - /* This protects us from concurrent execution of - * our dev->hard_start_xmit function above. - */ - - spin_lock(&np->lock); - - /* acknowledge the eop interrupt */ + /* Report any packets that have been sent */ + while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) && + myFirstTxDesc != myNextTxDesc) + { + np->stats.tx_bytes += myFirstTxDesc->skb->len; + np->stats.tx_packets++; + + /* dma is ready with the transmission of the data in tx_skb, so now + we can release the skb memory */ + dev_kfree_skb_irq(myFirstTxDesc->skb); + myFirstTxDesc->skb = 0; + myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); + } + if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { + /* acknowledge the eop interrupt and wake up queue */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); - - if (*R_DMA_CH0_FIRST == 0 && tx_skb) { - np->stats.tx_bytes += tx_skb->len; - np->stats.tx_packets++; - /* dma is ready with the transmission of the data in tx_skb, so now - we can release the skb memory */ - dev_kfree_skb_irq(tx_skb); - tx_skb = 0; - netif_wake_queue(dev); - } else { - printk(KERN_WARNING "%s: tx weird interrupt\n", - cardname); - } - - spin_unlock(&np->lock); + *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr); + netif_wake_queue(dev); } + return IRQ_HANDLED; } -static void +static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; @@ -968,7 +1100,7 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); } - + return IRQ_HANDLED; } /* We have a good packet(s), get it/them out of the buffers. */ @@ -978,7 +1110,6 @@ e100_rx(struct net_device *dev) struct sk_buff *skb; int length = 0; struct net_local *np = (struct net_local *)dev->priv; - struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; #ifdef ETHDEBUG int i; @@ -994,24 +1125,13 @@ e100_rx(struct net_device *dev) mod_timer(&clear_led_timer, jiffies + HZ/10); } - /* If the packet is broken down in many small packages then merge - * count how much space we will need to alloc with skb_alloc() for - * it to fit. - */ - - while (!(myNextRxDesc->status & d_eop)) { - length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } - - length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ + length = myNextRxDesc->descr.hw_len - 4; ((struct net_local *)dev->priv)->stats.rx_bytes += length; #ifdef ETHDEBUG printk("Got a packet of length %d:\n", length); /* dump the first bytes in the packet */ - skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); + skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf); for (i = 0; i < 8; i++) { printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], @@ -1020,53 +1140,68 @@ e100_rx(struct net_device *dev) } #endif - skb = dev_alloc_skb(length - ETHER_HEAD_LEN); - if (!skb) { - np->stats.rx_errors++; - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - return; - } + if (length < RX_COPYBREAK) { + /* Small packet, copy data */ + skb = dev_alloc_skb(length - ETHER_HEAD_LEN); + if (!skb) { + np->stats.rx_errors++; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + return; + } - skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ - skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ + skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ + skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ #ifdef ETHDEBUG - printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", - skb->head, skb->data, skb->tail, skb->end); - printk("copying packet to 0x%x.\n", skb_data_ptr); + printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", + skb->head, skb->data, skb->tail, skb->end); + printk("copying packet to 0x%x.\n", skb_data_ptr); #endif - - /* this loop can be made using max two memcpy's if optimized */ - - while (mySaveRxDesc != myNextRxDesc) { - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->sw_len); - skb_data_ptr += mySaveRxDesc->sw_len; - mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); + + memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length); + } + else { + /* Large packet, send directly to upper layers and allocate new + * memory (aligned to cache line boundary to avoid bug). + * Before sending the skb to upper layers we must make sure that + * skb->data points to the aligned start of the packet. + */ + int align; + struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); + if (!new_skb) { + np->stats.rx_errors++; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + return; + } + skb = myNextRxDesc->skb; + align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data; + skb_put(skb, length + align); + skb_pull(skb, align); /* Remove alignment bytes */ + myNextRxDesc->skb = new_skb; + myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data)); } - - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->hw_len); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* Send the packet to the upper layers */ - netif_rx(skb); /* Prepare for next packet */ - - myNextRxDesc->status = 0; + myNextRxDesc->descr.status = 0; myPrevRxDesc = myNextRxDesc; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); + myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next); - myPrevRxDesc->ctrl |= d_eol; - myLastRxDesc->ctrl &= ~d_eol; - myLastRxDesc = myPrevRxDesc; + rx_queue_len++; - return; + /* Check if descriptors should be returned */ + if (rx_queue_len == RX_QUEUE_THRESHOLD) { + flush_etrax_cache(); + myPrevRxDesc->descr.ctrl |= d_eol; + myLastRxDesc->descr.ctrl &= ~d_eol; + myLastRxDesc = myPrevRxDesc; + rx_queue_len = 0; + } } /* The inverse routine to net_open(). */ @@ -1105,9 +1240,6 @@ e100_close(struct net_device *dev) free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); - free_dma(NETWORK_TX_DMA_NBR); - free_dma(NETWORK_RX_DMA_NBR); - /* Update the statistics here. */ update_rx_stats(&np->stats); @@ -1119,8 +1251,24 @@ e100_close(struct net_device *dev) static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - /* Maybe default should return -EINVAL instead? */ + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct net_local *np = (struct net_local *)dev->priv; + + spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { + case SIOCETHTOOL: + return e100_ethtool_ioctl(dev,ifr); + case SIOCGMIIPHY: /* Get PHY address */ + data->phy_id = MDIO_PHYS_ADDR; + break; + case SIOCGMIIREG: /* Read MII register */ + data->val_out = e100_get_mdio_reg(data->reg_num); + break; + case SIOCSMIIREG: /* Write MII register */ + e100_set_mdio_reg(data->reg_num, data->val_in); + break; + /* The ioctls below should be considered obsolete but are */ + /* still present for compatability with old scripts/apps */ case SET_ETH_SPEED_10: /* 10 Mbps */ e100_set_speed(10); break; @@ -1139,11 +1287,128 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ e100_set_duplex(autoneg); break; - default: /* Auto neg */ + default: + return -EINVAL; + } + spin_unlock(&np->lock); + return 0; +} + +static int +e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) +{ + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) + return -EFAULT; + + switch (ecmd.cmd) { + case ETHTOOL_GSET: + { + memset((void *) &ecmd, 0, sizeof (ecmd)); + ecmd.supported = + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_EXTERNAL; + ecmd.phy_address = MDIO_PHYS_ADDR; + ecmd.speed = current_speed; + ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + ecmd.advertising = ADVERTISED_TP; + if (current_duplex == autoneg && current_speed_selection == 0) + ecmd.advertising = ADVERTISED_Autoneg; + else { + ecmd.advertising |= + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + if (current_speed_selection == 10) + ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); + else if (current_speed_selection == 100) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); + if (current_duplex == half) + ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); + else if (current_duplex == full) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); + } + ecmd.autoneg = AUTONEG_ENABLE; + if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) + return -EFAULT; + } + break; + case ETHTOOL_SSET: + { + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + if (ecmd.autoneg == AUTONEG_ENABLE) { + e100_set_duplex(autoneg); + e100_set_speed(0); + } else { + e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full); + e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100); + } + } + break; + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info; + memset((void *) &info, 0, sizeof (info)); + strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1); + strncpy(info.version, "$Revision: 1.17 $", sizeof(info.version) - 1); + strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); + strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); + info.regdump_len = 0; + info.eedump_len = 0; + info.testinfo_len = 0; + if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) + return -EFAULT; + } + break; + case ETHTOOL_NWAY_RST: + if (current_duplex == autoneg && current_speed_selection == 0) + e100_negotiate(); + break; + default: + return -EOPNOTSUPP; + break; + } + return 0; +} + +static int +e100_set_config(struct net_device *dev, struct ifmap *map) +{ + struct net_local *np = (struct net_local *)dev->priv; + spin_lock(&np->lock); /* Preempt protection */ + + switch(map->port) { + case IF_PORT_UNKNOWN: + /* Use autoneg */ e100_set_speed(0); e100_set_duplex(autoneg); break; + case IF_PORT_10BASET: + e100_set_speed(10); + e100_set_duplex(autoneg); + break; + case IF_PORT_100BASET: + case IF_PORT_100BASETX: + e100_set_speed(100); + e100_set_duplex(autoneg); + break; + case IF_PORT_100BASEFX: + case IF_PORT_10BASE2: + case IF_PORT_AUI: + spin_unlock(&np->lock); + return -EOPNOTSUPP; + break; + default: + printk(KERN_ERR "%s: Invalid media selected", dev->name); + spin_unlock(&np->lock); + return -EINVAL; } + spin_unlock(&np->lock); return 0; } @@ -1177,10 +1442,13 @@ static struct net_device_stats * e100_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); update_rx_stats(&lp->stats); update_tx_stats(&lp->stats); - + + spin_unlock_irqrestore(&lp->lock, flags); return &lp->stats; } @@ -1194,9 +1462,11 @@ e100_get_stats(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; int num_addr = dev->mc_count; unsigned long int lo_bits; unsigned long int hi_bits; + spin_lock(&lp->lock); if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ @@ -1255,7 +1525,7 @@ set_multicast_list(struct net_device *dev) hash_ix &= 0x3f; - if (hash_ix > 32) { + if (hash_ix >= 32) { hi_bits |= (1 << (hash_ix-32)); } else { @@ -1269,6 +1539,7 @@ set_multicast_list(struct net_device *dev) } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits; + spin_unlock(&lp->lock); } void @@ -1287,15 +1558,16 @@ e100_hardware_send_packet(char *buf, int length) } /* configure the tx dma descriptor */ + myNextTxDesc->descr.sw_len = length; + myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait; + myNextTxDesc->descr.buf = virt_to_phys(buf); - TxDesc.sw_len = length; - TxDesc.ctrl = d_eop | d_eol | d_wait; - TxDesc.buf = virt_to_phys(buf); + /* Move end of list */ + myLastTxDesc->descr.ctrl &= ~d_eol; + myLastTxDesc = myNextTxDesc; - /* setup the dma channel and start it */ - - *R_DMA_CH0_FIRST = virt_to_phys(&TxDesc); - *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start); + /* Restart DMA channel */ + *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart); } static void @@ -1323,7 +1595,7 @@ e100_set_network_leds(int active) if (!current_speed) { /* Make LED red, link is down */ - LED_NETWORK_SET(LED_RED); + LED_NETWORK_SET(LED_OFF); } else if (light_leds) { if (current_speed == 10) { diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c new file mode 100644 index 00000000000..a105cadaeed --- /dev/null +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -0,0 +1,907 @@ +/* $Id: gpio.c,v 1.8 2003/07/04 08:27:37 starvik Exp $ + * + * Etrax general port I/O device + * + * Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Ola Knutsson (LED handling) + * Johan Adolfsson (read/set directions, write, port G) + * + * $Log: gpio.c,v $ + * Revision 1.8 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.7 2003/01/10 07:44:07 starvik + * init_ioremap is now called by kernel before drivers are initialized + * + * Revision 1.6 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.5 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.4 2002/11/18 10:10:05 starvik + * Linux 2.5 port of latest gpio.c from Linux 2.4 + * + * Revision 1.20 2002/10/16 21:16:24 johana + * Added support for PA high level interrupt. + * That gives 2ms response time with iodtest for high levels and 2-12 ms + * response time on low levels if the check is not made in + * process.c:cpu_idle() as well. + * + * Revision 1.19 2002/10/14 18:27:33 johana + * Implemented alarm handling so select() now works. + * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in + * cpu_idle(). + * Otherwise I get 15-18 ms (same as doing the poll in userspace - + * but less overhead). + * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it + * is in 2.4) as well? + * TODO? Perhaps call request_irq()/free_irq() only when needed? + * Increased version to 2.5 + * + * Revision 1.18 2002/10/11 15:02:00 johana + * Mask inverted 8 bit value in setget_input(). + * + * Revision 1.17 2002/06/17 15:53:01 johana + * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT + * that take a pointer as argument and thus can handle 32 bit ports (G) + * correctly. + * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT. + * (especially if Port G bit 31 is used) + * + * Revision 1.16 2002/06/17 09:59:51 johana + * Returning 32 bit values in the ioctl return value doesn't work if bit + * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF. + * A new set of ioctl's will be added. + * + * Revision 1.15 2002/05/06 13:19:13 johana + * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well. + * + * Revision 1.14 2002/04/12 12:01:53 johana + * Use global r_port_g_data_shadow. + * Moved gpio_init_port_g() closer to gpio_init() and marked it __init. + * + * Revision 1.13 2002/04/10 12:03:55 johana + * Added support for port G /dev/gpiog (minor 3). + * Changed indentation on switch cases. + * Fixed other spaces to tabs. + * + * Revision 1.12 2001/11/12 19:42:15 pkj + * * Corrected return values from gpio_leds_ioctl(). + * * Fixed compiler warnings. + * + * Revision 1.11 2001/10/30 14:39:12 johana + * Added D() around gpio_write printk. + * + * Revision 1.10 2001/10/25 10:24:42 johana + * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast + * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB + * from ~60 seconds to 4 seconds). + * Added save_flags/cli/restore_flags in ioctl. + * + * Revision 1.9 2001/05/04 14:16:07 matsfg + * Corrected spelling error + * + * Revision 1.8 2001/04/27 13:55:26 matsfg + * Moved initioremap. + * Turns off all LEDS on init. + * Added support for shutdown and powerbutton. + * + * Revision 1.7 2001/04/04 13:30:08 matsfg + * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping + * + * Revision 1.6 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.5 2001/03/26 14:22:03 bjornw + * Namechange of some config options + * + * Revision 1.4 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.3 2001/01/24 15:06:48 bjornw + * gpio_wq correct type + * + * Revision 1.2 2001/01/18 16:07:30 bjornw + * 2.4 port + * + * Revision 1.1 2001/01/18 15:55:16 bjornw + * Verbatim copy of etraxgpio.c from elinux 2.0 added + * + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define GPIO_MAJOR 120 /* experimental MAJOR number */ + +#define D(x) + +#if 0 +static int dp_cnt; +#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0) +#else +#define DP(x) +#endif + +static char gpio_name[] = "etrax gpio"; + +#if 0 +static wait_queue_head_t *gpio_wq; +#endif + +static int gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off); +static int gpio_open(struct inode *inode, struct file *filp); +static int gpio_release(struct inode *inode, struct file *filp); +static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); + +/* private data per open() of this driver */ + +struct gpio_private { + struct gpio_private *next; + /* These fields are for PA and PB only */ + volatile unsigned char *port, *shadow; + volatile unsigned char *dir, *dir_shadow; + unsigned char changeable_dir; + unsigned char changeable_bits; + unsigned char clk_mask; + unsigned char data_mask; + unsigned char write_msb; + unsigned char pad1, pad2, pad3; + /* These fields are generic */ + unsigned long highalarm, lowalarm; + wait_queue_head_t alarm_wq; + int minor; +}; + +/* linked list of alarms to check for */ + +static struct gpio_private *alarmlist = 0; + +static int gpio_some_alarms = 0; /* Set if someone uses alarm */ + +/* Port A and B use 8 bit access, but Port G is 32 bit */ +#define NUM_PORTS (GPIO_MINOR_B+1) + +static volatile unsigned char *ports[NUM_PORTS] = { + R_PORT_PA_DATA, + R_PORT_PB_DATA, +}; +static volatile unsigned char *shads[NUM_PORTS] = { + &port_pa_data_shadow, + &port_pb_data_shadow +}; + +/* What direction bits that are user changeable 1=changeable*/ +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR +#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR +#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 +#endif + +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS +#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS +#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF +#endif + + +static unsigned char changeable_dir[NUM_PORTS] = { + CONFIG_ETRAX_PA_CHANGEABLE_DIR, + CONFIG_ETRAX_PB_CHANGEABLE_DIR +}; +static unsigned char changeable_bits[NUM_PORTS] = { + CONFIG_ETRAX_PA_CHANGEABLE_BITS, + CONFIG_ETRAX_PB_CHANGEABLE_BITS +}; + +static volatile unsigned char *dir[NUM_PORTS] = { + R_PORT_PA_DIR, + R_PORT_PB_DIR +}; + +static volatile unsigned char *dir_shadow[NUM_PORTS] = { + &port_pa_dir_shadow, + &port_pb_dir_shadow +}; + +/* Port G is 32 bit, handle it special, some bits are both inputs + and outputs at the same time, only some of the bits can change direction + and some of them in groups of 8 bit. */ +static unsigned long changeable_dir_g; +static unsigned long dir_g_in_bits; +static unsigned long dir_g_out_bits; +static unsigned long dir_g_shadow; /* 1=output */ + +#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B) + + + +static unsigned int +gpio_poll(struct file *file, + poll_table *wait) +{ + unsigned int mask = 0; + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned long data; + poll_wait(file, &priv->alarm_wq, wait); + if (priv->minor == GPIO_MINOR_A) { + unsigned long tmp; + data = *R_PORT_PA_DATA; + /* PA has support for high level interrupt - + * lets activate for those low and with highalarm set + */ + tmp = ~data & priv->highalarm & 0xFF; + *R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); + } else if (priv->minor == GPIO_MINOR_B) + data = *R_PORT_PB_DATA; + else if (priv->minor == GPIO_MINOR_G) + data = *R_PORT_G_DATA; + else + return 0; + + if ((data & priv->highalarm) || + (~data & priv->lowalarm)) { + mask = POLLIN|POLLRDNORM; + } + + DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); + return mask; +} + +int etrax_gpio_wake_up_check(void) +{ + struct gpio_private *priv = alarmlist; + unsigned long data = 0; + int ret = 0; + while (priv) { + if (USE_PORTS(priv)) { + data = *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + data = *R_PORT_G_DATA; + } + if ((data & priv->highalarm) || + (~data & priv->lowalarm)) { + DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor)); + wake_up_interruptible(&priv->alarm_wq); + ret = 1; + } + priv = priv->next; + } + return ret; +} + +static irqreturn_t +gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (gpio_some_alarms) { + etrax_gpio_wake_up_check(); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static irqreturn_t +gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long tmp; + /* Find what PA interrupts are active */ + tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF; + /* Clear them.. */ + /* NOTE: Maybe we need to be more careful here if some other + * driver uses PA interrupt as well? + */ + *R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR); + if (gpio_some_alarms) { + return IRQ_RETVAL(etrax_gpio_wake_up_check()); + } + return IRQ_NONE; +} + + +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned char data, clk_mask, data_mask, write_msb; + unsigned long flags; + ssize_t retval = count; + if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { + return -EFAULT; + } + + if (verify_area(VERIFY_READ, buf, count)) { + return -EFAULT; + } + clk_mask = priv->clk_mask; + data_mask = priv->data_mask; + /* It must have been configured using the IO_CFG_WRITE_MODE */ + /* Perhaps a better error code? */ + if (clk_mask == 0 || data_mask == 0) { + return -EPERM; + } + write_msb = priv->write_msb; + D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); + while (count--) { + int i; + data = *buf++; + if (priv->write_msb) { + for (i = 7; i >= 0;i--) { + local_irq_save(flags); local_irq_disable(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + local_irq_restore(flags); + } + } else { + for (i = 0; i <= 7;i++) { + local_irq_save(flags); local_irq_disable(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + local_irq_restore(flags); + } + } + } + return retval; +} + + + +static int +gpio_open(struct inode *inode, struct file *filp) +{ + struct gpio_private *priv; + int p = minor(inode->i_rdev); + + if (p > GPIO_MINOR_LAST) + return -EINVAL; + + priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), + GFP_KERNEL); + + if (!priv) + return -ENOMEM; + + priv->minor = p; + + /* initialize the io/alarm struct and link it into our alarmlist */ + + priv->next = alarmlist; + alarmlist = priv; + if (USE_PORTS(priv)) { /* A and B */ + priv->port = ports[p]; + priv->shadow = shads[p]; + priv->dir = dir[p]; + priv->dir_shadow = dir_shadow[p]; + priv->changeable_dir = changeable_dir[p]; + priv->changeable_bits = changeable_bits[p]; + } else { + priv->port = NULL; + priv->shadow = NULL; + priv->dir = NULL; + priv->dir_shadow = NULL; + priv->changeable_dir = 0; + priv->changeable_bits = 0; + } + + priv->highalarm = 0; + priv->lowalarm = 0; + priv->clk_mask = 0; + priv->data_mask = 0; + init_waitqueue_head(&priv->alarm_wq); + + filp->private_data = (void *)priv; + + return 0; +} + +static int +gpio_release(struct inode *inode, struct file *filp) +{ + struct gpio_private *p = alarmlist; + struct gpio_private *todel = (struct gpio_private *)filp->private_data; + + /* unlink from alarmlist and free the private structure */ + + if (p == todel) { + alarmlist = todel->next; + } else { + while (p->next != todel) + p = p->next; + p->next = todel->next; + } + + kfree(todel); + /* Check if there are still any alarms set */ + p = alarmlist; + while (p) { + if (p->highalarm | p->lowalarm) { + gpio_some_alarms = 1; + return 0; + } + p = p->next; + } + gpio_some_alarms = 0; + + return 0; +} + +/* Main device API. ioctl's to read/set/clear bits, as well as to + * set alarms to wait for using a subsequent select(). + */ + +unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) +{ + /* Set direction 0=unchanged 1=input, + * return mask with 1=input + */ + unsigned long flags; + if (USE_PORTS(priv)) { + local_irq_save(flags); local_irq_disable(); + *priv->dir = *priv->dir_shadow &= + ~((unsigned char)arg & priv->changeable_dir); + local_irq_restore(flags); + return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ + } else if (priv->minor == GPIO_MINOR_G) { + /* We must fiddle with R_GEN_CONFIG to change dir */ + if (((arg & dir_g_in_bits) != arg) && + (arg & changeable_dir_g)) { + arg &= changeable_dir_g; + /* Clear bits in genconfig to set to input */ + if (arg & (1<<0)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir); + dir_g_in_bits |= (1<<0); + dir_g_out_bits &= ~(1<<0); + } + if ((arg & 0x0000FF00) == 0x0000FF00) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir); + dir_g_in_bits |= 0x0000FF00; + dir_g_out_bits &= ~0x0000FF00; + } + if ((arg & 0x00FF0000) == 0x00FF0000) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir); + dir_g_in_bits |= 0x00FF0000; + dir_g_out_bits &= ~0x00FF0000; + } + if (arg & (1<<24)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir); + dir_g_in_bits |= (1<<24); + dir_g_out_bits &= ~(1<<24); + } + printk("gpio: SETINPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits); + *R_GEN_CONFIG = genconfig_shadow; + /* Must be a >120 ns delay before writing this again */ + + } + return dir_g_in_bits; + } + return 0; +} /* setget_input */ + +unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) +{ + unsigned long flags; + if (USE_PORTS(priv)) { + local_irq_save(flags); local_irq_disable(); + *priv->dir = *priv->dir_shadow |= + ((unsigned char)arg & priv->changeable_dir); + local_irq_restore(flags); + return *priv->dir_shadow; + } else if (priv->minor == GPIO_MINOR_G) { + /* We must fiddle with R_GEN_CONFIG to change dir */ + if (((arg & dir_g_out_bits) != arg) && + (arg & changeable_dir_g)) { + /* Set bits in genconfig to set to output */ + if (arg & (1<<0)) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir); + dir_g_out_bits |= (1<<0); + dir_g_in_bits &= ~(1<<0); + } + if ((arg & 0x0000FF00) == 0x0000FF00) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir); + dir_g_out_bits |= 0x0000FF00; + dir_g_in_bits &= ~0x0000FF00; + } + if ((arg & 0x00FF0000) == 0x00FF0000) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir); + dir_g_out_bits |= 0x00FF0000; + dir_g_in_bits &= ~0x00FF0000; + } + if (arg & (1<<24)) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir); + dir_g_out_bits |= (1<<24); + dir_g_in_bits &= ~(1<<24); + } + printk("gpio: SETOUTPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits); + *R_GEN_CONFIG = genconfig_shadow; + /* Must be a >120 ns delay before writing this again */ + } + return dir_g_out_bits & 0x7FFFFFFF; + } + return 0; +} /* setget_output */ + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg); + +static int +gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + unsigned long val; + struct gpio_private *priv = (struct gpio_private *)file->private_data; + if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ + // read the port + if (USE_PORTS(priv)) { + return *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + return (*R_PORT_G_DATA) & 0x7FFFFFFF; + } + break; + case IO_SETBITS: + local_irq_save(flags); local_irq_disable(); + // set changeable bits with a 1 in arg + if (USE_PORTS(priv)) { + *priv->port = *priv->shadow |= + ((unsigned char)arg & priv->changeable_bits); + } else if (priv->minor == GPIO_MINOR_G) { + *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); + } + local_irq_restore(flags); + break; + case IO_CLRBITS: + local_irq_save(flags); local_irq_disable(); + // clear changeable bits with a 1 in arg + if (USE_PORTS(priv)) { + *priv->port = *priv->shadow &= + ~((unsigned char)arg & priv->changeable_bits); + } else if (priv->minor == GPIO_MINOR_G) { + *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); + } + local_irq_restore(flags); + break; + case IO_HIGHALARM: + // set alarm when bits with 1 in arg go high + priv->highalarm |= arg; + gpio_some_alarms = 1; + break; + case IO_LOWALARM: + // set alarm when bits with 1 in arg go low + priv->lowalarm |= arg; + gpio_some_alarms = 1; + break; + case IO_CLRALARM: + // clear alarm for bits with 1 in arg + priv->highalarm &= ~arg; + priv->lowalarm &= ~arg; + break; + case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ + /* Read direction 0=input 1=output */ + if (USE_PORTS(priv)) { + return *priv->dir_shadow; + } else if (priv->minor == GPIO_MINOR_G) { + /* Note: Some bits are both in and out, + * Those that are dual is set here as well. + */ + return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; + } + case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ + /* Set direction 0=unchanged 1=input, + * return mask with 1=input + */ + return setget_input(priv, arg) & 0x7FFFFFFF; + break; + case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ + /* Set direction 0=unchanged 1=output, + * return mask with 1=output + */ + return setget_output(priv, arg) & 0x7FFFFFFF; + + case IO_SHUTDOWN: + SOFT_SHUTDOWN(); + break; + case IO_GET_PWR_BT: +#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) + return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); +#else + return 0; +#endif + break; + case IO_CFG_WRITE_MODE: + priv->clk_mask = arg & 0xFF; + priv->data_mask = (arg >> 8) & 0xFF; + priv->write_msb = (arg >> 16) & 0x01; + /* Check if we're allowed to change the bits and + * the direction is correct + */ + if (!((priv->clk_mask & priv->changeable_bits) && + (priv->data_mask & priv->changeable_bits) && + (priv->clk_mask & *priv->dir_shadow) && + (priv->data_mask & *priv->dir_shadow))) + { + priv->clk_mask = 0; + priv->data_mask = 0; + return -EPERM; + } + break; + case IO_READ_INBITS: + /* *arg is result of reading the input pins */ + if (USE_PORTS(priv)) { + val = *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + val = *R_PORT_G_DATA; + } + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + return 0; + break; + case IO_READ_OUTBITS: + /* *arg is result of reading the output shadow */ + if (USE_PORTS(priv)) { + val = *priv->shadow; + } else if (priv->minor == GPIO_MINOR_G) { + val = port_g_data_shadow; + } + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + case IO_SETGET_INPUT: + /* bits set in *arg is set to input, + * *arg updated with current input pins. + */ + if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) + return -EFAULT; + val = setget_input(priv, val); + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + case IO_SETGET_OUTPUT: + /* bits set in *arg is set to output, + * *arg updated with current output pins. + */ + if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) + return -EFAULT; + val = setget_output(priv, val); + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + default: + if (priv->minor == GPIO_MINOR_LEDS) + return gpio_leds_ioctl(cmd, arg); + else + return -EINVAL; + } /* switch */ + + return 0; +} + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg) +{ + unsigned char green; + unsigned char red; + + switch (_IOC_NR(cmd)) { + case IO_LEDACTIVE_SET: + green = ((unsigned char) arg) & 1; + red = (((unsigned char) arg) >> 1) & 1; + LED_ACTIVE_SET_G(green); + LED_ACTIVE_SET_R(red); + break; + + case IO_LED_SETBIT: + LED_BIT_SET(arg); + break; + + case IO_LED_CLRBIT: + LED_BIT_CLR(arg); + break; + + default: + return -EINVAL; + } /* switch */ + + return 0; +} + +struct file_operations gpio_fops = { + .owner = THIS_MODULE, + .poll = gpio_poll, + .ioctl = gpio_ioctl, + .write = gpio_write, + .open = gpio_open, + .release = gpio_release, +}; + + +static void __init gpio_init_port_g(void) +{ +#define GROUPA (0x0000FF3F) +#define GROUPB (1<<6 | 1<<7) +#define GROUPC (1<<30 | 1<<31) +#define GROUPD (0x3FFF0000) +#define GROUPD_LOW (0x00FF0000) + unsigned long used_in_bits = 0; + unsigned long used_out_bits = 0; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){ + used_in_bits |= GROUPA | GROUPB | 0 | 0; + used_out_bits |= GROUPA | GROUPB | 0 | 0; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) { + used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26)); + used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD; + } + + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; + used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) { + used_in_bits |= 0 | GROUPB | 0 | 0; + used_out_bits |= 0 | GROUPB | 0 | 0; + } + /* mio same as shared RAM ? */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW; + used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) { + used_in_bits |= 0 | 0 | GROUPC | GROUPD; + used_out_bits |= 0 | 0 | GROUPC | GROUPD; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) { + used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24); + used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26); + } + + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { + used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); + used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) { + used_in_bits |= 0 | 0 | GROUPC | 0; + used_out_bits |= 0 | 0 | GROUPC | 0; + } + /* mio same as shared RAM-W? */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW; + used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW; + } + /* TODO: USB p2, parw, sync ser3? */ + + /* Initialise the dir_g_shadow etc. depending on genconfig */ + /* 0=input 1=output */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) + dir_g_shadow |= (1 << 0); + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out)) + dir_g_shadow |= 0x0000FF00; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out)) + dir_g_shadow |= 0x00FF0000; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) + dir_g_shadow |= (1 << 24); + + dir_g_in_bits = ~used_in_bits; + dir_g_out_bits = ~used_out_bits; + + changeable_dir_g = 0x01FFFF01; /* all that can change dir */ + changeable_dir_g &= dir_g_out_bits; + changeable_dir_g &= dir_g_in_bits; + /* Correct the bits that can change direction */ + dir_g_out_bits &= ~changeable_dir_g; + dir_g_out_bits |= dir_g_shadow; + dir_g_in_bits &= ~changeable_dir_g; + dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); + + + printk("GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", + dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); + printk("GPIO port G: dir: %08lX changeable: %08lX\n", + dir_g_shadow, changeable_dir_g); +} + +/* main driver initialization routine, called from mem.c */ + +static __init int +gpio_init(void) +{ + int res; +#if defined (CONFIG_ETRAX_CSP0_LEDS) + int i; +#endif + + /* do the formalities */ + + res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); + if (res < 0) { + printk(KERN_ERR "gpio: couldn't get a major number.\n"); + return res; + } + + /* Clear all leds */ +#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) + LED_NETWORK_SET(0); + LED_ACTIVE_SET(0); + LED_DISK_READ(0); + LED_DISK_WRITE(0); + +#if defined (CONFIG_ETRAX_CSP0_LEDS) + for (i = 0; i < 32; i++) { + LED_BIT_SET(i); + } +#endif + +#endif + gpio_init_port_g(); + printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); + /* We call etrax_gpio_wake_up_check() from timer interrupt and + * from cpu_idle() in kernel/process.c + * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms + * in some tests. + */ + if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, + SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) { + printk("err: timer0 irq for gpio\n"); + } + if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt, + SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) { + printk("err: PA irq for gpio\n"); + } + + + return res; +} + +/* this makes sure that gpio_init is called during kernel boot */ + +module_init(gpio_init); diff --git a/arch/cris/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c similarity index 82% rename from arch/cris/drivers/i2c.c rename to arch/cris/arch-v10/drivers/i2c.c index 093c5d5dac1..7731f7d22f9 100644 --- a/arch/cris/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -12,8 +12,25 @@ *! don't use PB_I2C if DS1302 uses same bits, *! use PB. *! $Log: i2c.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.4 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.3 2002/11/20 11:56:11 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.2 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers +*! +*! Revision 1.9 2002/10/31 15:32:26 starvik +*! Update Port B register and shadow even when running with hardware support +*! to avoid glitches when reading bits +*! Never set direction to out in i2c_inbyte +*! Removed incorrect clock togling at end of i2c_inbyte +*! +*! Revision 1.8 2002/08/13 06:31:53 starvik +*! Made SDA and SCL line configurable +*! Modified i2c_inbyte to work with PCF8563 *! *! Revision 1.7 2001/04/04 13:11:36 markusl *! Updated according to review remarks @@ -43,10 +60,11 @@ *! *! --------------------------------------------------------------------------- *! -*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ -/* $Id: i2c.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */ +/* $Id: i2c.c,v 1.4 2002/12/11 13:13:57 starvik Exp $ */ + /****************** INCLUDE FILES SECTION ***********************************/ #include @@ -62,7 +80,7 @@ #include #include -#include +#include #include #include @@ -96,8 +114,15 @@ static const char i2c_name[] = "i2c"; #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C /* Use PB and not PB_I2C */ -#define SDABIT 0 -#define SCLBIT 1 +#ifndef CONFIG_ETRAX_I2C_DATA_PORT +#define CONFIG_ETRAX_I2C_DATA_PORT 0 +#endif +#ifndef CONFIG_ETRAX_I2C_CLK_PORT +#define CONFIG_ETRAX_I2C_CLK_PORT 1 +#endif + +#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT +#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT #define i2c_enable() #define i2c_disable() @@ -117,7 +142,7 @@ static const char i2c_name[] = "i2c"; /* read a bit from the i2c interface */ -#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT)) +#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT) #else /* enable or disable the i2c interface */ @@ -127,16 +152,24 @@ static const char i2c_name[] = "i2c"; /* enable or disable output-enable, to select output or input on the i2c bus */ -#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)) -#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)) +#define i2c_dir_out() \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); +#define i2c_dir_in() \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0); /* control the i2c clock and data signals */ -#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ - ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))) +#define i2c_clk(x) \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x); -#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ - ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))) +#define i2c_data(x) \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x); /* read a bit from the i2c interface */ @@ -209,14 +242,15 @@ void i2c_outbyte(unsigned char x) { int i; - + i2c_dir_out(); for (i = 0; i < 8; i++) { - if (x & 0x80) + if (x & 0x80) { i2c_data(I2C_DATA_HIGH); - else + } else { i2c_data(I2C_DATA_LOW); + } i2c_delay(CLOCK_LOW_TIME/2); i2c_clk(I2C_CLOCK_HIGH); @@ -241,65 +275,41 @@ i2c_inbyte(void) { unsigned char aBitByte = 0; int i; - int iaa; - /* - * enable output - */ - i2c_dir_out(); - /* - * Release data bus by setting - * data high - */ - i2c_data(I2C_DATA_HIGH); - /* - * enable input - */ + /* Switch off I2C to get bit */ + i2c_disable(); i2c_dir_in(); - /* - * Use PORT PB instead of I2C - * for input. (I2C not working) - */ - i2c_clk(1); - i2c_data(1); - /* - * get bits - */ - for (i = 0; i < 8; i++) { - i2c_delay(CLOCK_LOW_TIME/2); - /* - * low clock period - */ + i2c_delay(CLOCK_HIGH_TIME/2); + + /* Get bit */ + aBitByte |= i2c_getbit(); + + /* Enable I2C */ + i2c_enable(); + i2c_delay(CLOCK_LOW_TIME/2); + + for (i = 1; i < 8; i++) { + aBitByte <<= 1; + /* Clock pulse */ i2c_clk(I2C_CLOCK_HIGH); - /* - * switch off I2C - */ - i2c_data(1); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + /* Switch off I2C to get bit */ i2c_disable(); i2c_dir_in(); - /* - * wait before getting bit - */ - i2c_delay(CLOCK_HIGH_TIME/2); - aBitByte = (aBitByte << 1); - iaa = i2c_getbit(); - aBitByte = aBitByte | iaa ; - /* - * wait - */ i2c_delay(CLOCK_HIGH_TIME/2); - /* - * end clock puls - */ + + /* Get bit */ + aBitByte |= i2c_getbit(); + + /* Enable I2C */ i2c_enable(); - i2c_dir_out(); - i2c_clk(I2C_CLOCK_LOW); - /* - * low clock period - */ i2c_delay(CLOCK_LOW_TIME/2); } - i2c_dir_out(); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); return aBitByte; } @@ -424,44 +434,25 @@ i2c_sendack(void) *# *#--------------------------------------------------------------------------*/ int -i2c_writereg(unsigned char theSlave, unsigned char theReg, +i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue) { int error, cntr = 3; unsigned long flags; - + do { error = 0; /* * we don't like to be interrupted */ - save_flags(flags); - cli(); - /* - * generate start condition - */ - i2c_start(); - /* - * dummy preamble - */ - i2c_outbyte(0x01); - i2c_data(I2C_DATA_HIGH); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); + local_irq_save(flags); + local_irq_disable(); i2c_start(); /* * send slave address */ - i2c_outbyte(theSlave); + i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ @@ -493,10 +484,10 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, /* * enable interrupt again */ - restore_flags(flags); + local_irq_restore(flags); } while(error && cntr--); - + i2c_delay(CLOCK_LOW_TIME); return -error; @@ -515,40 +506,23 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) unsigned char b = 0; int error, cntr = 3; unsigned long flags; - + do { error = 0; /* * we don't like to be interrupted */ - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); /* * generate start condition */ i2c_start(); - /* - * dummy preamble - */ - i2c_outbyte(0x01); - i2c_data(I2C_DATA_HIGH); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - - i2c_start(); /* * send slave address */ - i2c_outbyte(theSlave); + i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ @@ -593,7 +567,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) /* * enable interrupt again */ - restore_flags(flags); + local_irq_restore(flags); } while(error && cntr--); diff --git a/arch/cris/drivers/i2c.h b/arch/cris/arch-v10/drivers/i2c.h similarity index 86% rename from arch/cris/drivers/i2c.h rename to arch/cris/arch-v10/drivers/i2c.h index d789274adc7..d0caa9ff883 100644 --- a/arch/cris/drivers/i2c.h +++ b/arch/cris/arch-v10/drivers/i2c.h @@ -1,4 +1,4 @@ -/* $Id: i2c.h,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */ +/* $Id: i2c.h,v 1.2 2002/11/18 13:16:06 starvik Exp $ */ /* High level I2C actions */ int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c new file mode 100644 index 00000000000..6a677bce6f1 --- /dev/null +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -0,0 +1,287 @@ +/* + * PCF8563 RTC + * + * From Phillips' datasheet: + * + * The PCF8563 is a CMOS real-time clock/calendar optimized for low power + * consumption. A programmable clock output, interupt output and voltage + * low detector are also provided. All address and data are transferred + * serially via two-line bidirectional I2C-bus. Maximum bus speed is + * 400 kbits/s. The built-in word address register is incremented + * automatically after each written or read bute. + * + * Copyright (c) 2002, Axis Communications AB + * All rights reserved. + * + * Author: Tobias Anderberg . + * + * $Id: pcf8563.c,v 1.1 2002/12/12 08:27:26 starvik Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "i2c.h" + +#define PCF8563_MAJOR 121 /* Local major number. */ +#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ +#define PCF8563_NAME "PCF8563" +#define DRIVER_VERSION "$Revision: 1.1 $" + +/* I2C bus slave registers. */ +#define RTC_I2C_READ 0xa3 +#define RTC_I2C_WRITE 0xa2 + +/* Two simple wrapper macros, saves a few keystrokes. */ +#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) +#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) + +static const unsigned char days_in_month[] = + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int pcf8563_open(struct inode *, struct file *); +int pcf8563_release(struct inode *, struct file *); + +static struct file_operations pcf8563_fops = { + owner: THIS_MODULE, + ioctl: pcf8563_ioctl, + open: pcf8563_open, + release: pcf8563_release, +}; + +unsigned char +pcf8563_readreg(int reg) +{ + unsigned char res = i2c_readreg(RTC_I2C_READ, reg); + + /* The PCF8563 does not return 0 for unimplemented bits */ + switch(reg) + { + case RTC_SECONDS: + case RTC_MINUTES: + res &= 0x7f; + break; + case RTC_HOURS: + case RTC_DAY_OF_MONTH: + res &= 0x3f; + break; + case RTC_MONTH: + res = (res & 0x1f) - 1; /* PCF8563 returns month in range 1-12 */ + break; + } + return res; +} + +void +pcf8563_writereg(int reg, unsigned char val) +{ + i2c_writereg(RTC_I2C_WRITE,reg,val); +} + +void +get_rtc_time(struct rtc_time *tm) +{ + tm->tm_sec = rtc_read(RTC_SECONDS); + tm->tm_min = rtc_read(RTC_MINUTES); + tm->tm_hour = rtc_read(RTC_HOURS); + tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); + tm->tm_mon = rtc_read(RTC_MONTH); + tm->tm_year = rtc_read(RTC_YEAR); + + if (tm->tm_sec & 0x80) + printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); + + tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0); + tm->tm_sec &= 0x7f; + tm->tm_min &= 0x7f; + tm->tm_hour &= 0x3f; + tm->tm_mday &= 0x3f; + tm->tm_mon &= 0x1f; + + BCD_TO_BIN(tm->tm_sec); + BCD_TO_BIN(tm->tm_min); + BCD_TO_BIN(tm->tm_hour); + BCD_TO_BIN(tm->tm_mday); + BCD_TO_BIN(tm->tm_mon); + tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */ +} + +int __init +pcf8563_init(void) +{ + unsigned char ret; + /* + * First of all we need to reset the chip. This is done by + * clearing control1, control2 and clk freq, clear the + * Voltage Low bit, and resetting all alarms. + */ + if (rtc_write(RTC_CONTROL1, 0x00) < 0) + goto err; + + if (rtc_write(RTC_CONTROL2, 0x00) < 0) + goto err; + + if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) + goto err; + + /* Clear the VL bit in the seconds register. */ + ret = rtc_read(RTC_SECONDS); + + if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0) + goto err; + + /* Reset the alarms. */ + if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_DAY_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0) + goto err; + + if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { + printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n", + PCF8563_NAME, PCF8563_MAJOR); + return -1; + } + + printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); + + /* Check for low voltage, and warn about it.. */ + if (rtc_read(RTC_SECONDS) & 0x80) + printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); + + return 0; + +err: + printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); + return -1; +} + +void __exit +pcf8563_exit(void) +{ + if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) { + printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME); + } +} + +/* + * ioctl calls for this driver. Why return -ENOTTY upon error? Because + * POSIX says so! + */ +int +pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + /* Some sanity checks. */ + if (_IOC_TYPE(cmd) != RTC_MAGIC) + return -ENOTTY; + + if (_IOC_NR(cmd) > RTC_MAX_IOCTL) + return -ENOTTY; + + switch (cmd) { + case RTC_RD_TIME: + { + struct rtc_time tm; + + get_rtc_time(&tm); + + if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { + return -EFAULT; + } + + return 0; + } + break; + case RTC_SET_TIME: + { + int leap; + int century; + unsigned long flags; + struct rtc_time tm; + + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) + return -EFAULT; + + /* Convert from struct tm to struct rtc_time. */ + tm.tm_year += 1900; + tm.tm_mon += 1; + + leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0; + + /* Perform some sanity checks. */ + if ((tm.tm_year < 1970) || + (tm.tm_mon > 12) || + (tm.tm_mday == 0) || + (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || + (tm.tm_hour >= 24) || + (tm.tm_min >= 60) || + (tm.tm_sec >= 60)) + return -EINVAL; + + century = (tm.tm_year >= 2000) ? 0x80 : 0; + tm.tm_year = tm.tm_year % 100; + + BIN_TO_BCD(tm.tm_year); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_sec); + tm.tm_mon |= century; + + rtc_write(RTC_YEAR, tm.tm_year); + rtc_write(RTC_MONTH, tm.tm_mon); + rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); + rtc_write(RTC_HOURS, tm.tm_hour); + rtc_write(RTC_MINUTES, tm.tm_min); + rtc_write(RTC_SECONDS, tm.tm_sec); + + return 0; + } + break; + default: + return -ENOTTY; + } + + return 0; +} + +int +pcf8563_open(struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +int +pcf8563_release(struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +EXPORT_NO_SYMBOLS; +module_init(pcf8563_init); +module_exit(pcf8563_exit); diff --git a/arch/cris/drivers/serial.c b/arch/cris/arch-v10/drivers/serial.c similarity index 71% rename from arch/cris/drivers/serial.c rename to arch/cris/arch-v10/drivers/serial.c index 1a47d686061..2822ffb812c 100644 --- a/arch/cris/drivers/serial.c +++ b/arch/cris/arch-v10/drivers/serial.c @@ -1,13 +1,129 @@ -/* $Id: serial.c,v 1.3 2001/12/19 10:32:35 johana Exp $ +/* $Id: serial.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ * * Serial port driver for the ETRAX 100LX chip * - * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Axis Communications AB * - * Many, many authors. Based once upon a time on serial.c for 16x50. + * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ - * Revision 1.3 2001/12/19 10:32:35 johana + * Revision 1.17 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.16 2003/06/13 10:05:19 johana + * Help the user to avoid trouble by: + * Forcing mixed mode for status/control lines if not all pins are used. + * + * Revision 1.15 2003/06/13 09:43:01 johana + * Merged in the following changes from os/linux/arch/cris/drivers/serial.c + * + some minor changes to reduce diff. + * + * Revision 1.49 2003/05/30 11:31:54 johana + * Merged in change-branch--serial9bit that adds CMSPAR support for sticky + * parity (mark/space) + * + * Revision 1.48 2003/05/30 11:03:57 johana + * Implemented rs_send_xchar() by disabling the DMA and writing manually. + * Added e100_disable_txdma_channel() and e100_enable_txdma_channel(). + * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar + * instead of setting info->x_char and check the CRTSCTS flag before + * controlling the rts pin. + * + * Revision 1.14 2003/04/09 08:12:44 pkj + * Corrected typo changes made upstream. + * + * Revision 1.13 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.11 2003/01/22 06:48:37 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.9 2002/12/13 09:07:47 starvik + * Alert user that RX_TIMEOUT_TICKS==0 doesn't work + * + * Revision 1.8 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.7 2002/12/06 07:13:57 starvik + * Corrected work queue stuff + * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + * + * Revision 1.6 2002/11/21 07:17:46 starvik + * Change static inline to extern inline where otherwise outlined with gcc-3.2 + * + * Revision 1.5 2002/11/14 15:59:49 starvik + * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff + * probably doesn't work yet. + * + * Revision 1.42 2002/11/05 09:08:47 johana + * Better implementation of rs_stop() and rs_start() that uses the XOFF + * register to start/stop transmission. + * change_speed() also initilises XOFF register correctly so that + * auto_xoff is enabled when IXON flag is set by user. + * This gives fast XOFF response times. + * + * Revision 1.41 2002/11/04 18:40:57 johana + * Implemented rs_stop() and rs_start(). + * Simple tests using hwtestserial indicates that this should be enough + * to make it work. + * + * Revision 1.40 2002/10/14 05:33:18 starvik + * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled + * + * Revision 1.39 2002/09/30 21:00:57 johana + * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and + * control pins can be mixed between PA and PB. + * If no serial port uses MIXED old solution is used + * (saves a few bytes and cycles). + * control_pins struct uses masks instead of bit numbers. + * Corrected dummy values and polarity in line_info() so + * /proc/tty/driver/serial is now correct. + * (the E100_xxx_GET() macros is really active low - perhaps not obvious) + * + * Revision 1.38 2002/08/23 11:01:36 starvik + * Check that serial port is enabled in all interrupt handlers to avoid + * restarts of DMA channels not assigned to serial ports + * + * Revision 1.37 2002/08/13 13:02:37 bjornw + * Removed some warnings because of unused code + * + * Revision 1.36 2002/08/08 12:50:01 starvik + * Serial interrupt is shared with synchronous serial port driver + * + * Revision 1.35 2002/06/03 10:40:49 starvik + * Increased RS-485 RTS toggle timer to 2 characters + * + * Revision 1.34 2002/05/28 18:59:36 johana + * Whitespace and comment fixing to be more like etrax100ser.c 1.71. + * + * Revision 1.33 2002/05/28 17:55:43 johana + * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time) + * timer from tranismit_chars (interrupt context). + * The timer toggles RTS in interrupt context when expired giving minimum + * latencies. + * + * Revision 1.32 2002/05/22 13:58:00 johana + * Renamed rs_write() to raw_write() and made it inline. + * New rs_write() handles RS-485 if configured and enabled + * (moved code from e100_write_rs485()). + * RS-485 ioctl's uses copy_from_user() instead of verify_area(). + * + * Revision 1.31 2002/04/22 11:20:03 johana + * Updated copyright years. + * + * Revision 1.30 2002/04/22 09:39:12 johana + * RS-485 support compiles. + * + * Revision 1.29 2002/01/14 16:10:01 pkj + * Allocate the receive buffers dynamically. The static 4kB buffer was + * too small for the peaks. This means that we can get rid of the extra + * buffer and the copying to it. It also means we require less memory + * under normal operations, but can use more when needed (there is a + * cap at 64kB for safety reasons). If there is no memory available + * we panic(), and die a horrible death... + * + * Revision 1.28 2001/12/18 15:04:53 johana * Cleaned up write_rs485() - now it works correctly without padding extra * char. * Added sane default initialisation of rs485. @@ -283,7 +399,7 @@ * */ -static char *serial_version = "$Revision: 1.3 $"; +static char *serial_version = "$Revision: 1.17 $"; #include #include @@ -301,12 +417,8 @@ static char *serial_version = "$Revision: 1.3 $"; #include #include #include -#if (LINUX_VERSION_CODE >= 131343) #include -#endif -#if (LINUX_VERSION_CODE >= 131336) #include -#endif #include #include @@ -314,28 +426,38 @@ static char *serial_version = "$Revision: 1.3 $"; #include #include #include -#include +#include -#include +#include /* non-arch dependent serial structures are in linux/serial.h */ #include /* while we keep our own stuff (struct e100_serial) in a local .h file */ #include "serial.h" +#include + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +#ifndef CONFIG_ETRAX_FAST_TIMER +#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" +#endif +#endif + +#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ + (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) +#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" +#endif /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h */ -#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#if defined(LOCAL_HEADERS) #include "serial_compat.h" #endif #define _INLINE_ inline -static DECLARE_TASK_QUEUE(tq_serial); - -static struct tty_driver *serial_driver; +struct tty_driver *serial_driver; /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL @@ -361,8 +483,7 @@ static struct tty_driver *serial_driver; #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) -#define SERIAL_RECV_SIZE 4096 -#define SERIAL_DESCR_BUF_SIZE 512 +#define SERIAL_DESCR_BUF_SIZE 256 /* Add an x here to log a lot of timer stuff */ #define TIMERD(x) @@ -381,6 +502,14 @@ static void change_speed(struct e100_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count); +static inline int raw_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); +#ifdef CONFIG_ETRAX_RS485 +static int e100_write_rs485(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); +#endif +static int get_lsr_info(struct e100_serial * info, unsigned int *value); + #define DEF_BAUD 0x99 /* 115.2 kbit/s */ #define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) @@ -487,6 +616,9 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static struct fast_timer fast_timers[NR_PORTS]; +#endif #ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY #define PROCSTAT(x) x @@ -506,7 +638,7 @@ struct ser_statistics_type { static struct ser_statistics_type ser_stat[NR_PORTS]; -#else +#else #define PROCSTAT(x) @@ -514,91 +646,440 @@ static struct ser_statistics_type ser_stat[NR_PORTS]; /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) +#ifdef CONFIG_ETRAX_FAST_TIMER +static struct fast_timer fast_timers_rs485[NR_PORTS]; +#endif #if defined(CONFIG_ETRAX_RS485_ON_PA) static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #endif - -/* For now we assume that all bits are on the same port for each serial port */ +/* Info and macros needed for each ports extra control/status signals. */ +#define E100_STRUCT_PORT(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (R_PORT_PA_DATA): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (R_PORT_PB_DATA):&dummy_ser[line])) + +#define E100_STRUCT_SHADOW(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (&port_pa_data_shadow): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (&port_pb_data_shadow):&dummy_ser[line])) +#define E100_STRUCT_MASK(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (1<= 0)? \ + (1<line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit)) +#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) /* Normally inputs */ -#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit)) -#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit)) +#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) +#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) /* Input */ -#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit)) +#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, @@ -653,43 +1130,6 @@ static DECLARE_MUTEX(tmp_buf_sem); static struct semaphore tmp_buf_sem = MUTEX; #endif -#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - -/* clock select 10 for timer 1 gives 230400 Hz */ -#define FASTTIMER_SELECT (10) -/* we use a source of 230400 Hz and a divider of 15 => 15360 Hz */ -#define FASTTIMER_DIV (15) - -/* fast flush timer stuff */ -static int fast_timer_started = 0; -static unsigned long int fast_timer_ints = 0; - -static void _INLINE_ start_flush_timer(void) -{ - if (fast_timer_started) - return; - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - (r_timer_ctrl_shadow & - ~IO_MASK(R_TIMER_CTRL, timerdiv1) & - ~IO_MASK(R_TIMER_CTRL, tm1) & - ~IO_MASK(R_TIMER_CTRL, clksel1)) | - IO_FIELD(R_TIMER_CTRL, timerdiv1, FASTTIMER_DIV) | - IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | - IO_FIELD(R_TIMER_CTRL, clksel1, FASTTIMER_SELECT); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | - IO_STATE(R_TIMER_CTRL, tm1, run); - - /* enable timer1 irq */ - - *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); - - fast_timer_started = 1; -} -#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ - /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { @@ -754,7 +1194,7 @@ cflag_to_etrax_baud(unsigned int cflag) retval = baud_table[cflag & CBAUD]; if (retval < 0) { - printk("serdriver tried setting invalid baud rate, flags %x.\n", cflag); + printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); retval = 5; /* choose default 9600 instead */ } @@ -770,16 +1210,17 @@ cflag_to_etrax_baud(unsigned int cflag) * any general port. */ + static inline void e100_dtr(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM - unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit); + unsigned char mask = e100_modem_pins[info->line].dtr_mask; #ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].shadow, + info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif /* DTR is active low */ @@ -788,20 +1229,15 @@ e100_dtr(struct e100_serial *info, int set) save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].dtr_shadow &= ~mask; + *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].dtr_bit, !set); -#endif #ifdef SERIAL_DEBUG_IO printk("ser%i shadow after 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].shadow, + info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif #endif @@ -814,15 +1250,16 @@ static inline void e100_rts(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM -#ifdef SERIAL_DEBUG_IO - printk("ser%i rts %i\n", info->line, set); -#endif info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ info->port[REG_REC_CTRL] = info->rx_ctrl; +#ifdef SERIAL_DEBUG_IO + printk("ser%i rts %i\n", info->line, set); +#endif #endif } + /* If this behaves as a modem, RI and CD is an output */ static inline void e100_ri_out(struct e100_serial *info, int set) @@ -830,21 +1267,16 @@ e100_ri_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* RI is active low */ { - unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit); + unsigned char mask = e100_modem_pins[info->line].ri_mask; unsigned long flags; save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].ri_shadow &= ~mask; + *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].ri_bit, !set); -#endif #endif } static inline void @@ -853,21 +1285,16 @@ e100_cd_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* CD is active low */ { - unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit); + unsigned char mask = e100_modem_pins[info->line].cd_mask; unsigned long flags; save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].cd_shadow &= ~mask; + *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].cd_bit, !set); -#endif #endif } @@ -931,6 +1358,60 @@ e100_enable_txdma_irq(struct e100_serial *info) *R_IRQ_MASK2_SET = info->irq; } +static inline void +e100_disable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + /* Disable output DMA channel for the serial port in question + * ( set to something other then serialX) + */ + save_flags(flags); + cli(); + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); + } + *R_GEN_CONFIG = genconfig_shadow; + restore_flags(flags); +} + + +static inline void +e100_enable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + save_flags(flags); + cli(); + /* Enable output DMA channel for the serial port in question */ + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); + } + *R_GEN_CONFIG = genconfig_shadow; + restore_flags(flags); +} + + #ifdef SERIAL_HANDLE_EARLY_ERRORS /* in order to detect and fix errors on the first byte we have to use the serial interrupts as well. */ @@ -972,88 +1453,98 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) info->rs485.rts_after_sent = 0x01 & r->rts_after_sent; info->rs485.delay_rts_before_send = r->delay_rts_before_send; info->rs485.enabled = r->enabled; - +/* printk("rts: on send = %i, after = %i, enabled = %i", + info->rs485.rts_on_send, + info->rs485.rts_after_sent, + info->rs485.enabled + ); +*/ return 0; } static int -e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) +e100_write_rs485(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) { - int total; struct e100_serial * info = (struct e100_serial *)tty->driver_data; + int old_enabled = info->rs485.enabled; - /* If we are in RS-485 mode, we need to toggle RTS and disable - * the receiver before initiating a DMA transfer + /* rs485 is always implicitly enabled if we're using the ioctl() + * but it doesn't have to be set in the rs485_control + * (to be backward compatible with old apps) + * So we store, set and restore it. */ - e100_rts(info, info->rs485.rts_on_send); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_disable_rx(info); - e100_disable_rxdma_irq(info); -#endif - - if (info->rs485.delay_rts_before_send > 0) { - current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000; - current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; - } - total = rs_write(tty, 1, (*r).outc, (*r).outc_size); - - /* If we are in RS-485 mode the following things has to be done: - * wait until DMA is ready - * wait on transmit shift register - * wait to toggle RTS - * enable the receiver - */ + info->rs485.enabled = 1; + /* rs_write now deals with RS485 if enabled */ + count = rs_write(tty, from_user, buf, count); + info->rs485.enabled = old_enabled; + return count; +} - /* Sleep until all sent */ - tty_wait_until_sent(tty, 0); -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER - /* Now sleep a little more so that shift register is empty */ - schedule_usleep(info->char_time_usec * 2); -#else - { - unsigned int val; - /* wait on transmit shift register */ - do{ - get_lsr_info(info, &val); - }while (!(val & TIOCSER_TEMT)); - } -#endif +#ifdef CONFIG_ETRAX_FAST_TIMER +/* Timer function to toggle RTS when using FAST_TIMER */ +static void rs485_toggle_rts_timer_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + fast_timers_rs485[info->line].function = NULL; e100_rts(info, info->rs485.rts_after_sent); - #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif - - return total; } #endif +#endif /* CONFIG_ETRAX_RS485 */ /* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. + * They enable or disable transmitter using the XOFF registers, as necessary. * ------------------------------------------------------------ */ -/* FIXME - when are these used and what is the purpose ? - * In rs_stop we probably just can block the transmit DMA ready irq - * and in rs_start we re-enable it (and then the old one will come). - */ - static void rs_stop(struct tty_struct *tty) { + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + save_flags(flags); cli(); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); + if (tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; + restore_flags(flags); + } } static void rs_start(struct tty_struct *tty) { + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + save_flags(flags); cli(); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); + if (tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; + + restore_flags(flags); + } } /* @@ -1086,8 +1577,7 @@ rs_sched_event(struct e100_serial *info, int event) { info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); + schedule_work(&info->work); } /* The output DMA channel is free - use it to send as many chars as possible @@ -1136,7 +1626,7 @@ transmit_chars(struct e100_serial *info) #endif if (!info->tr_running) { /* weirdo... we shouldn't get here! */ - printk("Achtung: transmit_chars with !tr_running\n"); + printk(KERN_WARNING "Achtung: transmit_chars with !tr_running\n"); return; } @@ -1173,26 +1663,16 @@ transmit_chars(struct e100_serial *info) /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; -#if defined(CONFIG_ETRAX_RS485) - /* Check if we should toggle RTS now */ +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) if (info->rs485.enabled) { - /* Make sure fifo is empty */ - int in_fifo = 0; - - do { - in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, - *info->ostatusadr); - } while (in_fifo > 0); - /* Any way to really check transmitter empty? (TEMT) */ - /* Control RTS to set to RX mode */ - e100_rts(info, info->rs485.rts_after_sent); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_enable_rx(info); - e100_enable_rxdma_irq(info); -#endif + /* Set a short timer to toggle RTS */ + start_one_shot_timer(&fast_timers_rs485[info->line], + rs485_toggle_rts_timer_function, + (unsigned long)info, + info->char_time_usec*2, + "RS-485"); } #endif /* RS485 */ - return; } @@ -1208,7 +1688,7 @@ transmit_chars(struct e100_serial *info) *info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */ /* DMA is now running (hopefully) */ -} +} /* transmit_chars */ static void start_transmit(struct e100_serial *info) @@ -1224,7 +1704,7 @@ start_transmit(struct e100_serial *info) info->tr_running = 1; transmit_chars(info); -} +} /* start_transmit */ #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static int serial_fast_timer_started = 0; @@ -1254,49 +1734,91 @@ static void flush_timeout_function(unsigned long data); #define START_FLUSH_FAST_TIMER(info, string) #endif +static struct etrax_recv_buffer * +alloc_recv_buffer(unsigned int size) +{ + struct etrax_recv_buffer *buffer; + + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + return NULL; + + buffer->next = NULL; + buffer->length = 0; + buffer->error = TTY_NORMAL; + + return buffer; +} + +static void +append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (!info->first_recv_buffer) + info->first_recv_buffer = buffer; + else + info->last_recv_buffer->next = buffer; + + info->last_recv_buffer = buffer; + + info->recv_cnt += buffer->length; + if (info->recv_cnt > info->max_recv_cnt) + info->max_recv_cnt = info->recv_cnt; + + restore_flags(flags); +} + static int add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) { - if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + struct etrax_recv_buffer *buffer; + + if (!(buffer = alloc_recv_buffer(4))) return 0; - info->recv.buf[info->recv.head] = data; - info->flag_buf[info->recv.head] = flag; - info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1); + buffer->length = 1; + buffer->error = flag; + buffer->buffer[0] = data; + + append_recv_buffer(info, buffer); info->icount.rx++; return 1; } -static _INLINE_ unsigned int -copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf) +extern _INLINE_ unsigned int +handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl) { - unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - unsigned int length = 0; + struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; - while (length < recvl && count) { - if (length + count > recvl) - count = recvl - length; + if (info->recv_cnt + recvl > 65536) { + printk(KERN_CRIT + "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl); + return 0; + } - memcpy(info->recv.buf + info->recv.head, buf + length, count); - memset(info->flag_buf + info->recv.head, '\0', count); - info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1); - length += count; + buffer->length = recvl; - count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - } + if (info->errorcode == ERRCODE_SET_BREAK) + buffer->error = TTY_BREAK; + info->errorcode = 0; - if (length != recvl) { - printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length); - PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length); - } + append_recv_buffer(info, buffer); - return length; + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + + descr->buf = virt_to_phys(buffer->buffer); + + return recvl; } static _INLINE_ unsigned int -copy_all_descr_data(struct e100_serial *info) +handle_all_descr_data(struct e100_serial *info) { struct etrax_dma_descr *descr; unsigned int recvl; @@ -1330,7 +1852,7 @@ copy_all_descr_data(struct e100_serial *info) /* update stats */ info->icount.rx += recvl; - ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf)); + ret += handle_descr_data(info, descr, recvl); } return ret; @@ -1341,7 +1863,6 @@ receive_chars(struct e100_serial *info) { struct tty_struct *tty; unsigned char rstat; - unsigned int old_head; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1366,12 +1887,7 @@ receive_chars(struct e100_serial *info) if (info->errorcode == ERRCODE_INSERT_BREAK) add_char_and_flag(info, '\0', TTY_BREAK); - old_head = info->recv.head; - - if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK) - info->flag_buf[old_head] = TTY_BREAK; - - info->errorcode = 0; + handle_all_descr_data(info); /* Read the status register to detect errors */ rstat = info->port[REG_STATUS]; @@ -1394,10 +1910,6 @@ receive_chars(struct e100_serial *info) add_char_and_flag(info, data, TTY_FRAME); } - if (!E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT) - info->tty->driver->throttle(info->tty); - START_FLUSH_FAST_TIMER(info, "receive_chars"); /* Restart the receiving DMA */ @@ -1408,19 +1920,20 @@ static _INLINE_ int start_recv_dma(struct e100_serial *info) { struct etrax_dma_descr *descr = info->rec_descr; - unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE; + struct etrax_recv_buffer *buffer; int i; /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + descr[i].ctrl = d_int; - descr[i].buf = virt_to_phys(buf); + descr[i].buf = virt_to_phys(buffer->buffer); descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; descr[i].hw_len = 0; descr[i].status = 0; descr[i].next = virt_to_phys(&descr[i+1]); - - buf += SERIAL_DESCR_BUF_SIZE; } /* Link the last descriptor to the first */ @@ -1448,7 +1961,7 @@ start_receive(struct e100_serial *info) #endif /* reset the input dma channel to be sure it works */ - + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); @@ -1456,10 +1969,6 @@ start_receive(struct e100_serial *info) info->tty->flip.count = 0; start_recv_dma(info); - -#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - start_flush_timer(); -#endif } @@ -1480,13 +1989,14 @@ status_handle(struct e100_serial *info, unsigned short status) DMA8(ser1) when they have finished a descriptor with the intr flag set. */ -static void +static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct e100_serial *info; unsigned long ireg; int i; - + int handled = 0; + #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of * the serial interface works, and this piece will just be removed. @@ -1495,7 +2005,7 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) const char *s = "What? tr_interrupt in simulator??\n"; SIMCOUT(s,strlen(s)); } - return; + return IRQ_HANDLED; #endif /* find out the line that caused this irq and get it from rs_table */ @@ -1504,10 +2014,11 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ if (ireg & info->irq) { + handled = 1; /* we can send a new dma bunch. make it so. */ DEBUG_LOG(info->line, "tr_interrupt %i\n", i); /* Read jiffies_usec first, @@ -1522,16 +2033,18 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* FIXME: here we should really check for a change in the status lines and if so call status_handle(info) */ } + return IRQ_RETVAL(handled); } /* dma input channel interrupt handler */ -static void +static irqreturn_t rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct e100_serial *info; unsigned long ireg; int i; + int handled = 0; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1550,10 +2063,11 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* check for both dma_eop and dma_descr for the input dma channel */ if (ireg & ((info->irq << 2) | (info->irq << 3))) { + handled = 1; /* we have received something */ receive_chars(info); } @@ -1561,6 +2075,7 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* FIXME: here we should really check for a change in the status lines and if so call status_handle(info) */ } + return IRQ_RETVAL(handled); } static _INLINE_ int @@ -1611,48 +2126,56 @@ force_eop_if_needed(struct e100_serial *info) static _INLINE_ void flush_to_flip_buffer(struct e100_serial *info) { - struct tty_struct *tty = info->tty; - unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + struct tty_struct *tty; + struct etrax_recv_buffer *buffer; unsigned int length; unsigned long flags; - if (!count) + if (!info->first_recv_buffer) return; save_flags(flags); cli(); + if (!(tty = info->tty)) { + restore_flags(flags); + return; + } + length = tty->flip.count; - - do { + + while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) { + unsigned int count = buffer->length; + if (length + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - length; - memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count); - memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count); - info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1)); + memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); + memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); + tty->flip.flag_buf_ptr[length] = buffer->error; + length += count; - - count = CIRC_CNT_TO_END(info->recv.head, - info->recv.tail, - SERIAL_RECV_SIZE); - } while (length < TTY_FLIPBUF_SIZE && count); + info->recv_cnt -= count; + + if (count == buffer->length) { + info->first_recv_buffer = buffer->next; + kfree(buffer); + } else { + buffer->length -= count; + memmove(buffer->buffer, buffer->buffer + count, buffer->length); + buffer->error = TTY_NORMAL; + } + } + + if (!info->first_recv_buffer) + info->last_recv_buffer = NULL; tty->flip.count = length; restore_flags(flags); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66) /* this includes a check for low-latency */ tty_flip_buffer_push(tty); -#else - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); -#endif - - /* unthrottle if we have throttled */ - if (E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT) - tty->driver->unthrottle(info->tty); } static _INLINE_ void @@ -1662,7 +2185,7 @@ check_flush_timeout(struct e100_serial *info) flush_to_flip_buffer(info); - if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + if (info->first_recv_buffer) START_FLUSH_FAST_TIMER(info, "flip"); } @@ -1678,43 +2201,11 @@ static void flush_timeout_function(unsigned long data) check_flush_timeout(info); } -#elif defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) - -static void -timeout_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct e100_serial *info; - int i; - -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? timeout_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return; -#endif - - /* acknowledge the timer1 irq */ - *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); - PROCSTAT(fast_timer_ints++); - - for (i = 0; i < NR_PORTS; i++) { - info = rs_table + i; - if (info->uses_dma) - check_flush_timeout(info); - } -} /* timeout_interrupt */ - #else /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. - If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this - handler is instead run at 15360 Hz. */ static struct timer_list flush_timer; @@ -1810,7 +2301,7 @@ TODO: The break will be delayed until an F or V character is received. */ -static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) +extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) { unsigned char rstat = info->port[REG_STATUS]; @@ -1869,7 +2360,7 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) } info->break_detected_cnt = 0; DEBUG_LOG(info->line, "#iERR s d %04X\n", - ((rstat & SER_ERROR_MASK) << 8) | data); + ((rstat & SER_ERROR_MASK) << 8) | data); } PROCSTAT(ser_stat[info->line].early_errors_cnt++); } else { /* It was a valid byte, now let the DMA do the rest */ @@ -1883,8 +2374,8 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) * previous interrupt we should discard it. */ long elapsed_usec = - (curr_time - info->last_rx_active) * (1000000/HZ) + - curr_time_u - info->last_rx_active_usec; + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; if (elapsed_usec < 2*info->char_time_usec) { DEBUG_LOG(info->line, "FBRK %i\n", info->line); /* Report as BREAK (error) and let @@ -1911,25 +2402,29 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); START_FLUSH_FAST_TIMER(info, "ser_int"); + return IRQ_HANDLED; } /* handle_ser_interrupt */ -static void +static irqreturn_t ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct e100_serial *info; int i; + int handled = 0; for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* Which line caused the irq? */ if (*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { + handled = 1; handle_ser_interrupt(info); } } + return IRQ_RETVAL(handled); } /* ser_interrupt */ #endif @@ -1949,12 +2444,6 @@ ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) * them using rs_sched_event(), and they get done here. */ static void -do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) { struct e100_serial *info = (struct e100_serial *) private_; @@ -1972,53 +2461,25 @@ do_softint(void *private_) } } -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void -do_serial_hangup(void *private_) -{ - struct e100_serial *info = (struct e100_serial *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); -} - static int startup(struct e100_serial * info) { unsigned long flags; unsigned long xmit_page; - unsigned char *recv_page; + int i; xmit_page = get_zeroed_page(GFP_KERNEL); if (!xmit_page) return -ENOMEM; - recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL); - if (!recv_page) { - free_page(xmit_page); - return -ENOMEM; - } - - save_flags(flags); cli(); + save_flags(flags); + cli(); /* if it was already initialized, skip this */ if (info->flags & ASYNC_INITIALIZED) { restore_flags(flags); free_page(xmit_page); - kfree(recv_page); return 0; } @@ -2027,13 +2488,6 @@ startup(struct e100_serial * info) else info->xmit.buf = (unsigned char *) xmit_page; - if (info->recv.buf) - kfree(recv_page); - else { - info->recv.buf = (unsigned char *) recv_page; - info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE; - } - #ifdef SERIAL_DEBUG_OPEN printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf); #endif @@ -2044,8 +2498,13 @@ startup(struct e100_serial * info) right? */ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = NULL; /* No real action in the simulator, but may set info important to ioctl. */ @@ -2084,8 +2543,12 @@ startup(struct e100_serial * info) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = 0; + /* * and set the speed and other flags of the serial port * this will start the rx/tx as well @@ -2137,6 +2600,9 @@ static void shutdown(struct e100_serial * info) { unsigned long flags; + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; #ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ @@ -2173,11 +2639,12 @@ shutdown(struct e100_serial * info) info->xmit.buf = NULL; } - if (info->recv.buf) { - kfree(info->recv.buf); - info->recv.buf = NULL; - info->flag_buf = NULL; - } + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + if (descr[i].buf) { + buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; + kfree(buffer); + descr[i].buf = 0; + } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ @@ -2199,6 +2666,7 @@ static void change_speed(struct e100_serial *info) { unsigned int cflag; + unsigned long xoff; /* first some safety checks */ @@ -2248,10 +2716,21 @@ change_speed(struct e100_serial *info) info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); } - if (cflag & PARODD) { - /* set odd parity */ - info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); - info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); + if (cflag & CMSPAR) { + /* enable stick parity */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); + if (!(cflag & PARODD)) { + /* set mark parity */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); + } + } else { + if (cflag & PARODD) { + /* set odd parity */ + info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); + info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); + } } if (cflag & CRTSCTS) { @@ -2268,7 +2747,13 @@ change_speed(struct e100_serial *info) info->port[REG_TR_CTRL] = info->tx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl; - *((unsigned long *)&info->port[REG_XOFF]) = 0; + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); + if (info->tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; #endif /* !CONFIG_SVINTO_SIM */ update_char_time(info); @@ -2301,9 +2786,9 @@ rs_flush_chars(struct tty_struct *tty) restore_flags(flags); } -static int -rs_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) +extern inline int +raw_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) { int c, ret = 0; struct e100_serial *info = (struct e100_serial *)tty->driver_data; @@ -2316,7 +2801,7 @@ rs_write(struct tty_struct * tty, int from_user, #ifdef SERIAL_DEBUG_DATA if (info->line == SERIAL_DEBUG_LINE) - printk("rs_write (%d), status %d\n", + printk("raw_write (%d), status %d\n", count, info->port[REG_STATUS]); #endif @@ -2402,7 +2887,74 @@ rs_write(struct tty_struct * tty, int from_user, } return ret; -} +} /* raw_write() */ + +static int +rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ +#if defined(CONFIG_ETRAX_RS485) + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + if (info->rs485.enabled) + { + /* If we are in RS-485 mode, we need to toggle RTS and disable + * the receiver before initiating a DMA transfer + */ +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Abort any started timer */ + fast_timers_rs485[info->line].function = NULL; + del_fast_timer(&fast_timers_rs485[info->line]); +#endif + e100_rts(info, info->rs485.rts_on_send); +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_disable_rx(info); + e100_disable_rxdma_irq(info); +#endif + + if (info->rs485.delay_rts_before_send > 0) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000); + } + } +#endif /* CONFIG_ETRAX_RS485 */ + + count = raw_write(tty, from_user, buf, count); + +#if defined(CONFIG_ETRAX_RS485) + if (info->rs485.enabled) + { + unsigned int val; + /* If we are in RS-485 mode the following has to be done: + * wait until DMA is ready + * wait on transmit shift register + * toggle RTS + * enable the receiver + */ + + /* Sleep until all sent */ + tty_wait_until_sent(tty, 0); +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Now sleep a little more so that shift register is empty */ + schedule_usleep(info->char_time_usec * 2); +#endif + /* wait on transmit shift register */ + do{ + get_lsr_info(info, &val); + }while (!(val & TIOCSER_TEMT)); + + e100_rts(info, info->rs485.rts_after_sent); + +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rxdma_irq(info); +#endif + } +#endif /* CONFIG_ETRAX_RS485 */ + + return count; +} /* rs_write */ + /* how much space is available in the xmit buffer? */ @@ -2451,20 +3003,23 @@ rs_flush_buffer(struct tty_struct *tty) * This function is used to send a high-priority XON/XOFF character to * the device * - * Since we don't bother to check for info->x_char in transmit_chars yet, - * we don't really implement this function yet. + * Since we use DMA we don't check for info->x_char in transmit_chars, + * just disable DMA channel and write the character when possible. */ static void rs_send_xchar(struct tty_struct *tty, char ch) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; - printk("serial.c:rs_send_xchar not implemented!\n"); + e100_disable_txdma_channel(info); - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - /* TODO. */ - } + /* Wait for tr_ready */ + while (!(info->port[REG_STATUS] & IO_MASK(R_SERIAL0_STATUS, tr_ready))) + /* wait */; + + /* Write the XON/XOFF char */ + info->port[REG_TR_DATA] = ch; + + e100_enable_txdma_channel(info); } /* @@ -2482,20 +3037,22 @@ rs_throttle(struct tty_struct * tty) unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("throttle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - + + /* Do RTS before XOFF since XOFF might take some time */ + if (tty->termios->c_cflag & CRTSCTS) { + /* Turn off RTS line (do this atomic) */ + save_flags(flags); + cli(); + e100_rts(info, 0); + restore_flags(flags); + } if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) should here be an else ?? */ - - save_flags(flags); - cli(); - e100_rts(info, 0); - restore_flags(flags); + rs_send_xchar(tty, STOP_CHAR(tty)); + } static void @@ -2505,24 +3062,27 @@ rs_unthrottle(struct tty_struct * tty) unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - + + /* Do RTS before XOFF since XOFF might take some time */ + if (tty->termios->c_cflag & CRTSCTS) { + /* Assert RTS line (do this atomic) */ + save_flags(flags); + cli(); + e100_rts(info, 1); + restore_flags(flags); + } + if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else - info->x_char = START_CHAR(tty); + rs_send_xchar(tty, START_CHAR(tty)); } - - /* Assert RTS line (do this atomic) */ - - save_flags(flags); - cli(); - e100_rts(info, 1); - restore_flags(flags); + } /* @@ -2594,9 +3154,7 @@ set_serial_info(struct e100_serial *info, info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif check_and_exit: if (info->flags & ASYNC_INITIALIZED) { @@ -2641,8 +3199,8 @@ get_lsr_info(struct e100_serial * info, unsigned int *value) #ifdef SERIAL_DEBUG_IO struct state_str { - int state; - const char *str; + int state; + const char *str; }; const struct state_str control_state_str[] = { @@ -2690,14 +3248,15 @@ get_modem_info(struct e100_serial * info, unsigned int *value) E100_DSR_GET(info), E100_CTS_GET(info)); #endif + result = (!E100_RTS_GET(info) ? TIOCM_RTS : 0) | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) - | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_RI_GET(info) ? TIOCM_RNG : 0) | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) + | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); - + #ifdef SERIAL_DEBUG_IO printk("e100ser: modem state: %i 0x%08X\n", result, result); { @@ -2766,44 +3325,7 @@ set_modem_info(struct e100_serial * info, unsigned int cmd, return 0; } -/* - * This routine sends a break character out the serial port. - */ -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static void -send_break(struct e100_serial * info, int duration) -{ - unsigned long flags; - - if (!info->port) - return; - - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; - - save_flags(flags); - cli(); - - /* Go to manual mode and set the txd pin to 0 */ - - info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - - /* wait for "duration" jiffies */ - - schedule(); - - info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - - /* the DMA gets awfully confused if we toggle the transceiver like this - * so we need to reset it - */ - *info->ocmdadr = 4; - restore_flags(flags); -} -#else static void rs_break(struct tty_struct *tty, int break_state) { @@ -2824,19 +3346,12 @@ rs_break(struct tty_struct *tty, int break_state) info->port[REG_TR_CTRL] = info->tx_ctrl; restore_flags(flags); } -#endif static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; -#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int error; -#endif -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int retval; -#endif if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && @@ -2846,45 +3361,6 @@ rs_ioctl(struct tty_struct *tty, struct file * file, } switch (cmd) { -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCGSOFTCAR: - error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); - if (error) - return error; - put_fs_long(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - return 0; - case TIOCSSOFTCAR: - arg = get_fs_long((unsigned long *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; -#endif case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: @@ -2908,22 +3384,22 @@ rs_ioctl(struct tty_struct *tty, struct file * file, #if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct rs485_control)); - - if (error) - return error; - - return e100_enable_rs485(tty, (struct rs485_control *) arg); + { + struct rs485_control rs485ctrl; + if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl))) + return -EFAULT; + + return e100_enable_rs485(tty, &rs485ctrl); + } case TIOCSERWRRS485: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct rs485_write)); - - if (error) - return error; - - return e100_write_rs485(tty, (struct rs485_write *) arg); + { + struct rs485_write rs485wr; + if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr))) + return -EFAULT; + + return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size); + } #endif default: @@ -2991,12 +3467,13 @@ rs_close(struct tty_struct *tty, struct file * filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("rs_close: bad serial port count; tty->count is 1, " + printk(KERN_CRIT + "rs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%d: %d\n", + printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } @@ -3149,7 +3626,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, return -EAGAIN; #endif } - + /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -3162,7 +3639,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; - + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3187,7 +3664,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, while (1) { save_flags(flags); cli(); - /* assert RTS and DTR */ + /* assert RTS and DTR */ e100_rts(info, 1); e100_dtr(info, 1); restore_flags(flags); @@ -3204,7 +3681,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & ASYNC_CLOSING) && do_clocal) + if (!(info->flags & ASYNC_CLOSING) && do_clocal) /* && (do_clocal || DCD_IS_ASSERTED) */ break; if (signal_pending(current)) { @@ -3258,17 +3735,15 @@ rs_open(struct tty_struct *tty, struct file * filp) return -ENODEV; #ifdef SERIAL_DEBUG_OPEN - printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, - info->count); + printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, + info->count); #endif info->count++; tty->driver_data = info; info->tty = tty; -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -3312,7 +3787,7 @@ rs_open(struct tty_struct *tty, struct file * filp) #endif return retval; } - + #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful...\n", info->line); #endif @@ -3323,7 +3798,7 @@ rs_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline int line_info(char *buf, struct e100_serial *info) +extern inline int line_info(char *buf, struct e100_serial *info) { char stat_buf[30]; int ret; @@ -3338,17 +3813,17 @@ static inline int line_info(char *buf, struct e100_serial *info) stat_buf[0] = 0; stat_buf[1] = 0; - if (E100_RTS_GET(info)) + if (!E100_RTS_GET(info)) strcat(stat_buf, "|RTS"); - if (E100_CTS_GET(info)) + if (!E100_CTS_GET(info)) strcat(stat_buf, "|CTS"); - if (E100_DTR_GET(info)) + if (!E100_DTR_GET(info)) strcat(stat_buf, "|DTR"); - if (E100_DSR_GET(info)) + if (!E100_DSR_GET(info)) strcat(stat_buf, "|DSR"); - if (E100_CD_GET(info)) + if (!E100_CD_GET(info)) strcat(stat_buf, "|CD"); - if (E100_RI_GET(info)) + if (!E100_RI_GET(info)) strcat(stat_buf, "|RI"); ret += sprintf(buf+ret, " baud:%d", info->baud); @@ -3357,6 +3832,10 @@ static inline int line_info(char *buf, struct e100_serial *info) (unsigned long)info->icount.tx, (unsigned long)info->icount.rx); + ret += sprintf(buf+ret, " rx_pend:%lu/%lu", + (unsigned long)info->recv_cnt, + (unsigned long)info->max_recv_cnt); + if (info->icount.frame) ret += sprintf(buf+ret, " fe:%lu", (unsigned long)info->icount.frame); @@ -3413,12 +3892,13 @@ done: static void show_serial_version(void) { - printk("ETRAX 100LX serial-driver %s, (c) 2000 Axis Communications AB\r\n", - serial_version); + printk(KERN_INFO + "ETRAX 100LX serial-driver %s, (c) 2000-2003 Axis Communications AB\r\n", + &serial_version[11]); /* "$Revision: x.yy" */ } /* rs_init inits the driver at boot (using the module_init chain) */ - + static struct tty_operations rs_ops = { .open = rs_open, .close = rs_close, @@ -3428,8 +3908,8 @@ static struct tty_operations rs_ops = { .chars_in_buffer = rs_chars_in_buffer, .flush_buffer = rs_flush_buffer, .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, .set_termios = rs_set_termios, .stop = rs_stop, .start = rs_start, @@ -3451,12 +3931,10 @@ rs_init(void) return -ENOMEM; show_serial_version(); - - init_bh(SERIAL_BH, do_serial_bh); /* Setup the timed flush handler system */ -#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) && !defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) +#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) init_timer(&flush_timer); flush_timer.function = timed_flush_handler; mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); @@ -3477,7 +3955,7 @@ rs_init(void) tty_set_operations(driver, &rs_ops); if (tty_register_driver(driver)) panic("Couldn't register serial driver\n"); - serial_driver = driver; + serial_driver = driver; /* do some initializing for the separate ports */ @@ -3495,15 +3973,12 @@ rs_init(void) info->event = 0; info->count = 0; info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; - info->recv.buf = NULL; - info->recv.tail = info->recv.head = 0; - info->flag_buf = NULL; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; info->last_tx_active_usec = 0; info->last_tx_active = 0; @@ -3514,12 +3989,22 @@ rs_init(void) info->rs485.delay_rts_before_send = 0; info->rs485.enabled = 0; #endif + INIT_WORK(&info->work, do_softint, info); if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", serial_driver->name, info->line, (unsigned int)info->port); } } +#ifdef CONFIG_ETRAX_FAST_TIMER +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER + memset(fast_timers, 0, sizeof(fast_timers)); +#endif +#ifdef CONFIG_ETRAX_RS485 + memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); +#endif + fast_timer_init(); +#endif #ifndef CONFIG_SVINTO_SIM /* Not needed in simulator. May only complicate stuff. */ @@ -3531,7 +4016,7 @@ rs_init(void) panic("irq23"); #endif #ifdef SERIAL_HANDLE_EARLY_ERRORS - if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT1 @@ -3555,12 +4040,6 @@ rs_init(void) panic("irq21"); #endif -#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT, - "fast serial dma timeout", NULL)) { - printk("err: timer1 irq\n"); - } -#endif #endif /* CONFIG_SVINTO_SIM */ return 0; diff --git a/arch/cris/drivers/serial.h b/arch/cris/arch-v10/drivers/serial.h similarity index 90% rename from arch/cris/drivers/serial.h rename to arch/cris/arch-v10/drivers/serial.h index 1994228fa10..45813c657aa 100644 --- a/arch/cris/drivers/serial.h +++ b/arch/cris/arch-v10/drivers/serial.h @@ -25,6 +25,15 @@ #define SERIAL_RECV_DESCRIPTORS 8 +struct etrax_recv_buffer { + struct etrax_recv_buffer *next; + unsigned short length; + unsigned char error; + unsigned char pad; + + unsigned char buffer[0]; +}; + struct e100_serial { int baud; volatile u8 *port; /* R_SERIALx_CTRL */ @@ -79,10 +88,12 @@ struct e100_serial { int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ struct circ_buf xmit; - struct circ_buf recv; - unsigned char *flag_buf; + struct etrax_recv_buffer *first_recv_buffer; + struct etrax_recv_buffer *last_recv_buffer; + unsigned int recv_cnt; + unsigned int max_recv_cnt; - struct tq_struct tqueue; + struct work_struct work; struct async_icount icount; /* error-statistics etc.*/ #ifdef DECLARE_WAITQUEUE wait_queue_head_t open_wait; @@ -101,7 +112,7 @@ struct e100_serial { int break_detected_cnt; int errorcode; -#ifdef CONFIG_RS485 +#ifdef CONFIG_ETRAX_RS485 struct rs485_control rs485; /* RS-485 support */ #endif }; diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile new file mode 100644 index 00000000000..20a56080a8f --- /dev/null +++ b/arch/cris/arch-v10/kernel/Makefile @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.4 2003/07/04 12:57:13 tobiasa Exp $ +# +# Makefile for the linux kernel. +# + +extra-y := head.o + + +obj-y := entry.o traps.o shadows.o debugport.o irq.o \ + process.o setup.o signal.o traps.o time.o ptrace.o + +obj-$(CONFIG_ETRAX_KGDB) += kgdb.o +obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o + +clean: + diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c new file mode 100644 index 00000000000..1aa3cc4e710 --- /dev/null +++ b/arch/cris/arch-v10/kernel/asm-offsets.c @@ -0,0 +1,47 @@ +#include +#include + +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + */ + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ +#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry)) + ENTRY(orig_r10); + ENTRY(r13); + ENTRY(r12); + ENTRY(r11); + ENTRY(r10); + ENTRY(r9); + ENTRY(mof); + ENTRY(dccr); + ENTRY(srp); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry)) + ENTRY(task); + ENTRY(flags); + ENTRY(preempt_count); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry)) + ENTRY(ksp); + ENTRY(usp); + ENTRY(dccr); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry)) + ENTRY(pid); + BLANK(); + DEFINE(LCLONE_VM, CLONE_VM); + DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED); + return 0; +} diff --git a/arch/cris/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c similarity index 64% rename from arch/cris/kernel/debugport.c rename to arch/cris/arch-v10/kernel/debugport.c index fa20b2146ad..012c3028e5f 100644 --- a/arch/cris/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -12,6 +12,33 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.11 2003/07/07 09:53:36 starvik + * Revert all the 2.5.74 merge changes to make the console work again + * + * Revision 1.9 2003/02/17 17:07:23 starvik + * Solved the problem with corrupted debug output (from Linux 2.4) + * * Wait until DMA, FIFO and pipe is empty before and after transmissions + * * Buffer data until a FIFO flush can be triggered. + * + * Revision 1.8 2003/01/22 06:48:36 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.7 2002/12/12 08:26:32 starvik + * Don't use C-comments inside CVS comments + * + * Revision 1.6 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ + * + * Revision 1.5 2002/11/20 06:58:03 starvik + * Compiles with kgdb + * + * Revision 1.4 2002/11/19 14:35:24 starvik + * Changes from linux 2.4 + * Changed struct initializer syntax to the currently prefered notation + * + * Revision 1.3 2002/11/06 09:47:03 starvik + * Modified for new interrupt macros + * * Revision 1.2 2002/01/21 15:21:50 bjornw * Update for kdev_t changes * @@ -31,9 +58,10 @@ #include #include #include +#include #include -#include +#include #include /* Get SIMCOUT. */ /* Which serial-port is our debug port ? */ @@ -94,6 +122,8 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr) #endif +#define MIN_SIZE 32 /* Size that triggers the FIFO to flush characters to interface */ + /* Write a string of count length to the console (debug port) using DMA, polled * for completion. Interrupts are disabled during the whole process. Some * caution needs to be taken to not interfere with ttyS business on this port. @@ -102,9 +132,13 @@ static void console_write(struct console *co, const char *buf, unsigned int len) { + static struct etrax_dma_descr descr; + static struct etrax_dma_descr descr2; + static char tmp_buf[MIN_SIZE]; + static int tmp_size = 0; + unsigned long flags; - int in_progress; #ifdef CONFIG_ETRAX_DEBUG_PORT_NULL /* no debug printout at all */ @@ -117,16 +151,48 @@ console_write(struct console *co, const char *buf, unsigned int len) return; #endif - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); #ifdef CONFIG_ETRAX_KGDB /* kgdb needs to output debug info using the gdb protocol */ putDebugString(buf, len); - restore_flags(flags); + local_irq_restore(flags); return; #endif + /* To make this work together with the real serial port driver + * we have to make sure that everything is flushed when we leave + * here. The following steps are made to assure this: + * 1. Wait until DMA stops, FIFO is empty and serial port pipeline empty. + * 2. Write at least half the FIFO to trigger flush to serial port. + * 3. Wait until DMA stops, FIFO is empty and serial port pipeline empty. + */ + + /* Do we have enough characters to make the DMA/FIFO happy? */ + if (tmp_size + len < MIN_SIZE) + { + int size = min((int)(MIN_SIZE - tmp_size),(int)len); + memcpy(&tmp_buf[tmp_size], buf, size); + tmp_size += size; + len -= size; + + /* Pad with space if complete line */ + if (tmp_buf[tmp_size-1] == '\n') + { + memset(&tmp_buf[tmp_size-1], ' ', MIN_SIZE - tmp_size); + tmp_buf[MIN_SIZE - 1] = '\n'; + tmp_size = MIN_SIZE; + len = 0; + } + else + { + /* Wait for more characters */ + local_irq_restore(flags); + return; + } + } + /* make sure the transmitter is enabled. * NOTE: this overrides any setting done in ttySx, to 8N1, no auto-CTS. * in the future, move the tr/rec_ctrl shadows from etrax100ser.c to @@ -134,38 +200,37 @@ console_write(struct console *co, const char *buf, unsigned int len) */ *DEBUG_TR_CTRL = 0x40; - - /* if the tty has some ongoing business, remember it */ - - in_progress = *DEBUG_OCMD & 7; - - if(in_progress) { - /* wait until the output dma channel is ready */ - - while(*DEBUG_OCMD & 7) /* nothing */ ; + while(*DEBUG_OCMD & 7); /* Until DMA is not running */ + while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */ + udelay(200); /* Wait for last two characters to leave the serial transmitter */ + + if (tmp_size) + { + descr.ctrl = len ? 0 : d_eop | d_wait | d_eol; + descr.sw_len = tmp_size; + descr.buf = virt_to_phys(tmp_buf); + descr.next = virt_to_phys(&descr2); + descr2.ctrl = d_eop | d_wait | d_eol; + descr2.sw_len = len; + descr2.buf = virt_to_phys((char*)buf); + } + else + { + descr.ctrl = d_eop | d_wait | d_eol; + descr.sw_len = len; + descr.buf = virt_to_phys((char*)buf); } - descr.ctrl = d_eol; - descr.sw_len = len; - descr.buf = __pa(buf); - - *DEBUG_FIRST = __pa(&descr); /* write to R_DMAx_FIRST */ + *DEBUG_FIRST = virt_to_phys(&descr); /* write to R_DMAx_FIRST */ *DEBUG_OCMD = 1; /* dma command start -> R_DMAx_CMD */ /* wait until the output dma channel is ready again */ + while(*DEBUG_OCMD & 7); + while(*DEBUG_STATUS & 0x7f); + udelay(200); - while(*DEBUG_OCMD & 7) /* nothing */; - - /* clear pending interrupts so we don't get a surprise below */ - - if(in_progress) - *DEBUG_OCLRINT = 2; /* only clear EOP, leave DESCR for the tty */ - else - *DEBUG_OCLRINT = 3; /* clear both EOP and DESCR */ - - while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */ - - restore_flags(flags); + tmp_size = 0; + local_irq_restore(flags); } /* legacy function */ @@ -227,11 +292,11 @@ console_setup(struct console *co, char *options) } static struct console sercons = { - .name = "ttyS", - .write = console_write, - .read = NULL, - .device = console_device, - .unblank = NULL, + .name = "ttyS", + .write = console_write, + .read = NULL, + .device = console_device, + .unblank = NULL, .setup = console_setup, .flags = CON_PRINTBUFFER, .index = DEBUG_PORT_IDX, diff --git a/arch/cris/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S similarity index 76% rename from arch/cris/kernel/entry.S rename to arch/cris/arch-v10/kernel/entry.S index 2c0477bcdd5..5e5f5be7e13 100644 --- a/arch/cris/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -1,12 +1,55 @@ -/* $Id: entry.S,v 1.3 2002/01/21 15:22:20 bjornw Exp $ +/* $Id: entry.S,v 1.16 2003/07/04 08:27:41 starvik Exp $ * * linux/arch/cris/entry.S * - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000, 2001, 2002 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.16 2003/07/04 08:27:41 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.15 2003/04/09 07:32:55 starvik + * resume should return task_struct, not thread_info + * + * Revision 1.14 2003/04/09 05:20:44 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.13 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c + * + * Revision 1.12 2002/12/10 09:00:10 starvik + * Merge of Linux 2.5.51 + * + * Revision 1.11 2002/12/05 07:53:10 starvik + * Corrected constants used with btstq + * + * Revision 1.10 2002/11/27 08:45:10 starvik + * pid is in task_struct, not thread_info + * + * Revision 1.9 2002/11/26 09:52:05 starvik + * Added preemptive kernel scheduling (if CONFIG_PREEMPT) + * + * Revision 1.8 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.7 2002/11/18 13:02:42 starvik + * Added fourth parameter to do_notify_resume + * Minor cleanup + * + * Revision 1.6 2002/11/11 10:37:50 starvik + * Use new asm-offset defines + * Modified for new location of current->work etc + * Removed SYMBOL_NAME from syscalls + * Added some new syscalls + * + * Revision 1.5 2002/11/05 06:45:11 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.4 2002/02/05 15:41:31 bjornw + * Rewritten to conform better to current 2.5 code (similar to arch/i386) + * * Revision 1.3 2002/01/21 15:22:20 bjornw * NICE_DOGGY fix from 2.4 arch/cris * @@ -185,75 +228,88 @@ #include #include #include -#include +#include #include - +#include +#include + ;; functions exported from this file .globl system_call .globl ret_from_intr - .globl ret_from_sys_call + .globl ret_from_fork .globl resume .globl multiple_interrupt .globl hwbreakpoint .globl IRQ1_interrupt - .globl timer_interrupt - .globl timer_shortcut .globl spurious_interrupt .globl hw_bp_trigs .globl mmu_bus_fault .globl do_sigtrap .globl gdb_handle_breakpoint - .globl sys_call_table - ;; Get values and offsets into various structs. The file isn't - ;; suitable for consumption by the preprocessor, so don't use - ;; #include. - .include "entryoffsets.s" - - ;; process bits for ptrace. FIXME: Should be in a header file. - -PT_TRACESYS_BIT = 1 - ;; below are various parts of system_call which are not in the fast-path - ;; handle software irqs - -_handle_softirq: - move.d $r9, $r1 - jsr do_softirq ; call the C routine for softirq handling - move.d $r1, $r9 - - ;; fall-through - +#ifdef CONFIG_PREEMPT + ; Check if preemptive kernel scheduling should be done +_resume_kernel: + ; Load current task struct + movs.w -8192, $r0 ; THREAD_SIZE = 8192 + and.d $sp, $r0 + move.d [$r0+TI_preempt_count], $r10 ; Preemption disabled? + bne _Rexit + nop +_need_resched: + move.d [$r0+TI_flags], $r10 + btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set + bpl _Rexit + nop + ; Ok, lets's do some preemptive kernel scheduling + move.d PREEMPT_ACTIVE, $r10 + move.d $r10, [$r0+TI_preempt_count] ; Mark as active + ei + jsr schedule + clear.d [$r0+TI_preempt_count] ; Mark as inactive + di + ; Load new task struct + movs.w -8192, $r0 ; THREAD_SIZE = 8192 + and.d $sp, $r0 + ; One more time (with new task) + ba _need_resched + nop +#else +#define _resume_kernel _Rexit +#endif + + ; Called at exit from fork. schedule_tail must be called to drop + ; spinlock if CONFIG_PREEMPT +ret_from_fork: + jsr schedule_tail + ba ret_from_sys_call + nop + ret_from_intr: - ;; check for resched only if we're going back to user-mode + ;; check for resched if preemptive kernel or if we're going back to user-mode ;; this test matches the user_regs(regs) macro ;; we cannot simply test $dccr, because that does not necessarily ;; reflect what mode we'll return into. - move.d [$sp + LDCCR], $r0; regs->dccr + move.d [$sp + PT_dccr], $r0; regs->dccr btstq 8, $r0 ; U-flag - bpl _Rexit ; go back directly - nop - ba _ret_with_reschedule ; go back but check schedule and signals first - nop + bpl _resume_kernel + ; Note that di below is in delay slot + +_resume_userspace: + di ; so need_resched and sigpending don't change -_reschedule: - ;; keep r9 intact - move.d $r9, $r1 - jsr schedule - ba ret_from_sys_call - move.d $r1, $r9 + movs.w -8192, $r0 ; THREAD_SIZE == 8192 + and.d $sp, $r0 - ;; return but call do_signal first -_signal_return: - ei ; we can get here from an interrupt - move.d $r9, $r10 ; do_signals syscall/irq param - moveq 0, $r11 ; oldset param - 0 in this case - move.d $sp, $r12 ; another argument to do_signal (the regs param) - jsr do_signal ; arch/cris/kernel/signal.c + move.d [$r0+TI_flags], $r10 ; current->work + and.d _TIF_WORK_MASK, $r10 ; is there any work to be done on return + bne _work_pending + nop ba _Rexit nop @@ -285,18 +341,20 @@ system_call: clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe movs.w -ENOSYS, $r0 - move.d $r0, [$sp+LR10] ; put the default return value in r10 in the frame + move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame ;; check if this process is syscall-traced movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 - move.d [$r0+LTASK_PTRACE], $r0 - btstq PT_TRACESYS_BIT, $r0 - bmi _tracesys + move.d [$r0+TI_flags], $r0 + btstq TIF_SYSCALL_TRACE, $r0 + bmi _syscall_trace_entry nop +_syscall_traced: + ;; check for sanity in the requested syscall number cmpu.w NR_syscalls, $r9 @@ -317,39 +375,26 @@ system_call: jsr [$r9+sys_call_table] ; actually do the system call addq 3*4, $sp ; pop the mof, srp and regs parameters - move.d $r10, [$sp+LR10] ; save the return value + move.d $r10, [$sp+PT_r10] ; save the return value moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call ;; fall through into ret_from_sys_call to return ret_from_sys_call: - ;; r9 is a parameter - if 1, we came from a syscall, if 0, from an irq + ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq - ;; check if any bottom halves need service - - test.d [irq_stat] ; softirq_pending - bne _handle_softirq - nop + ;; get the current task-struct pointer (see top for defs) -_ret_with_reschedule: - ;; first get the current task-struct pointer (see top for defs) + movs.w -8192, $r0 ; THREAD_SIZE == 8192 + and.d $sp, $r0 - move.d $sp, $r0 - and.d -8192, $r0 ; THREAD_SIZE == 8192 - - ;; see if we want to reschedule into another process - - test.d [$r0+LTASK_NEEDRESCHED] - bne _reschedule + di ; make sure need_resched and sigpending don't change + move.d [$r0+TI_flags],$r1 + and.d _TIF_ALLWORK_MASK, $r1 + bne _syscall_exit_work nop - ;; see if we need to run signal checks (important that r9 is intact here) - - test.d [$r0+LTASK_SIGPENDING] - bne _signal_return - nop - _Rexit: ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h pop $r10 ; frametype @@ -375,63 +420,82 @@ _RBFexit: pop $srp ; subroutine return pointer rbf [$sp+] ; return by popping the CPU status -_tracesys: - ;; this first invocation of syscall_trace _requires_ that - ;; LR10 in the frame contains -ENOSYS (as is set in the beginning - ;; of system_call). - - jsr syscall_trace - - ;; now we should more or less do the same things as in the system_call - ;; but since our argument regs got clobbered during syscall_trace and - ;; because syscall_trace might want to alter them, we need to reload them - ;; from the stack-frame as we use them. - - ;; check for sanity in the requested syscall number - - move.d [$sp+LR9], $r9 - movs.w -ENOSYS, $r10 - cmpu.w NR_syscalls, $r9 - bcc 1f - lslq 2, $r9 ; multiply by 4, in the delay slot - - ;; read the system call vector entry into r9 + ;; We get here after doing a syscall if extra work might need to be done + ;; perform syscall exit tracing if needed - move.d [$r9+sys_call_table], $r9 - - ;; restore r10, r11, r12, r13, mof and srp into the needed registers - - move.d [$sp+LORIG_R10], $r10 ; LR10 is already filled with -ENOSYS. - move.d [$sp+LR11], $r11 - move.d [$sp+LR12], $r12 - move.d [$sp+LR13], $r13 - move [$sp+LMOF], $mof - move [$sp+LSRP], $srp - - ;; as a bonus 7th parameter, we give the location on the stack - ;; of the register structure itself. some syscalls need this. +_syscall_exit_work: + ;; $r0 contains current at this point and irq's are disabled - push $sp + move.d [$r0+TI_flags], $r1 + btstq TIF_SYSCALL_TRACE, $r1 + bpl _work_pending + nop - ;; the fifth and sixth parameters needs to be put on the stack for - ;; the system call to find them + ei - push $srp - push $mof + move.d $r9, $r1 ; preserve r9 + jsr do_syscall_trace + move.d $r1, $r9 + + ba _resume_userspace + nop + +_work_pending: + move.d [$r0+TI_flags], $r1 + btstq TIF_NEED_RESCHED, $r1 + bpl _work_notifysig ; was neither trace nor sched, must be signal/notify + nop + +_work_resched: + move.d $r9, $r1 ; preserve r9 + jsr schedule + move.d $r1, $r9 + di - jsr $r9 ; actually call the system-call - addq 3*4, $sp ; pop the srp, mof and regs parameters + move.d [$r0+TI_flags], $r1 + and.d _TIF_WORK_MASK, $r1; ignore the syscall trace counter + beq _Rexit + nop + btstq TIF_NEED_RESCHED, $r1 + bmi _work_resched ; current->work.need_resched + nop -1: move.d $r10, [$sp+LR10]; save the return value +_work_notifysig: + ;; deal with pending signals and notify-resume requests - ;; second call of syscall_trace, to let it grab the results - - jsr syscall_trace + move.d $r9, $r10 ; do_notify_resume syscall/irq param + moveq 0, $r11 ; oldset param - 0 in this case + move.d $sp, $r12 ; the regs param + move.d $r1, $r13 ; the thread_info_flags parameter + jsr do_notify_resume + + ba _Rexit + nop - moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call - ba ret_from_sys_call + ;; We get here as a sidetrack when we've entered a syscall with the + ;; trace-bit set. We need to call do_syscall_trace and then continue + ;; with the call. + +_syscall_trace_entry: + ;; PT_r10 in the frame contains -ENOSYS as required, at this point + + jsr do_syscall_trace + + ;; now re-enter the syscall code to do the syscall itself + ;; we need to restore $r9 here to contain the wanted syscall, and + ;; the other parameter-bearing registers + + move.d [$sp+PT_r9], $r9 + move.d [$sp+PT_orig_r10], $r10 ; PT_r10 is already filled with -ENOSYS. + move.d [$sp+PT_r11], $r11 + move.d [$sp+PT_r12], $r12 + move.d [$sp+PT_r13], $r13 + move [$sp+PT_mof], $mof + move [$sp+PT_srp], $srp + + ba _syscall_traced nop - + ;; resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct ;; returns old current in r10 @@ -442,26 +506,27 @@ _tracesys: resume: push $srp ; we keep the old/new PC on the stack add.d $r12, $r10 ; r10 = current tasks tss - move $dccr, [$r10+LTHREAD_DCCR] ; save irq enable state + move $dccr, [$r10+THREAD_dccr]; save irq enable state di - move $usp, [$r10+LTHREAD_USP] ; save user-mode stackpointer + move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer ;; See copy_thread for the reason why register R9 is saved. subq 10*4, $sp movem $r9, [$sp] ; save non-scratch registers and R9. - move.d $sp, [$r10+LTHREAD_KSP] ; save the kernel stack pointer for the old task + move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task move.d $sp, $r10 ; return last running task in r10 - and.d -8192, $r10 ; get task ptr from stackpointer + and.d -8192, $r10 ; get thread_info from stackpointer + move.d [$r10+TI_task], $r10 ; get task add.d $r12, $r11 ; find the new tasks tss - move.d [$r11+LTHREAD_KSP], $sp ; switch into the new stackframe by restoring kernel sp + move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp movem [$sp+], $r9 ; restore non-scratch registers and R9. - move [$r11+LTHREAD_USP], $usp ; restore user-mode stackpointer + move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer - move [$r11+LTHREAD_DCCR], $dccr ; restore irq enable status + move [$r11+THREAD_dccr], $dccr ; restore irq enable status jump [$sp+] ; restore PC ;; This is the MMU bus fault handler. @@ -689,7 +754,8 @@ do_sigtrap: movs.w -8192,$r9 ; THREAD_SIZE == 8192 and.d $sp, $r9 - move.d [$r9+LTASK_PID], $r10 ; current->pid as arg1. + move.d [$r9+TI_task], $r10 + move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. moveq 5, $r11 ; SIGTRAP as arg2. jsr sys_kill jump ret_from_intr ; Use the return routine for interrupts. @@ -722,75 +788,9 @@ hw_bp_trigs: hw_bp_trig_ptr: .dword hw_bp_trigs -/* - * This is the mechanism for creating a new kernel thread. - * - * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be free'd until both the parent and the child have exited. - * - * This *can* be done in C with an single-asm-wrapped-in-a-function, but you - * get more or less gross code. The safer you make the asm-constraints, - * the grosser the code, at least with the gcc version in cris-dist-1.13. - */ - -/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ -/* r10 r11 r12 */ - - .text - .global kernel_thread -kernel_thread: - - /* Save ARG for later. */ - move.d $r11, $r13 - - /* r11 is argument 2 to clone, the flags */ - move.d $r12, $r11 - or.w LCLONE_VM, $r11 - or.w LCLONE_UNTRACED, $r11 - - /* Save FN for later. */ - move.d $r10, $r12 - - /* r9 contains syscall number, to sys_clone */ - movu.w __NR_clone, $r9 - - /* r10 is argument 1 to clone */ - clear.d $r10 - - /* call sys_clone, this will fork */ - break 13 - - /* parent or child? child returns 0 here. */ - test.d $r10 - - /* jump if parent */ - bne 1f - nop /* delay slot */ - - /* set argument to function to call */ - move.d $r13, $r10 - - /* call specified function */ - jsr $r12 - /* If we ever return from the function, something bad has happened. */ - - /* r9 is sys_exit syscall number */ - movu.w __NR_exit, $r9 - - /* Give a really bad exit-value */ - moveq -1, $r10 - - /* call sys_exit, killing the child */ - break 13 -1: - ret - nop /* delay slot */ - .section .rodata,"a" sys_call_table: - .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork .long sys_read @@ -842,7 +842,7 @@ sys_call_table: .long sys_geteuid16 .long sys_getegid16 /* 50 */ .long sys_acct - .long sys_umount /* recycled never used phys() */ + .long sys_umount /* recycled never used phys( */ .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl .long sys_fcntl /* 55 */ @@ -913,14 +913,14 @@ sys_call_table: .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* TODO sys_modify_ldt - do something ?*/ + .long sys_ni_syscall /* sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_create_module + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module - .long sys_get_kernel_syms /* 130 */ + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ .long sys_quotactl .long sys_getpgid .long sys_fchdir @@ -945,19 +945,19 @@ sys_call_table: .long sys_mlockall .long sys_munlockall .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ + .long sys_sched_getparam /* 155 */ .long sys_sched_setscheduler .long sys_sched_getscheduler .long sys_sched_yield .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval .long sys_nanosleep .long sys_mremap .long sys_setresuid16 .long sys_getresuid16 /* 165 */ .long sys_ni_syscall /* sys_vm86 */ - .long sys_query_module + .long sys_ni_syscall /* Old sys_query_module */ .long sys_poll .long sys_nfsservctl .long sys_setresgid16 /* 170 */ @@ -970,8 +970,8 @@ sys_call_table: .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend - .long sys_pread /* 180 */ - .long sys_pwrite + .long sys_pread64 /* 180 */ + .long sys_pwrite64 .long sys_chown16 .long sys_getcwd .long sys_capget @@ -1013,11 +1013,54 @@ sys_call_table: .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall /* Reserved for Security */ + .long sys_ni_syscall .long sys_gettid .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr .long sys_tkill - + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_ni_syscall /* sys_set_thread_area */ + .long sys_ni_syscall /* sys_get_thread_area */ + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + /* * NOTE!! This doesn't have to be exact - we just have * to make sure we have _enough_ of the "sys_ni_syscall" diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c new file mode 100644 index 00000000000..2c2cb60c471 --- /dev/null +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -0,0 +1,996 @@ +/* $Id: fasttimer.c,v 1.4 2003/07/04 08:27:41 starvik Exp $ + * linux/arch/cris/kernel/fasttimer.c + * + * Fast timers for ETRAX100/ETRAX100LX + * This may be useful in other OS than Linux so use 2 space indentation... + * + * $Log: fasttimer.c,v $ + * Revision 1.4 2003/07/04 08:27:41 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.3 2002/12/12 08:26:32 starvik + * Don't use C-comments inside CVS comments + * + * Revision 1.2 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ + * + * Revision 1.1 2002/11/18 07:58:06 starvik + * Fast timers (from Linux 2.4) + * + * Revision 1.5 2002/10/15 06:21:39 starvik + * Added call to init_waitqueue_head + * + * Revision 1.4 2002/05/28 17:47:59 johana + * Added del_fast_timer() + * + * Revision 1.3 2002/05/28 16:16:07 johana + * Handle empty fast_timer_list + * + * Revision 1.2 2002/05/27 15:38:42 johana + * Made it compile without warnings on Linux 2.4. + * (includes, wait_queue, PROC_FS and snprintf) + * + * Revision 1.1 2002/05/27 15:32:25 johana + * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. + * + * Revision 1.8 2001/11/27 13:50:40 pkj + * Disable interrupts while stopping the timer and while modifying the + * list of active timers in timer1_handler() as it may be interrupted + * by other interrupts (e.g., the serial interrupt) which may add fast + * timers. + * + * Revision 1.7 2001/11/22 11:50:32 pkj + * * Only store information about the last 16 timers. + * * proc_fasttimer_read() now uses an allocated buffer, since it + * requires more space than just a page even for only writing the + * last 16 timers. The buffer is only allocated on request, so + * unless /proc/fasttimer is read, it is never allocated. + * * Renamed fast_timer_started to fast_timers_started to match + * fast_timers_added and fast_timers_expired. + * * Some clean-up. + * + * Revision 1.6 2000/12/13 14:02:08 johana + * Removed volatile for fast_timer_list + * + * Revision 1.5 2000/12/13 13:55:35 johana + * Added DEBUG_LOG, added som cli() and cleanup + * + * Revision 1.4 2000/12/05 13:48:50 johana + * Added range check when writing proc file, modified timer int handling + * + * Revision 1.3 2000/11/23 10:10:20 johana + * More debug/logging possibilities. + * Moved GET_JIFFIES_USEC() to timex.h and time.c + * + * Revision 1.2 2000/11/01 13:41:04 johana + * Clean up and bugfixes. + * Created new do_gettimeofday_fast() that gets a timeval struct + * with time based on jiffies and *R_TIMER0_DATA, uses a table + * for fast conversion of timer value to microseconds. + * (Much faster the standard do_gettimeofday() and we don't really + * wan't to use the true time - we wan't the "uptime" so timers don't screw up + * when we change the time. + * TODO: Add efficient support for continuous timers as well. + * + * Revision 1.1 2000/10/26 15:49:16 johana + * Added fasttimer, highresolution timers. + * + * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +#define DEBUG_LOG_INCLUDED +#define FAST_TIMER_LOG +//#define FAST_TIMER_TEST + +#define FAST_TIMER_SANITY_CHECKS + +#ifdef FAST_TIMER_SANITY_CHECKS +#define SANITYCHECK(x) x +static int sanity_failed = 0; +#else +#define SANITYCHECK(x) +#endif + +#define D1(x) +#define D2(x) +#define DP(x) + +#define __INLINE__ inline + +static int fast_timer_running = 0; +static int fast_timers_added = 0; +static int fast_timers_started = 0; +static int fast_timers_expired = 0; +static int fast_timers_deleted = 0; +static int fast_timer_is_init = 0; +static int fast_timer_ints = 0; + +static struct fast_timer *fast_timer_list = NULL; + +#ifdef DEBUG_LOG_INCLUDED +#define DEBUG_LOG_MAX 128 +static const char * debug_log_string[DEBUG_LOG_MAX]; +static unsigned long debug_log_value[DEBUG_LOG_MAX]; +static int debug_log_cnt = 0; +static int debug_log_cnt_wrapped = 0; + +#define DEBUG_LOG(string, value) \ +{ \ + unsigned long log_flags; \ + save_flags(log_flags); \ + cli(); \ + debug_log_string[debug_log_cnt] = (string); \ + debug_log_value[debug_log_cnt] = (unsigned long)(value); \ + if (++debug_log_cnt >= DEBUG_LOG_MAX) \ + { \ + debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ + debug_log_cnt_wrapped = 1; \ + } \ + restore_flags(log_flags); \ +} +#else +#define DEBUG_LOG(string, value) +#endif + + +/* The frequencies for index = clkselx number in R_TIMER_CTRL */ +#define NUM_TIMER_FREQ 15 +#define MAX_USABLE_TIMER_FREQ 7 +#define MAX_DELAY_US 853333L +const unsigned long timer_freq_100[NUM_TIMER_FREQ] = +{ + 3, /* 0 3333 - 853333 us */ + 6, /* 1 1666 - 426666 us */ + 12, /* 2 833 - 213333 us */ + 24, /* 3 416 - 106666 us */ + 48, /* 4 208 - 53333 us */ + 96, /* 5 104 - 26666 us */ + 192, /* 6 52 - 13333 us */ + 384, /* 7 26 - 6666 us */ + 576, + 1152, + 2304, + 4608, + 9216, + 18432, + 62500, + /* 15 = cascade */ +}; +#define NUM_TIMER_STATS 16 +#ifdef FAST_TIMER_LOG +struct fast_timer timer_added_log[NUM_TIMER_STATS]; +struct fast_timer timer_started_log[NUM_TIMER_STATS]; +struct fast_timer timer_expired_log[NUM_TIMER_STATS]; +#endif + +int timer_div_settings[NUM_TIMER_STATS]; +int timer_freq_settings[NUM_TIMER_STATS]; +int timer_delay_settings[NUM_TIMER_STATS]; + +/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ +void __INLINE__ do_gettimeofday_fast(struct timeval *tv) +{ + unsigned long sec = jiffies; + unsigned long usec = GET_JIFFIES_USEC(); + + usec += (sec % HZ) * (1000000 / HZ); + sec = sec / HZ; + + if (usec > 1000000) + { + usec -= 1000000; + sec++; + } + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) +{ + if (t0->tv_sec < t1->tv_sec) + { + return -1; + } + else if (t0->tv_sec > t1->tv_sec) + { + return 1; + } + if (t0->tv_usec < t1->tv_usec) + { + return -1; + } + else if (t0->tv_usec > t1->tv_usec) + { + return 1; + } + return 0; +} + +void __INLINE__ start_timer1(unsigned long delay_us) +{ + int freq_index = 0; /* This is the lowest resolution */ + unsigned long upper_limit = MAX_DELAY_US; + + unsigned long div; + /* Start/Restart the timer to the new shorter value */ + /* t = 1/freq = 1/19200 = 53us + * T=div*t, div = T/t = delay_us*freq/1000000 + */ +#if 1 /* Adaptive timer settings */ + while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ) + { + freq_index++; + upper_limit >>= 1; /* Divide by 2 using shift */ + } + if (freq_index > 0) + { + freq_index--; + } +#else + freq_index = 6; +#endif + div = delay_us * timer_freq_100[freq_index]/10000; + if (div < 2) + { + /* Maybe increase timer freq? */ + div = 2; + } + if (div > 255) + { + div = 0; /* This means 256, the max the timer takes */ + /* If a longer timeout than the timer can handle is used, + * then we must restart it when it goes off. + */ + } + + timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div; + timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; + timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; + + D1(printk("start_timer1 : %d us freq: %i div: %i\n", + delay_us, freq_index, div)); + /* Clear timer1 irq */ + *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); + + /* Set timer values */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & + ~IO_MASK(R_TIMER_CTRL, timerdiv1) & + ~IO_MASK(R_TIMER_CTRL, tm1) & + ~IO_MASK(R_TIMER_CTRL, clksel1)) | + IO_FIELD(R_TIMER_CTRL, timerdiv1, div) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | + IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */ + + /* Ack interrupt */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | + IO_STATE(R_TIMER_CTRL, i1, clr); + + /* Start timer */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | + IO_STATE(R_TIMER_CTRL, tm1, run); + + /* Enable timer1 irq */ + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); + fast_timers_started++; + fast_timer_running = 1; +} + +/* In version 1.4 this function takes 27 - 50 us */ +void start_one_shot_timer(struct fast_timer *t, + fast_timer_function_type *function, + unsigned long data, + unsigned long delay_us, + const char *name) +{ + unsigned long flags; + struct fast_timer *tmp; + + D1(printk("sft %s %d us\n", name, delay_us)); + + save_flags(flags); + cli(); + + do_gettimeofday_fast(&t->tv_set); + tmp = fast_timer_list; + + SANITYCHECK({ /* Check so this is not in the list already... */ + while (tmp != NULL) + { + if (tmp == t) + { + printk("timer name: %s data: 0x%08lX already in list!\n", name, data); + sanity_failed++; + return; + } + else + { + tmp = tmp->next; + } + } + tmp = fast_timer_list; + }); + + t->delay_us = delay_us; + t->function = function; + t->data = data; + t->name = name; + + t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; + t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; + if (t->tv_expires.tv_usec > 1000000) + { + t->tv_expires.tv_usec -= 1000000; + t->tv_expires.tv_sec++; + } +#ifdef FAST_TIMER_LOG + timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; +#endif + fast_timers_added++; + + /* Check if this should timeout before anything else */ + if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) + { + /* Put first in list and modify the timer value */ + t->prev = NULL; + t->next = fast_timer_list; + if (fast_timer_list) + { + fast_timer_list->prev = t; + } + fast_timer_list = t; +#ifdef FAST_TIMER_LOG + timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; +#endif + start_timer1(delay_us); + } else { + /* Put in correct place in list */ + while (tmp->next && + timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) + { + tmp = tmp->next; + } + /* Insert t after tmp */ + t->prev = tmp; + t->next = tmp->next; + if (tmp->next) + { + tmp->next->prev = t; + } + tmp->next = t; + } + + D2(printk("start_one_shot_timer: %d us done\n", delay_us)); + + restore_flags(flags); +} /* start_one_shot_timer */ + +static inline int fast_timer_pending (const struct fast_timer * t) +{ + return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list); +} + +static inline int detach_fast_timer (struct fast_timer *t) +{ + struct fast_timer *next, *prev; + if (!fast_timer_pending(t)) + return 0; + next = t->next; + prev = t->prev; + if (next) + next->prev = prev; + if (prev) + prev->next = next; + else + fast_timer_list = next; + fast_timers_deleted++; + return 1; +} + +int del_fast_timer(struct fast_timer * t) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = detach_fast_timer(t); + t->next = t->prev = NULL; + restore_flags(flags); + return ret; +} /* del_fast_timer */ + + +/* Interrupt routines or functions called in interrupt context */ + +/* Timer 1 interrupt handler */ + +static irqreturn_t +timer1_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct fast_timer *t; + unsigned long flags; + + save_flags(flags); + cli(); + + /* Clear timer1 irq */ + *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); + + /* First stop timer, then ack interrupt */ + /* Stop timer */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld); + + /* Ack interrupt */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); + + fast_timer_running = 0; + fast_timer_ints++; + + restore_flags(flags); + + t = fast_timer_list; + while (t) + { + struct timeval tv; + + /* Has it really expired? */ + do_gettimeofday_fast(&tv); + D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); + + if (timeval_cmp(&t->tv_expires, &tv) <= 0) + { + /* Yes it has expired */ +#ifdef FAST_TIMER_LOG + timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; +#endif + fast_timers_expired++; + + /* Remove this timer before call, since it may reuse the timer */ + save_flags(flags); + cli(); + if (t->prev) + { + t->prev->next = t->next; + } + else + { + fast_timer_list = t->next; + } + if (t->next) + { + t->next->prev = t->prev; + } + t->prev = NULL; + t->next = NULL; + restore_flags(flags); + + if (t->function != NULL) + { + t->function(t->data); + } + else + { + DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); + } + } + else + { + /* Timer is to early, let's set it again using the normal routines */ + D1(printk(".\n")); + } + + save_flags(flags); + cli(); + if ((t = fast_timer_list) != NULL) + { + /* Start next timer.. */ + long us; + struct timeval tv; + + do_gettimeofday_fast(&tv); + us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + + t->tv_expires.tv_usec - tv.tv_usec); + if (us > 0) + { + if (!fast_timer_running) + { +#ifdef FAST_TIMER_LOG + timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; +#endif + start_timer1(us); + } + restore_flags(flags); + break; + } + else + { + /* Timer already expired, let's handle it better late than never. + * The normal loop handles it + */ + D1(printk("e! %d\n", us)); + } + } + restore_flags(flags); + } + + if (!t) + { + D1(printk("t1 stop!\n")); + } + + return IRQ_HANDLED; +} + +static void wake_up_func(unsigned long data) +{ +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; +#else + struct wait_queue **sleep_wait_p = (struct wait_queue **)data; +#endif + wake_up(sleep_wait_p); +} + + +/* Useful API */ + +void schedule_usleep(unsigned long us) +{ + struct fast_timer t; +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t sleep_wait; + init_waitqueue_head(&sleep_wait); + { + DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue *sleep_wait = NULL; + struct wait_queue wait = { current, NULL }; +#endif + + D1(printk("schedule_usleep(%d)\n", us)); + add_wait_queue(&sleep_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, + "usleep"); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&sleep_wait, &wait); + D1(printk("done schedule_usleep(%d)\n", us)); +#ifdef DECLARE_WAITQUEUE + } +#endif +} + +#ifdef CONFIG_PROC_FS +static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + ,int *eof, void *data_unused +#else + ,int unused +#endif + ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) +static struct proc_dir_entry *fasttimer_proc_entry; +#else +static struct proc_dir_entry fasttimer_proc_entry = +{ + 0, 9, "fasttimer", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, NULL /* ops -- default to array */, + &proc_fasttimer_read /* get_info */, +}; +#endif +#endif /* CONFIG_PROC_FS */ + +#ifdef CONFIG_PROC_FS + +/* This value is very much based on testing */ +#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) + +static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + ,int *eof, void *data_unused +#else + ,int unused +#endif + ) +{ + unsigned long flags; + int i = 0; + int num_to_show; + struct timeval tv; + struct fast_timer *t, *nextt; + static char *bigbuf = NULL; + static unsigned long used; + + if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) + { + used = 0; + bigbuf[0] = '\0'; + return 0; + } + + if (!offset || !used) + { + do_gettimeofday_fast(&tv); + + used = 0; + used += sprintf(bigbuf + used, "Fast timers added: %i\n", + fast_timers_added); + used += sprintf(bigbuf + used, "Fast timers started: %i\n", + fast_timers_started); + used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n", + fast_timer_ints); + used += sprintf(bigbuf + used, "Fast timers expired: %i\n", + fast_timers_expired); + used += sprintf(bigbuf + used, "Fast timers deleted: %i\n", + fast_timers_deleted); + used += sprintf(bigbuf + used, "Fast timer running: %s\n", + fast_timer_running ? "yes" : "no"); + used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", + (unsigned long)tv.tv_sec, + (unsigned long)tv.tv_usec); +#ifdef FAST_TIMER_SANITY_CHECKS + used += sprintf(bigbuf + used, "Sanity failed: %i\n", + sanity_failed); +#endif + used += sprintf(bigbuf + used, "\n"); + +#ifdef DEBUG_LOG_INCLUDED + { + int end_i = debug_log_cnt; + i = 0; + + if (debug_log_cnt_wrapped) + { + i = debug_log_cnt; + } + + while ((i != end_i || (debug_log_cnt_wrapped && !used)) && + used+100 < BIG_BUF_SIZE) + { + used += sprintf(bigbuf + used, debug_log_string[i], + debug_log_value[i]); + i = (i+1) % DEBUG_LOG_MAX; + } + } + used += sprintf(bigbuf + used, "\n"); +#endif + + num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++) + { + int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; + +#if 1 //ndef FAST_TIMER_LOG + used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i" + "\n", + timer_div_settings[cur], + timer_freq_settings[cur], + timer_delay_settings[cur] + ); +#endif +#ifdef FAST_TIMER_LOG + t = &timer_started_log[cur]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); +#endif + } + used += sprintf(bigbuf + used, "\n"); + +#ifdef FAST_TIMER_LOG + num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) + { + t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); + } + used += sprintf(bigbuf + used, "\n"); + + num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) + { + t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); + } + used += sprintf(bigbuf + used, "\n"); +#endif + + used += sprintf(bigbuf + used, "Active timers:\n"); + save_flags(flags); + cli(); + t = fast_timer_list; + while (t != NULL && (used+100 < BIG_BUF_SIZE)) + { + nextt = t->next; + restore_flags(flags); + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" +/* " func: 0x%08lX" */ + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data +/* , t->function */ + ); + cli(); + if (t->next != nextt) + { + printk("timer removed!\n"); + } + t = nextt; + } + restore_flags(flags); + } + + if (used - offset < len) + { + len = used - offset; + } + + memcpy(buf, bigbuf + offset, len); + *start = buf; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + *eof = 1; +#endif + + return len; +} +#endif /* PROC_FS */ + +#ifdef FAST_TIMER_TEST +static volatile unsigned long i = 0; +static volatile int num_test_timeout = 0; +static struct fast_timer tr[10]; +static int exp_num[10]; + +static struct timeval tv_exp[100]; + +static void test_timeout(unsigned long data) +{ + do_gettimeofday_fast(&tv_exp[data]); + exp_num[data] = num_test_timeout; + + num_test_timeout++; +} + +static void test_timeout1(unsigned long data) +{ + do_gettimeofday_fast(&tv_exp[data]); + exp_num[data] = num_test_timeout; + if (data < 7) + { + start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1"); + i++; + } + num_test_timeout++; +} + +DP( +static char buf0[2000]; +static char buf1[2000]; +static char buf2[2000]; +static char buf3[2000]; +static char buf4[2000]; +); + +static char buf5[6000]; +static int j_u[1000]; + +static void fast_timer_test(void) +{ + int prev_num; + int j; + + struct timeval tv, tv0, tv1, tv2; + + printk("fast_timer_test() start\n"); + do_gettimeofday_fast(&tv); + + for (j = 0; j < 1000; j++) + { + j_u[j] = GET_JIFFIES_USEC(); + } + for (j = 0; j < 100; j++) + { + do_gettimeofday_fast(&tv_exp[j]); + } + printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); + + for (j = 0; j < 1000; j++) + { + printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); + j += 4; + } + for (j = 0; j < 100; j++) + { + printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", + tv_exp[j].tv_sec,tv_exp[j].tv_usec, + tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, + tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, + tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, + tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); + j += 4; + } + do_gettimeofday_fast(&tv0); + start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0"); + DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1"); + DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2"); + DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3"); + DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx"); + DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0)); + i++; + do_gettimeofday_fast(&tv1); + + proc_fasttimer_read(buf5, NULL, 0, 0, 0); + + prev_num = num_test_timeout; + while (num_test_timeout < i) + { + if (num_test_timeout != prev_num) + { + prev_num = num_test_timeout; + } + } + do_gettimeofday_fast(&tv2); + printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); + printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); + printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); + DP(printk("buf0:\n"); + printk(buf0); + printk("buf1:\n"); + printk(buf1); + printk("buf2:\n"); + printk(buf2); + printk("buf3:\n"); + printk(buf3); + printk("buf4:\n"); + printk(buf4); + ); + printk("buf5:\n"); + printk(buf5); + + printk("timers set:\n"); + for(j = 0; jname, + t->tv_set.tv_sec, + t->tv_set.tv_usec, + t->tv_expires.tv_sec, + t->tv_expires.tv_usec, + t->data, + t->function + ); + + printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", + t->delay_us, + tv_exp[j].tv_sec, + tv_exp[j].tv_usec, + exp_num[j], + (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); + } + proc_fasttimer_read(buf5, NULL, 0, 0, 0); + printk("buf5 after all done:\n"); + printk(buf5); + printk("fast_timer_test() done\n"); +} +#endif + + +void fast_timer_init(void) +{ + /* For some reason, request_irq() hangs when called froom time_init() */ + if (!fast_timer_is_init) + { +#if 0 && defined(FAST_TIMER_TEST) + int i; +#endif + + printk("fast_timer_init()\n"); + +#if 0 && defined(FAST_TIMER_TEST) + for (i = 0; i <= TIMER0_DIV; i++) + { + /* We must be careful not to get overflow... */ + printk("%3i %6u\n", i, timer0_value_us[i]); + } +#endif +#ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) + fasttimer_proc_entry->read_proc = proc_fasttimer_read; +#else + proc_register_dynamic(&proc_root, &fasttimer_proc_entry); +#endif +#endif /* PROC_FS */ + if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, + "fast timer int", NULL)) + { + printk("err: timer1 irq\n"); + } + fast_timer_is_init = 1; +#ifdef FAST_TIMER_TEST + printk("do test\n"); + fast_timer_test(); +#endif + } +} diff --git a/arch/cris/kernel/head.S b/arch/cris/arch-v10/kernel/head.S similarity index 97% rename from arch/cris/kernel/head.S rename to arch/cris/arch-v10/kernel/head.S index bbd4eb3dd93..8192cd758b4 100644 --- a/arch/cris/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.2 2001/12/18 13:35:19 bjornw Exp $ +/* $Id: head.S,v 1.6 2003/04/28 05:31:46 starvik Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,19 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.6 2003/04/28 05:31:46 starvik + * Added section attributes + * + * Revision 1.5 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c + * + * Revision 1.4 2002/11/07 09:00:44 starvik + * Names changed for init sections + * init_task_union -> init_thread_union + * + * Revision 1.3 2002/02/05 15:38:23 bjornw + * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it... + * * Revision 1.2 2001/12/18 13:35:19 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -161,7 +174,7 @@ #define ASSEMBLER_MACROS_ONLY /* The IO_* macros use the ## token concatenation operator, so -traditional must not be used when assembling this file. */ -#include +#include #define CRAMFS_MAGIC 0x28cd3d45 #define RAM_INIT_MAGIC 0x56902387 @@ -294,7 +307,7 @@ ;; ;; arch/etrax100/etrax100.ld sets some symbols that define the start ;; and end of each segment. - + ;; Check if we start from DRAM or FLASH by testing PC move.d $pc,$r0 @@ -311,7 +324,7 @@ _inflash0: ;; Put this in a suitable section where we can reclaim storage ;; after init. - .section ".text.init" + .section ".init.text", "ax" _inflash: #ifdef CONFIG_ETRAX_ETHERNET ;; Start MII clock to make sure it is running when tranceiver is reset @@ -379,7 +392,7 @@ _dram_init_finished: _inram: ;; Move the ROM fs to after BSS end. This assumes that the cramfs ;; second longword contains the length of the cramfs - + moveq 0, $r0 move.d $r0, [romfs_length] ; default if there is no cramfs @@ -411,19 +424,20 @@ _inram: moveq 1, $r0 move.d $r0, [romfs_in_flash] - + jump _start_it ; enter code, cached this time _no_romfs_in_flash: + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does ;; not need this mechanism anyway) - + move.d __vmlinux_end, $r0; the image will be after the vmlinux end address move.d [$r0], $r1 ; cramfs assumes same endian on host/target cmp.d CRAMFS_MAGIC, $r1; magic value in cramfs superblock - bne 1f + bne 2f nop ;; Ok. What is its size ? @@ -453,7 +467,8 @@ _no_romfs_in_flash: subq 1, $r2 bne 1b nop - + +2: ;; Dont worry that the BSS is tainted. It will be cleared later. moveq 0, $r0 @@ -462,14 +477,15 @@ _no_romfs_in_flash: jump _start_it ; better skip the additional cramfs check below _start_it: + ;; the kernel stack is overlayed with the task structure for each ;; task. thus the initial kernel stack is in the same page as the ;; init_task (but starts in the top of the page, size 8192) - move.d init_task_union + 8192, $sp + move.d init_thread_union + 8192, $sp move.d ibr_start,$r0 ; this symbol is set by the linker script move $r0,$ibr move.d $r0,[etrax_irv] ; set the interrupt base register and pointer - + ;; Clear BSS region, from _bss_start to _end move.d __bss_start, $r0 @@ -839,5 +855,5 @@ swapper_pg_dir = 0x60002000 swapper_pg_dir = 0xc0002000 #endif - .section ".data.init" + .section ".init.data", "aw" #include "../lib/hw_settings.S" diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c new file mode 100644 index 00000000000..c5e6348aba1 --- /dev/null +++ b/arch/cris/arch-v10/kernel/irq.c @@ -0,0 +1,219 @@ +/* $Id: irq.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ + * + * linux/arch/cris/kernel/irq.c + * + * Copyright (c) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * This file contains the interrupt vectors and some + * helper functions + * + */ + +#include +#include +#include +#include + +irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ + +/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is + * global just so that the kernel gdb can use it. + */ + +void +set_int_vector(int n, irqvectptr addr, irqvectptr saddr) +{ + /* remember the shortcut entry point, after the prologue */ + + irq_shortcuts[n] = saddr; + + etrax_irv->v[n + 0x20] = (irqvectptr)addr; +} + +/* the breakpoint vector is obviously not made just like the normal irq handlers + * but needs to contain _code_ to jump to addr. + * + * the BREAK n instruction jumps to IBR + n * 8 + */ + +void +set_break_vector(int n, irqvectptr addr) +{ + unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; + unsigned long *jaddr = (unsigned long *)(jinstr + 1); + + /* if you don't know what this does, do not touch it! */ + + *jinstr = 0x0d3f; + *jaddr = (unsigned long)addr; + + /* 00000026 3f0d82000000 jump 0x82 */ +} + +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that do all + * the operations that are needed. They are also written to be fast - and to + * disable interrupts as little as humanly possible. + * + */ + +/* IRQ0 and 1 are special traps */ +void hwbreakpoint(void); +void IRQ1_interrupt(void); +BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ +BUILD_IRQ(3, 0x08) +BUILD_IRQ(4, 0x10) +BUILD_IRQ(5, 0x20) +BUILD_IRQ(6, 0x40) +BUILD_IRQ(7, 0x80) +BUILD_IRQ(8, 0x100) +BUILD_IRQ(9, 0x200) +BUILD_IRQ(10, 0x400) +BUILD_IRQ(11, 0x800) +BUILD_IRQ(12, 0x1000) +BUILD_IRQ(13, 0x2000) +void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ +void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ +BUILD_IRQ(16, 0x10000) +BUILD_IRQ(17, 0x20000) +BUILD_IRQ(18, 0x40000) +BUILD_IRQ(19, 0x80000) +BUILD_IRQ(20, 0x100000) +BUILD_IRQ(21, 0x200000) +BUILD_IRQ(22, 0x400000) +BUILD_IRQ(23, 0x800000) +BUILD_IRQ(24, 0x1000000) +BUILD_IRQ(25, 0x2000000) +/* IRQ 26-30 are reserved */ +BUILD_IRQ(31, 0x80000000) + +/* + * Pointers to the low-level handlers + */ + +static void (*interrupt[NR_IRQS])(void) = { + NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, + IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, + IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, + IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, + IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, + IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, + IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + IRQ31_interrupt +}; + +static void (*sinterrupt[NR_IRQS])(void) = { + NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt, + sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt, + sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt, + sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, + sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, + sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, + sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + sIRQ31_interrupt +}; + +static void (*bad_interrupt[NR_IRQS])(void) = { + NULL, NULL, + NULL, bad_IRQ3_interrupt, + bad_IRQ4_interrupt, bad_IRQ5_interrupt, + bad_IRQ6_interrupt, bad_IRQ7_interrupt, + bad_IRQ8_interrupt, bad_IRQ9_interrupt, + bad_IRQ10_interrupt, bad_IRQ11_interrupt, + bad_IRQ12_interrupt, bad_IRQ13_interrupt, + NULL, NULL, + bad_IRQ16_interrupt, bad_IRQ17_interrupt, + bad_IRQ18_interrupt, bad_IRQ19_interrupt, + bad_IRQ20_interrupt, bad_IRQ21_interrupt, + bad_IRQ22_interrupt, bad_IRQ23_interrupt, + bad_IRQ24_interrupt, bad_IRQ25_interrupt, + NULL, NULL, NULL, NULL, NULL, + bad_IRQ31_interrupt +}; + +void arch_setup_irq(int irq) +{ + set_int_vector(irq, interrupt[irq], sinterrupt[irq]); +} + +void arch_free_irq(int irq) +{ + set_int_vector(irq, bad_interrupt[irq], 0); +} + +void weird_irq(void); +void system_call(void); /* from entry.S */ +void do_sigtrap(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from entry.S */ + +/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and + setting the irq vector table to point to bad_interrupt ptrs. +*/ + +void __init +init_IRQ(void) +{ + int i; + + /* clear all interrupt masks */ + +#ifndef CONFIG_SVINTO_SIM + *R_IRQ_MASK0_CLR = 0xffffffff; + *R_IRQ_MASK1_CLR = 0xffffffff; + *R_IRQ_MASK2_CLR = 0xffffffff; +#endif + + *R_VECT_MASK_CLR = 0xffffffff; + + /* clear the shortcut entry points */ + + for(i = 0; i < NR_IRQS; i++) + irq_shortcuts[i] = NULL; + + for (i = 0; i < 256; i++) + etrax_irv->v[i] = weird_irq; + + /* the entries in the break vector contain actual code to be + executed by the associated break handler, rather than just a jump + address. therefore we need to setup a default breakpoint handler + for all breakpoints */ + + for (i = 0; i < 16; i++) + set_break_vector(i, do_sigtrap); + + /* set all etrax irq's to the bad handlers */ + for (i = 2; i < NR_IRQS; i++) + set_int_vector(i, bad_interrupt[i], 0); + + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ + + set_int_vector(15, multiple_interrupt, 0); + + /* 0 and 1 which are special breakpoint/NMI traps */ + + set_int_vector(0, hwbreakpoint, 0); + set_int_vector(1, IRQ1_interrupt, 0); + + /* and irq 14 which is the mmu bus fault handler */ + + set_int_vector(14, mmu_bus_fault, 0); + + /* setup the system-call trap, which is reached by BREAK 13 */ + + set_break_vector(13, system_call); + + /* setup a breakpoint handler for debugging used for both user and + kernel mode debugging (which is why it is not inside an ifdef + CONFIG_ETRAX_KGDB) */ + set_break_vector(8, gdb_handle_breakpoint); + +#ifdef CONFIG_ETRAX_KGDB + /* setup kgdb if its enabled, and break into the debugger */ + kgdb_init(); + breakpoint(); +#endif +} diff --git a/arch/cris/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c similarity index 99% rename from arch/cris/kernel/kgdb.c rename to arch/cris/arch-v10/kernel/kgdb.c index 793c77575c8..4e5d50d28de 100644 --- a/arch/cris/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -18,8 +18,18 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.4 2003/04/09 05:20:44 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.3 2003/01/21 19:11:08 starvik +*! Modified include path for new dir layout +*! +*! Revision 1.2 2002/11/19 14:35:24 starvik +*! Changes from linux 2.4 +*! Changed struct initializer syntax to the currently prefered notation +*! +*! Revision 1.1 2001/12/17 13:59:27 bjornw +*! Initial revision *! *! Revision 1.6 2001/10/09 13:10:03 matsfg *! Added $ on registers and removed some underscores @@ -58,7 +68,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -216,7 +226,7 @@ #include #include -#include +#include #include static int kgdb_started = 0; @@ -1067,7 +1077,7 @@ handle_exception (int sigval) int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); int status; #ifdef PROCESS_SUPPORT - if (current_thread_g =! executing_task) + if (current_thread_g != executing_task) status = write_stack_register (current_thread_g, regno, suffix+1); else #endif diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c new file mode 100644 index 00000000000..62e3a4fbf33 --- /dev/null +++ b/arch/cris/arch-v10/kernel/process.c @@ -0,0 +1,252 @@ +/* $Id: process.c,v 1.3 2003/07/04 08:27:41 starvik Exp $ + * + * linux/arch/cris/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * Mikael Starvik (starvik@axis.com) + * + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_ETRAX_GPIO +void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ +#endif + +/* + * We use this if we don't have any better + * idle routine.. + */ +void default_idle(void) +{ +#ifdef CONFIG_ETRAX_GPIO + etrax_gpio_wake_up_check(); +#endif +} + +/* if the watchdog is enabled, we can simply disable interrupts and go + * into an eternal loop, and the watchdog will reset the CPU after 0.1s + * if on the other hand the watchdog wasn't enabled, we just enable it and wait + */ + +void hard_reset_now (void) +{ + /* + * Don't declare this variable elsewhere. We don't want any other + * code to know about it than the watchdog handler in entry.S and + * this code, implementing hard reset through the watchdog. + */ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + extern int cause_of_death; +#endif + + printk("*** HARD RESET ***\n"); + local_irq_disable(); + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + cause_of_death = 0xbedead; +#else + /* Since we dont plan to keep on reseting the watchdog, + the key can be arbitrary hence three */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | + IO_STATE(R_WATCHDOG, enable, start); +#endif + + while(1) /* waiting for RETRIBUTION! */ ; +} + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *t) +{ + return (unsigned long)user_regs(t->thread_info)->irp; +} + +static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) +{ + fn(arg); + do_exit(-1); /* Should never be called, return bad exit value */ +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + /* Don't use r10 since that is set to 0 in copy_thread */ + regs.r11 = (unsigned long)fn; + regs.r12 = (unsigned long)arg; + regs.irp = (unsigned long)kernel_thread_helper; + + /* Ok, create the new process.. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +} + +/* setup the child's kernel stack with a pt_regs and switch_stack on it. + * it will be un-nested during _resume and _ret_from_sys_call when the + * new thread is scheduled. + * + * also setup the thread switching structure which is used to keep + * thread-specific data during _resumes. + * + */ +asmlinkage void ret_from_fork(void); + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs * childregs; + struct switch_stack *swstack; + + /* put the pt_regs structure at the end of the new kernel stack page and fix it up + * remember that the task_struct doubles as the kernel stack for the task + */ + + childregs = user_regs(p->thread_info); + + *childregs = *regs; /* struct copy of pt_regs */ + + p->set_child_tid = p->clear_child_tid = NULL; + + childregs->r10 = 0; /* child returns 0 after a fork/clone */ + + /* put the switch stack right below the pt_regs */ + + swstack = ((struct switch_stack *)childregs) - 1; + + swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ + + /* we want to return into ret_from_sys_call after the _resume */ + + swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */ + + /* fix the user-mode stackpointer */ + + p->thread.usp = usp; + + /* and the kernel-mode one */ + + p->thread.ksp = (unsigned long) swstack; + +#ifdef DEBUG + printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); + show_registers(childregs); +#endif + + return 0; +} + +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) +{ + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +/* if newusp is 0, we just grab the old usp */ +/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, + int* parent_tid, int* child_tid, long mof, long srp, + struct pt_regs *regs) +{ + if (!newusp) + newusp = rdusp(); + return do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0, parent_tid, child_tid); +} + +/* vfork is a system call in i386 because of register-pressure - maybe + * we can remove it and handle it in libc but we put it here until then. + */ + +asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char *fname, char **argv, char **envp, + long r13, long mof, long srp, + struct pt_regs *regs) +{ + int error; + char *filename; + + filename = getname(fname); + error = PTR_ERR(filename); + + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); + out: + return error; +} + +/* + * These bracket the sleeping functions.. + */ + +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ +#if 0 + /* YURGH. TODO. */ + + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)p; + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > 8184+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); +#endif + return 0; +} +#undef last_sched +#undef first_sched diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c similarity index 53% copy from arch/cris/kernel/ptrace.c copy to arch/cris/arch-v10/kernel/ptrace.c index c8a066c4ee4..c83eba5d6d0 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -1,36 +1,5 @@ /* - * linux/arch/cris/kernel/ptrace.c - * - * Parts taken from the m68k port. - * - * Copyright (c) 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen - * - * $Log: ptrace.c,v $ - * Revision 1.2 2001/12/18 13:35:20 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.8 2001/11/12 18:26:21 pkj - * Fixed compiler warnings. - * - * Revision 1.7 2001/09/26 11:53:49 bjornw - * PTRACE_DETACH works more simple in 2.4.10 - * - * Revision 1.6 2001/07/25 16:08:47 bjornw - * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7 - * - * Revision 1.5 2001/03/26 14:24:28 orjanf - * * Changed loop condition. - * * Added comment documenting non-standard ptrace behaviour. - * - * Revision 1.4 2001/03/20 19:44:41 bjornw - * Use the user_regs macro instead of thread.esp0 - * - * Revision 1.3 2000/12/18 23:45:25 bjornw - * Linux/CRIS first version - * - * + * Copyright (C) 2000-2003, Axis Communications AB. */ #include @@ -48,122 +17,105 @@ #include #include -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. +/* + * Determines which bits in DCCR the user has access to. + * 1 = access, 0 = no access. */ - -/* determines which bits in DCCR the user has access to. */ -/* 1 = access 0 = no access */ #define DCCR_MASK 0x0000001f /* XNZVC */ -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, unsigned int regno) -{ - /* USP is a special case, it's not in the pt_regs struct but - * in the tasks thread struct - */ - - if (regno == PT_USP) - return task->thread.usp; - else if (regno < PT_MAX) - return ((unsigned long *)user_regs(task))[regno]; - else - return 0; -} +extern inline long get_reg(struct task_struct *, unsigned int); +extern inline long put_reg(struct task_struct *, unsigned int, unsigned long); /* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, unsigned int regno, - unsigned long data) -{ - if (regno == PT_USP) - task->thread.usp = data; - else if (regno < PT_MAX) - ((unsigned long *)user_regs(task))[regno] = data; - else - return -1; - return 0; -} - -/* - * Called by kernel/ptrace.c when detaching.. + * Called by kernel/ptrace.c when detaching. * * Make sure the single step bit is not set. */ -void ptrace_disable(struct task_struct *child) +void +ptrace_disable(struct task_struct *child) { /* Todo - pending singlesteps? */ } -/* Note that this implementation of ptrace behaves differently from vanilla +/* + * Note that this implementation of ptrace behaves differently from vanilla * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not * ignored. Instead, the data variable is expected to point at a location * (in user space) where the result of the ptrace call is written (instead of * being returned). */ - -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +asmlinkage int +sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; int ret; lock_kernel(); ret = -EPERM; + if (request == PTRACE_TRACEME) { - /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; ret = 0; goto out; } + ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); + if (child) get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) goto out; + ret = -EPERM; - if (pid == 1) /* you may not mess with init */ + + if (pid == 1) /* Leave the init process alone! */ goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) goto out_tsk; + if (child->state != TASK_STOPPED) { if (request != PTRACE_KILL) goto out_tsk; } - if (child->p_pptr != current) + + if (child->parent != current) goto out_tsk; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ + /* Read word at location address. */ + case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: { unsigned long tmp; int copied; copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ret = -EIO; + if (copied != sizeof(tmp)) break; + ret = put_user(tmp,(unsigned long *) data); break; } - /* read the word at location addr in the USER area. */ + /* Read the word at location address in the USER area. */ case PTRACE_PEEKUSR: { unsigned long tmp; @@ -173,24 +125,30 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) tmp = 0; /* Default return condition */ ret = -EIO; + if (addr < sizeof(struct pt_regs)) { tmp = get_reg(child, addr >> 2); ret = put_user(tmp, (unsigned long *)data); } + break; } - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ + + /* Write the word at location address. */ + case PTRACE_POKETEXT: case PTRACE_POKEDATA: ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) break; + ret = -EIO; break; - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + + /* Write the word at location address in the USER area. */ + case PTRACE_POKEUSR: ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) break; @@ -198,57 +156,69 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) addr >>= 2; if (addr == PT_DCCR) { - /* don't allow the tracing process to change stuff like - * interrupt enable, kernel/user bit, dma enables etc. - */ + /* + * Don't allow the tracing process to + * change stuff like interrupt enable, + * kernel/user bit, etc. + */ data &= DCCR_MASK; data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; } + if (put_reg(child, addr, data)) break; + ret = 0; } break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ + case PTRACE_SYSCALL: + case PTRACE_CONT: ret = -EIO; + if ((unsigned long) data > _NSIG) break; - if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; - else - child->ptrace &= ~PT_TRACESYS; + + if (request == PTRACE_SYSCALL) { + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + else { + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + child->exit_code = data; + /* TODO: make sure any pending breakpoint is killed */ wake_up_process(child); ret = 0; + break; - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ + + /* Make the child exit by sending it a sigkill. */ case PTRACE_KILL: ret = 0; - if (child->state == TASK_ZOMBIE) /* already dead */ + + if (child->state == TASK_ZOMBIE) break; + child->exit_code = SIGKILL; + /* TODO: make sure any pending breakpoint is killed */ wake_up_process(child); break; - case PTRACE_SINGLESTEP: /* set the trap flag. */ + /* Set the trap flag. */ + case PTRACE_SINGLESTEP: ret = -EIO; + if ((unsigned long) data > _NSIG) break; - child->ptrace &= ~PT_TRACESYS; + + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); /* TODO: set some clever breakpoint mechanism... */ child->exit_code = data; - /* give it a chance to run. */ wake_up_process(child); ret = 0; break; @@ -257,36 +227,46 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_detach(child, data); break; - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + /* Get all GP registers from the child. */ + case PTRACE_GETREGS: { int i; unsigned long tmp; + for (i = 0; i <= PT_MAX; i++) { tmp = get_reg(child, i); + if (put_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } + data += sizeof(long); } + ret = 0; break; } - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + /* Set all GP registers in the child. */ + case PTRACE_SETREGS: { int i; unsigned long tmp; + for (i = 0; i <= PT_MAX; i++) { if (get_user(tmp, (unsigned long *) data)) { ret = -EFAULT; break; } + if (i == PT_DCCR) { tmp &= DCCR_MASK; tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; } + put_reg(child, i, tmp); data += sizeof(long); } + ret = 0; break; } @@ -296,26 +276,30 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; } out_tsk: - free_task_struct(child); + put_task_struct(child); out: unlock_kernel(); return ret; } -asmlinkage void syscall_trace(void) +void do_syscall_trace(void) { - if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) != - (PT_PTRACED | PT_TRACESYS)) + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + if (!(current->ptrace & PT_PTRACED)) return; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0); + current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); + /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl + * This isn't the same as continuing with a signal, but it will do for + * normal use. */ if (current->exit_code) { send_sig(current->exit_code, current, 1); diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c new file mode 100644 index 00000000000..d95930270a9 --- /dev/null +++ b/arch/cris/arch-v10/kernel/setup.c @@ -0,0 +1,96 @@ +/* $Id: setup.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ + * + * linux/arch/cris/arch-v10/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (c) 2001-2002 Axis Communications AB + */ + +/* + * This file handles the architecture-dependent parts of initialization + */ + +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +#define HAS_FPU 0x0001 +#define HAS_MMU 0x0002 +#define HAS_ETHERNET100 0x0004 +#define HAS_TOKENRING 0x0008 +#define HAS_SCSI 0x0010 +#define HAS_ATA 0x0020 +#define HAS_USB 0x0040 +#define HAS_IRQ_BUG 0x0080 +#define HAS_MMU_BUG 0x0100 + +static struct cpu_info { + char *model; + unsigned short cache; + unsigned short flags; +} cpu_info[] = { + /* The first four models will never ever run this code and are + only here for display. */ + { "ETRAX 1", 0, 0 }, + { "ETRAX 2", 0, 0 }, + { "ETRAX 3", 0, HAS_TOKENRING }, + { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "Unknown", 0, 0 } /* This entry MUST be the last */ +}; + +int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long revision; + struct cpu_info *info; + + /* read the version register in the CPU and print some stuff */ + + revision = rdvr(); + + if (revision >= sizeof cpu_info/sizeof *cpu_info) + info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; + else + info = &cpu_info[revision]; + + return seq_printf(m, + "processor\t: 0\n" + "cpu\t\t: CRIS\n" + "cpu revision\t: %lu\n" + "cpu model\t: %s\n" + "cache size\t: %d kB\n" + "fpu\t\t: %s\n" + "mmu\t\t: %s\n" + "mmu DMA bug\t: %s\n" + "ethernet\t: %s Mbps\n" + "token ring\t: %s\n" + "scsi\t\t: %s\n" + "ata\t\t: %s\n" + "usb\t\t: %s\n" + "bogomips\t: %lu.%02lu\n", + + revision, + info->model, + info->cache, + info->flags & HAS_FPU ? "yes" : "no", + info->flags & HAS_MMU ? "yes" : "no", + info->flags & HAS_MMU_BUG ? "yes" : "no", + info->flags & HAS_ETHERNET100 ? "10/100" : "10", + info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", + info->flags & HAS_SCSI ? "yes" : "no", + info->flags & HAS_ATA ? "yes" : "no", + info->flags & HAS_USB ? "yes" : "no", + (loops_per_jiffy * HZ + 500) / 500000, + ((loops_per_jiffy * HZ + 500) / 5000) % 100); +} + +#endif /* CONFIG_PROC_FS */ diff --git a/arch/cris/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c similarity index 94% rename from arch/cris/kernel/shadows.c rename to arch/cris/arch-v10/kernel/shadows.c index 25fac64945e..561a890a8e4 100644 --- a/arch/cris/kernel/shadows.c +++ b/arch/cris/arch-v10/kernel/shadows.c @@ -1,4 +1,4 @@ -/* $Id: shadows.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ diff --git a/arch/cris/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c similarity index 91% rename from arch/cris/kernel/signal.c rename to arch/cris/arch-v10/kernel/signal.c index 678281dae20..6698054a576 100644 --- a/arch/cris/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -55,11 +55,11 @@ sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, sigset_t saveset; mask &= _BLOCKABLE; - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); regs->r10 = -EINTR; while (1) { @@ -94,11 +94,11 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); regs->r10 = -EINTR; while (1) { @@ -117,7 +117,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, } int -sys_sigaction(int sig, const struct old_sigaction *act, +sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; @@ -149,7 +149,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, } int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) { return do_sigaltstack(uss, uoss, rdusp()); } @@ -175,7 +175,7 @@ struct rt_sigframe { static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int err = 0; unsigned long old_usp; @@ -217,7 +217,7 @@ badframe: asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, struct pt_regs *regs) { - struct sigframe *frame = (struct sigframe *)rdusp(); + struct sigframe __user *frame = (struct sigframe *)rdusp(); sigset_t set; /* @@ -232,15 +232,15 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, + && __copy_from_user(&set.sig[1], frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -259,7 +259,7 @@ badframe: asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, struct pt_regs *regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); + struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); sigset_t set; stack_t st; @@ -277,10 +277,10 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -303,7 +303,7 @@ badframe: */ static int -setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask) +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; unsigned long usp = rdusp(); @@ -328,7 +328,7 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask /* figure out where we want to put the new signal frame - usually on the stack */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long sp = rdusp(); @@ -343,7 +343,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) sp &= ~3; - return (void *)(sp - frame_size); + return (void __user*)(sp - frame_size); } /* grab and setup a signal frame. @@ -357,7 +357,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - struct sigframe *frame; + struct sigframe __user *frame; unsigned long return_ip; int err = 0; @@ -414,7 +414,7 @@ give_sigsegv: static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; unsigned long return_ip; int err = 0; @@ -481,16 +481,18 @@ give_sigsegv: * OK, we're invoking a handler */ -static inline void +extern inline void handle_signal(int canrestart, unsigned long sig, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sig->action[sig-1]; + struct k_sigaction *ka = ¤t->sighand->action[sig-1]; /* Are we from a system call? */ if (canrestart) { /* If so, check system call restarting.. */ switch (regs->r10) { + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = do_no_restart_syscall; case -ERESTARTNOHAND: /* ERESTARTNOHAND means that the syscall should only be restarted if there was no handler for the signal, and since @@ -523,11 +525,11 @@ handle_signal(int canrestart, unsigned long sig, ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); } } @@ -575,6 +577,10 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) regs->r10 == -ERESTARTNOINTR) { RESTART_CRIS_SYS(regs); } + if (regs->r10 == -ERESTART_RESTARTBLOCK){ + regs->r10 = __NR_restart_syscall; + regs->irp -= 2; + } } return 0; } diff --git a/arch/cris/kernel/time.c b/arch/cris/arch-v10/kernel/time.c similarity index 56% copy from arch/cris/kernel/time.c copy to arch/cris/arch-v10/kernel/time.c index 81f91df573a..31e83a84e4a 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -1,73 +1,74 @@ -/* $Id: time.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: time.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ * - * linux/arch/cris/kernel/time.c + * linux/arch/cris/arch-v10/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Copyright (C) 1999, 2000, 2001 Axis Communications AB - * - * 1994-07-02 Alan Modra - * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime - * 1995-03-26 Markus Kuhn - * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 - * precision CMOS clock update - * 1996-05-03 Ingo Molnar - * fixed time warps in do_[slow|fast]_gettimeoffset() - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * - * Linux/CRIS specific code: - * - * Authors: Bjorn Wesen - * Johan Adolfsson + * Copyright (C) 1999-2002 Axis Communications AB * */ -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include #include -#include #include #include -#include -#include - -#include - -u64 jiffies_64 = INITIAL_JIFFIES; - -static int have_rtc; /* used to remember if we have an RTC or not */ - /* define this if you need to use print_timestamp */ /* it will make jiffies at 96 hz instead of 100 hz though */ #undef USE_CASCADE_TIMERS -extern int setup_etrax_irq(int, struct irqaction *); +extern void update_xtime_from_cmos(void); +extern int set_rtc_mmss(unsigned long nowtime); +extern int setup_irq(int, struct irqaction *); +extern int have_rtc; -/* Lookup table to convert *R_TIMER0 to microseconds (us) - * Timer goes from TIMER0_DIV down to 1 meaning 0-10000us in step of approx 52us - */ -unsigned short cris_timer0_value_us[TIMER0_DIV+1]; +unsigned long get_ns_in_jiffie(void) +{ + unsigned char timer_count, t1; + unsigned short presc_count; + unsigned long ns; + unsigned long flags; -#define TICK_SIZE tick + local_irq_save(flags); + local_irq_disable(); + timer_count = *R_TIMER0_DATA; + presc_count = *R_TIM_PRESC_STATUS; + /* presc_count might be wrapped */ + t1 = *R_TIMER0_DATA; + + if (timer_count != t1){ + /* it wrapped, read prescaler again... */ + presc_count = *R_TIM_PRESC_STATUS; + timer_count = t1; + } + local_irq_restore(flags); + if (presc_count >= PRESCALE_VALUE/2 ){ + presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; + } else { + presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; + } -static unsigned long do_slow_gettimeoffset(void) + ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + + ( (presc_count) * (1000000000/PRESCALE_FREQ)); + return ns; +} + +unsigned long do_slow_gettimeoffset(void) { - unsigned long count; + unsigned long count, t1; unsigned long usec_count = 0; + unsigned short presc_count; - static unsigned long count_p = LATCH; /* for the first call after boot */ + static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ static unsigned long jiffies_p = 0; /* @@ -83,130 +84,46 @@ static unsigned long do_slow_gettimeoffset(void) #ifndef CONFIG_SVINTO_SIM /* Not available in the xsim simulator. */ count = *R_TIMER0_DATA; + presc_count = *R_TIM_PRESC_STATUS; + /* presc_count might be wrapped */ + t1 = *R_TIMER0_DATA; + if (count != t1){ + /* it wrapped, read prescaler again... */ + presc_count = *R_TIM_PRESC_STATUS; + count = t1; + } #else count = 0; + presc_count = 0; #endif jiffies_t = jiffies; /* * avoiding timer inconsistencies (they are rare, but they happen)... - * there are three kinds of problems that must be avoided here: + * there are one problem that must be avoided here: * 1. the timer counter underflows - * 2. we are after the timer interrupt, but the bottom half handler - * hasn't executed yet. - */ + */ if( jiffies_t == jiffies_p ) { if( count > count_p ) { - /* Timer wrapped */ - count = count_p; - usec_count = 1000000/CLOCK_TICK_RATE/2; + /* Timer wrapped, use new count and prescale + * increase the time corresponding to one jiffie + */ + usec_count = 1000000/HZ; } } else jiffies_p = jiffies_t; count_p = count; - /* Convert timer value to usec using table lookup */ - usec_count += cris_timer0_value_us[count]; -#if 0 - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; -#endif - return usec_count; -} - -static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; - -/* - * This version of gettimeofday has near microsecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - - save_flags(flags); - cli(); - *tv = xtime; - tv->tv_usec += do_gettimeoffset(); - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } - restore_flags(flags); -} - -int do_settimeofday(struct timespec *tv) -{ - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - cli(); - /* This is revolting. We need to set the xtime.tv_usec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ - tv->tv_nsec -= do_gettimeoffset() * 1000; - - if (tv->tv_nsec < 0) { - tv->tv_nsec += NSEC_PER_SEC; - tv->tv_sec--; - } - - xtime = *tv; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - sti(); - return 0; -} - - -/* - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you'll only notice that after reboot! - */ - -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - - printk("set_rtc_mmss(%lu)\n", nowtime); - - if(!have_rtc) - return 0; - - cmos_minutes = CMOS_READ(RTC_MINUTES); - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); + if (presc_count >= PRESCALE_VALUE/2 ){ + presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; + presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; } + /* Convert timer value to usec */ + usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + + (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000); - return retval; + return usec_count; } /* Excerpt from the Etrax100 HSDD about the built-in watchdog: @@ -283,7 +200,7 @@ static long last_rtc_update = 0; //static unsigned short myjiff; /* used by our debug routine print_timestamp */ -static inline void +static inline irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* acknowledge the timer irq */ @@ -315,78 +232,20 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * If we have an externally synchronized Linux clock, then update * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. + * + * The division here is not time critical since it will run once in + * 11 minutes */ - if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) { + (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else - last_rtc_update = xtime.tv_sec - 600; - } -} - -#if 0 -/* some old debug code for testing the microsecond timing of packets */ -static unsigned int lastjiff; - -void print_timestamp(const char *s) -{ - unsigned long flags; - unsigned int newjiff; - - save_flags(flags); - cli(); - newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); - printk("%s: %x (%x)\n", s, newjiff, newjiff - lastjiff); - lastjiff = newjiff; - restore_flags(flags); -} -#endif - -/* grab the time from the RTC chip */ - -unsigned long -get_cmos_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - - printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", - sec, min, hour, day, mon, year); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - if ((year += 1900) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. - * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. - */ - -void -update_xtime_from_cmos(void) -{ - if(have_rtc) { - xtime.tv_sec = get_cmos_time(); - xtime.tv_usec = 0; + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } + return IRQ_HANDLED; } /* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain @@ -399,13 +258,18 @@ static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, void __init time_init(void) { - int i; - /* probe for the RTC and read it if it exists */ + /* probe for the RTC and read it if it exists + * Before the RTC can be probed the loops_per_usec variable needs + * to be initialized to make usleep work. A better value for + * loops_per_usec is calculated by the kernel later once the + * clock has started. + */ + loops_per_usec = 50; if(RTC_INIT() < 0) { /* no RTC, start at 1980 */ xtime.tv_sec = 0; - xtime.tv_usec = 0; + xtime.tv_nsec = 0; have_rtc = 0; } else { /* get the current time */ @@ -414,7 +278,7 @@ time_init(void) } /* Setup the etrax timers - * Base frequency is 19200 hz, divider 192 -> 100 hz as Linux wants + * Base frequency is 25000 hz, divider 250 -> 100 HZ * In normal mode, we use timer0, so timer1 is free. In cascade * mode (which we sometimes use for debugging) both timers are used. * Remember that linux/timex.h contains #defines that rely on the @@ -444,38 +308,33 @@ time_init(void) #else *R_TIMER_CTRL = IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | IO_STATE(R_TIMER_CTRL, i0, nop) | IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); + IO_STATE(R_TIMER_CTRL, clksel0, flexible); *R_TIMER_CTRL = r_timer_ctrl_shadow = IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | IO_STATE(R_TIMER_CTRL, i1, nop) | IO_STATE(R_TIMER_CTRL, tm1, run) | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | IO_STATE(R_TIMER_CTRL, i0, nop) | IO_STATE(R_TIMER_CTRL, tm0, run) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); + IO_STATE(R_TIMER_CTRL, clksel0, flexible); + + *R_TIMER_PRESCALE = PRESCALE_VALUE; #endif - for (i=0; i <= TIMER0_DIV; i++) { - /* We must be careful not to get overflow... */ - cris_timer0_value_us[TIMER0_DIV-i] = - (unsigned short)((unsigned long) - ((i*(1000000/HZ))/TIMER0_DIV)&0x0000FFFFL); - } - *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ /* now actually register the timer irq handler that calls timer_interrupt() */ - setup_etrax_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ + setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ /* enable watchdog if we should use one */ diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c new file mode 100644 index 00000000000..da491f438a6 --- /dev/null +++ b/arch/cris/arch-v10/kernel/traps.c @@ -0,0 +1,132 @@ +/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ + * + * linux/arch/cris/arch-v10/traps.c + * + * Heler functions for trap handlers + * + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * Hans-Peter Nilsson + * + */ + +#include +#include +#include +#include + +void +show_registers(struct pt_regs * regs) +{ + /* We either use rdusp() - the USP register, which might not + correspond to the current process for all cases we're called, + or we use the current->thread.usp, which is not up to date for + the current process. Experience shows we want the USP + register. */ + unsigned long usp = rdusp(); + + printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); + printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); + printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + regs->r4, regs->r5, regs->r6, regs->r7); + printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + regs->r8, regs->r9, regs->r10, regs->r11); + printk("r12: %08lx r13: %08lx oR10: %08lx\n", + regs->r12, regs->r13, regs->orig_r10); + printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long)current); + + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (! user_mode(regs)) { + int i; + + show_stack(NULL, (unsigned long*)usp); + + /* Dump kernel stack if the previous dump wasn't one. */ + if (usp != 0) + show_stack (NULL, NULL); + + printk("\nCode: "); + if(regs->irp < PAGE_OFFSET) + goto bad; + + /* Often enough the value at regs->irp does not point to + the interesting instruction, which is most often the + _previous_ instruction. So we dump at an offset large + enough that instruction decoding should be in sync at + the interesting point, but small enough to fit on a row + (sort of). We point out the regs->irp location in a + ksymoops-friendly way by wrapping the byte for that + address in parentheses. */ + for(i = -12; i < 12; i++) + { + unsigned char c; + if(__get_user(c, &((unsigned char*)regs->irp)[i])) { +bad: + printk(" Bad IP value."); + break; + } + + if (i == 0) + printk("(%02x) ", c); + else + printk("%02x ", c); + } + printk("\n"); + } +} + +/* Called from entry.S when the watchdog has bitten + * We print out something resembling an oops dump, and if + * we have the nice doggy development flag set, we halt here + * instead of rebooting. + */ + +extern void reset_watchdog(void); +extern void stop_watchdog(void); + + +void +watchdog_bite_hook(struct pt_regs *regs) +{ +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + local_irq_disable(); + stop_watchdog(); + show_registers(regs); + while(1) /* nothing */; +#else + show_registers(regs); +#endif +} + +/* This is normally the 'Oops' routine */ +void +die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if(user_mode(regs)) + return; + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + /* This printout might take too long and trigger the + * watchdog normally. If we're in the nice doggy + * development mode, stop the watchdog during printout. + */ + stop_watchdog(); +#endif + + printk("%s: %04lx\n", str, err & 0xffff); + + show_registers(regs); + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + reset_watchdog(); +#endif + do_exit(SIGSEGV); +} diff --git a/arch/cris/lib/Makefile b/arch/cris/arch-v10/lib/Makefile similarity index 98% rename from arch/cris/lib/Makefile rename to arch/cris/arch-v10/lib/Makefile index 568496a8884..36e9a9c5239 100644 --- a/arch/cris/lib/Makefile +++ b/arch/cris/arch-v10/lib/Makefile @@ -2,6 +2,8 @@ # Makefile for Etrax-specific library files.. # + EXTRA_AFLAGS := -traditional lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o + diff --git a/arch/cris/lib/checksum.S b/arch/cris/arch-v10/lib/checksum.S similarity index 97% rename from arch/cris/lib/checksum.S rename to arch/cris/arch-v10/lib/checksum.S index fd15a76f78d..85c48f0a9ec 100644 --- a/arch/cris/lib/checksum.S +++ b/arch/cris/arch-v10/lib/checksum.S @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: checksum.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * A fast checksum routine using movem * Copyright (c) 1998-2001 Axis Communications AB * diff --git a/arch/cris/lib/checksumcopy.S b/arch/cris/arch-v10/lib/checksumcopy.S similarity index 97% rename from arch/cris/lib/checksumcopy.S rename to arch/cris/arch-v10/lib/checksumcopy.S index 4d8bc348da3..35cbffb306f 100644 --- a/arch/cris/lib/checksumcopy.S +++ b/arch/cris/arch-v10/lib/checksumcopy.S @@ -1,4 +1,4 @@ -/* $Id: checksumcopy.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: checksumcopy.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * A fast checksum+copy routine using movem * Copyright (c) 1998, 2001 Axis Communications AB * diff --git a/arch/cris/lib/csumcpfruser.S b/arch/cris/arch-v10/lib/csumcpfruser.S similarity index 100% rename from arch/cris/lib/csumcpfruser.S rename to arch/cris/arch-v10/lib/csumcpfruser.S diff --git a/arch/cris/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c similarity index 93% rename from arch/cris/lib/dmacopy.c rename to arch/cris/arch-v10/lib/dmacopy.c index fe8f091ed09..e5fb44f505c 100644 --- a/arch/cris/lib/dmacopy.c +++ b/arch/cris/arch-v10/lib/dmacopy.c @@ -1,4 +1,4 @@ -/* $Id: dmacopy.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax */ diff --git a/arch/cris/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S similarity index 82% rename from arch/cris/lib/dram_init.S rename to arch/cris/arch-v10/lib/dram_init.S index d46efd1aef1..4852709dc7a 100644 --- a/arch/cris/lib/dram_init.S +++ b/arch/cris/arch-v10/lib/dram_init.S @@ -1,4 +1,4 @@ -/* $Id: dram_init.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: dram_init.S,v 1.3 2003/03/31 09:38:37 starvik Exp $ * * DRAM/SDRAM initialization - alter with care * This file is intended to be included from other assembler files @@ -11,8 +11,20 @@ * Authors: Mikael Starvik (starvik@axis.com) * * $Log: dram_init.S,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 + * Revision 1.3 2003/03/31 09:38:37 starvik + * Corrected calculation of end of sdram init commands + * + * Revision 1.2 2002/11/19 13:33:29 starvik + * Changes from Linux 2.4 + * + * Revision 1.13 2002/10/30 07:42:28 starvik + * Always read SDRAM command sequence from flash + * + * Revision 1.12 2002/08/09 11:37:37 orjanf + * Added double initialization work-around for Samsung SDRAMs. + * + * Revision 1.11 2002/06/04 11:43:21 starvik + * Check if mrs_data is specified in kernelconfig (necessary for MCM) * * Revision 1.10 2001/10/04 12:00:21 martinnn * Added missing underscores. @@ -73,7 +85,11 @@ move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0 move.d $r0, [R_DRAM_TIMING] -#else +#else + ;; Samsung SDRAMs seem to require to be initialized twice to work properly. + moveq 2, $r6 +_sdram_init: + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization ; Bank configuration @@ -85,6 +101,12 @@ ; CAS latency = 3 && bus_width = 32 => 0x60 ; CAS latency = 2 && bus_width = 16 => 0x20 ; CAS latency = 3 && bus_width = 16 => 0x30 + + ; Check if value is already supplied in kernel config + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2 + and.d 0x00ff0000, $r2 + bne _set_timing + lsrq 16, $r2 move.d 0x40, $r2 ; Assume 32 bits and CAS latency = 2 move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 @@ -130,7 +152,9 @@ _set_timing: ; Issue initialization command sequence move.d _sdram_commands_start, $r2 + and.d 0x00ffffff, $r2 ; Make sure commands are read from flash move.d _sdram_commands_end, $r3 + and.d 0x00ffffff, $r3 1: clear.d $r4 move.b [$r2+], $r4 lslq 9, $r4 ; Command starts at bit 9 @@ -145,6 +169,9 @@ _set_timing: bne 1b nop move.d $r5, [R_SDRAM_TIMING] + subq 1, $r6 + bne _sdram_init + nop ba _sdram_commands_end nop diff --git a/arch/cris/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S similarity index 95% rename from arch/cris/lib/hw_settings.S rename to arch/cris/arch-v10/lib/hw_settings.S index b35bb3baa5a..56905aaa7b6 100644 --- a/arch/cris/lib/hw_settings.S +++ b/arch/cris/arch-v10/lib/hw_settings.S @@ -1,5 +1,5 @@ /* - * $Id: hw_settings.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ + * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * This table is used by some tools to extract hardware parameters. * The table should be included in the kernel and the decompressor. diff --git a/arch/cris/lib/memset.c b/arch/cris/arch-v10/lib/memset.c similarity index 100% rename from arch/cris/lib/memset.c rename to arch/cris/arch-v10/lib/memset.c diff --git a/arch/cris/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c similarity index 94% rename from arch/cris/lib/old_checksum.c rename to arch/cris/arch-v10/lib/old_checksum.c index 5d4d9bc4b05..3b68d1a60a0 100644 --- a/arch/cris/lib/old_checksum.c +++ b/arch/cris/arch-v10/lib/old_checksum.c @@ -1,4 +1,4 @@ -/* $Id: old_checksum.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: old_checksum.c,v 1.2 2002/11/05 06:45:12 starvik Exp $ * * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket @@ -75,7 +75,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) sum += *((unsigned short *)buff)++; } if(endMarker - buff > 0) { - sum += *buff; /* add extra byte separately */ + sum += *buff; /* add extra byte seperately */ } BITOFF; return(sum); diff --git a/arch/cris/lib/string.c b/arch/cris/arch-v10/lib/string.c similarity index 100% rename from arch/cris/lib/string.c rename to arch/cris/arch-v10/lib/string.c diff --git a/arch/cris/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c similarity index 80% rename from arch/cris/lib/usercopy.c rename to arch/cris/arch-v10/lib/usercopy.c index fc0b89cc57f..43778d53c25 100644 --- a/arch/cris/lib/usercopy.c +++ b/arch/cris/arch-v10/lib/usercopy.c @@ -31,7 +31,7 @@ kernel-to-kernel copying; see "string.c". */ unsigned long -__copy_user (void *pdst, const void *psrc, unsigned long pn) +__copy_user (void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -88,11 +88,11 @@ __copy_user (void *pdst, const void *psrc, unsigned long pn) If you want to check that the allocation was right; then check the equalities in the first comment. It should say "r13=r13, r11=r11, r12=r12". */ - __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r11, %2=r12 %3=r10 - ;; + __asm__ volatile ("\ + .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll use in the movem process ;; on the stack. subq 11*4,$sp @@ -189,10 +189,11 @@ __copy_user (void *pdst, const void *psrc, unsigned long pn) } /* Copy from user to kernel, zeroing the bytes that were inaccessible in - userland. */ + userland. The return-value is the number of bytes that were + inaccessible. */ unsigned long -__copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) +__copy_user_zeroing (void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -207,30 +208,34 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) register int n __asm__ ("r12") = pn; register int retn __asm__ ("r10") = 0; - /* When src is aligned but not dst, this makes a few extra needless - cycles. I believe it would take as many to check that the - re-alignment was unnecessary. */ - if (((unsigned long) dst & 3) != 0 - /* Don't align if we wouldn't copy more than a few bytes; so we - don't have to check further for overflows. */ - && n >= 3) + /* The best reason to align src is that we then know that a read-fault + was for aligned bytes; there's no 1..3 remaining good bytes to + pickle. */ + if (((unsigned long) src & 3) != 0) { - if ((unsigned long) dst & 1) + if (((unsigned long) src & 1) && n != 0) { __asm_copy_from_user_1 (dst, src, retn); n--; } - if ((unsigned long) dst & 2) + if (((unsigned long) src & 2) && n >= 2) { __asm_copy_from_user_2 (dst, src, retn); n -= 2; } + + /* We only need one check after the unalignment-adjustments, because + if both adjustments were done, either both or neither reference + had an exception. */ + if (retn != 0) + goto copy_exception_bytes; } /* Decide which copying method to use. */ if (n >= 44*2) /* Break even between movem and - move16 is at 38.7*2, but modulo 44. */ + move16 is at 38.7*2, but modulo 44. + FIXME: We use move4 now. */ { /* For large copies we use 'movem' */ @@ -249,10 +254,10 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) check the equalities in the first comment. It should say "r13=r13, r11=r11, r12=r12" */ __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r11, %2=r12 %3=r10 - ;; + .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll use in the movem process ;; on the stack. subq 11*4,$sp @@ -273,73 +278,30 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) movem $r10,[$r13+] addq 44,$r12 ;; compensate for last loop underflowing n -8: + ;; Restore registers from stack movem [$sp+],$r10 - +4: .section .fixup,\"ax\" ;; Do not jump back into the loop if we fail. For some uses, we get a -;; page fault but for performance reasons we care to not get further -;; faults. For example, fs/super.c at one time did +;; page fault somewhere on the line. Without checking for page limits, +;; we don't know where, but we need to copy accurately and keep an +;; accurate count; not just clear the whole line. To do that, we fall +;; down in the code below, proceeding with smaller amounts. It should +;; be kept in mind that we have to cater to code like what at one time +;; was in fs/super.c: ;; i = size - copy_from_user((void *)page, data, size); ;; which would cause repeated faults while clearing the remainder of ;; the SIZE bytes at PAGE after the first fault. +;; A caveat here is that we must not fall through from a failing page +;; to a valid page. 3: - move.d [$sp],$r10 - -;; Number of remaining bytes, cleared but not copied, is r12 + 44. - - add.d $r12,$r10 - addq 44,$r10 - - move.d $r10,[$sp] - clear.d $r0 - clear.d $r1 - clear.d $r2 - clear.d $r3 - clear.d $r4 - clear.d $r5 - clear.d $r6 - clear.d $r7 - clear.d $r8 - clear.d $r9 - clear.d $r10 - -;; Perform clear similar to the copy-loop. - -4: - subq 44,$r12 - bge 4b - movem $r10,[$r13+] - -;; Clear by four for the remaining multiples. - - addq 40,$r12 - bmi 6f - nop -5: - subq 4,$r12 - bpl 5b - clear.d [$r13+] -6: - addq 4,$r12 - beq 7f - nop - - subq 1,$r12 - beq 7f - clear.b [$r13+] - - subq 1,$r12 - beq 7f - clear.b [$r13+] - - clear.d $r12 - clear.b [$r13+] -7: - jump 8b + movem [$sp+],$r10 + addq 44,$r12 ;; Get back count before faulting point. + subq 44,$r11 ;; Get back pointer to faulting movem-line. + jump 4b ;; Fall through, pretending the fault didn't happen. .previous .section __ex_table,\"a\" @@ -354,25 +316,30 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) /* Either we directly start copying here, using dword copying in a loop, or we copy as much as possible with 'movem' and then the last block (<44 bytes) is copied here. This will work since 'movem' will have - updated src, dst and n. */ + updated src, dst and n. (Except with failing src.) - while (n >= 16) - { - __asm_copy_from_user_16 (dst, src, retn); - n -= 16; - } + Since we want to keep src accurate, we can't use + __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and + retn, but not src (by design; it's value is ignored elsewhere). */ - /* Having a separate by-four loops cuts down on cache footprint. - FIXME: Test with and without; increasing switch to be 0..15. */ while (n >= 4) { __asm_copy_from_user_4 (dst, src, retn); n -= 4; + + if (retn) + goto copy_exception_bytes; } + /* If we get here, there were no memory read faults. */ switch (n) { + /* These copies are at least "naturally aligned" (so we don't have + to check each byte), due to the src alignment code before the + movem loop. The *_3 case *will* get the correct count for retn. */ case 0: + /* This case deliberately left in (if you have doubts check the + generated assembly code). */ break; case 1: __asm_copy_from_user_1 (dst, src, retn); @@ -385,13 +352,28 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) break; } + /* If we get here, retn correctly reflects the number of failing + bytes. */ return retn; + +copy_exception_bytes: + /* We already have "retn" bytes cleared, and need to clear the + remaining "n" bytes. A non-optimized simple byte-for-byte in-line + memset is preferred here, since this isn't speed-critical code and + we'd rather have this a leaf-function than calling memset. */ + { + char *endp; + for (endp = dst + n; dst < endp; dst++) + *dst = 0; + } + + return retn + n; } /* Zero userspace. */ unsigned long -__do_clear_user (void *pto, unsigned long pn) +__do_clear_user (void __user *pto, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -444,10 +426,10 @@ __do_clear_user (void *pto, unsigned long pn) check the equalities in the first comment. It should say something like "r13=r13, r11=r11, r12=r12". */ __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r12 %2=r10 - ;; + .ifnc %0%1%2,$r13$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll clobber in the movem process ;; on the stack. Don't mention them to gcc, it will only be ;; upset. diff --git a/arch/cris/mm/Makefile b/arch/cris/arch-v10/mm/Makefile similarity index 58% copy from arch/cris/mm/Makefile copy to arch/cris/arch-v10/mm/Makefile index 5a92ec53ca3..588b4baee85 100644 --- a/arch/cris/mm/Makefile +++ b/arch/cris/arch-v10/mm/Makefile @@ -2,4 +2,5 @@ # Makefile for the linux cris-specific parts of the memory manager. # -obj-y := init.o fault.o tlb.o extable.o ioremap.o +obj-y := fault.o init.o tlb.o + diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c new file mode 100644 index 00000000000..7a012adc157 --- /dev/null +++ b/arch/cris/arch-v10/mm/fault.c @@ -0,0 +1,175 @@ +/* + * linux/arch/cris/mm/fault.c + * + * Low level bus fault handler + * + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen + * + */ + +#include +#include +#include +#include + +/* debug of low-level TLB reload */ +#undef DEBUG + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +extern volatile pgd_t *current_pgd; + +extern const struct exception_table_entry + *search_exception_tables(unsigned long addr); + +asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, + int error_code); + +/* fast TLB-fill fault handler + * this is called from entry.S with interrupts disabled + */ + +void +handle_mmu_bus_fault(struct pt_regs *regs) +{ + int cause, select; +#ifdef DEBUG + int index; + int page_id; + int acc, inv; +#endif + int miss, we, writeac; + pmd_t *pmd; + pte_t pte; + int errcode; + unsigned long address; + + cause = *R_MMU_CAUSE; + select = *R_TLB_SELECT; + + address = cause & PAGE_MASK; /* get faulting address */ + +#ifdef DEBUG + page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); + inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); + index = IO_EXTRACT(R_TLB_SELECT, index, select); +#endif + miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); + we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); + writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); + + /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned + * write causes a MMU-fault, it will not be restarted correctly. + * This could happen if a write crosses a page-boundary and the + * second page is not yet COW'ed or even loaded. The workaround + * is to clear the unaligned bit in the CPU status record, so + * that the CPU will rerun both the first and second halves of + * the instruction. This will not have any sideeffects unless + * the first half goes to any device or memory that can't be + * written twice, and which is mapped through the MMU. + * + * We only need to do this for writes. + */ + + if(writeac) + regs->csrinstr &= ~(1 << 5); + + /* Set errcode's R/W flag according to the mode which caused the + * fault + */ + + errcode = writeac << 1; + + D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", + regs->irp, address, miss, inv, we, acc, index, page_id)); + + /* for a miss, we need to reload the TLB entry */ + + if (miss) { + /* see if the pte exists at all + * refer through current_pgd, dont use mm->pgd + */ + + pmd = (pmd_t *)(current_pgd + pgd_index(address)); + if (pmd_none(*pmd)) + goto dofault; + if (pmd_bad(*pmd)) { + printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); + pmd_clear(pmd); + return; + } + pte = *pte_offset_kernel(pmd, address); + if (!pte_present(pte)) + goto dofault; + +#ifdef DEBUG + printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); + if (pte_val(pte) & _PAGE_SILENT_WRITE) + printk("Silent-W "); + if (pte_val(pte) & _PAGE_KERNEL) + printk("Kernel "); + if (pte_val(pte) & _PAGE_SILENT_READ) + printk("Silent-R "); + if (pte_val(pte) & _PAGE_GLOBAL) + printk("Global "); + if (pte_val(pte) & _PAGE_PRESENT) + printk("Present "); + if (pte_val(pte) & _PAGE_ACCESSED) + printk("Accessed "); + if (pte_val(pte) & _PAGE_MODIFIED) + printk("Modified "); + if (pte_val(pte) & _PAGE_READ) + printk("Readable "); + if (pte_val(pte) & _PAGE_WRITE) + printk("Writeable "); + printk("\n"); +#endif + + /* load up the chosen TLB entry + * this assumes the pte format is the same as the TLB_LO layout. + * + * the write to R_TLB_LO also writes the vpn and page_id fields from + * R_MMU_CAUSE, which we in this case obviously want to keep + */ + + *R_TLB_LO = pte_val(pte); + + return; + } + + errcode = 1 | (we << 1); + + dofault: + /* leave it to the MM system fault handler below */ + D(printk("do_page_fault %lx errcode %d\n", address, errcode)); + do_page_fault(address, regs, errcode); +} + +/* Called from arch/cris/mm/fault.c to find fixup code. */ +int +find_fixup_code(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + if ((fixup = search_exception_tables(regs->irp)) != 0) { + /* Adjust the instruction pointer in the stackframe. */ + regs->irp = fixup->fixup; + + /* + * Don't return by restoring the CPU state, so switch + * frame-type. + */ + regs->frametype = CRIS_FRAME_NORMAL; + return 1; + } + + return 0; +} diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c new file mode 100644 index 00000000000..df03dea5bae --- /dev/null +++ b/arch/cris/arch-v10/mm/init.c @@ -0,0 +1,265 @@ +/* + * linux/arch/cris/arch-v10/mm/init.c + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void tlb_init(void); + +/* + * The kernel is already mapped with a kernel segment at kseg_c so + * we don't need to map it with a page table. However head.S also + * temporarily mapped it at kseg_4 so we should set up the ksegs again, + * clear the TLB and do some other paging setup stuff. + */ + +void __init +paging_init(void) +{ + int i; + unsigned long zones_size[MAX_NR_ZONES]; + + printk("Setting up paging and the MMU.\n"); + + /* clear out the init_mm.pgd that will contain the kernel's mappings */ + + for(i = 0; i < PTRS_PER_PGD; i++) + swapper_pg_dir[i] = __pgd(0); + + /* make sure the current pgd table points to something sane + * (even if it is most probably not used until the next + * switch_mm) + */ + + current_pgd = init_mm.pgd; + + /* initialise the TLB (tlb.c) */ + + tlb_init(); + + /* see README.mm for details on the KSEG setup */ + +#ifdef CONFIG_CRIS_LOW_MAP + /* Etrax-100 LX version 1 has a bug so that we cannot map anything + * across the 0x80000000 boundary, so we need to shrink the user-virtual + * area to 0x50000000 instead of 0xb0000000 and map things slightly + * different. The unused areas are marked as paged so that we can catch + * freak kernel accesses there. + * + * The ARTPEC chip is mapped at 0xa so we pass that segment straight + * through. We cannot vremap it because the vmalloc area is below 0x8 + * and Juliette needs an uncached area above 0x8. + * + * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. + * We map them straight over in LOW_MAP, but use vremap in LX version 2. + */ + +#define CACHED_BOOTROM (KSEG_F | 0x08000000UL) + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* bootrom */ + IO_STATE(R_MMU_KSEG, seg_e, page ) | + IO_STATE(R_MMU_KSEG, seg_d, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ +#ifdef CONFIG_JULIETTE + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ +#else + IO_STATE(R_MMU_KSEG, seg_a, page ) | +#endif + IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ + IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ + IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ + IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x3 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | +#ifdef CONFIG_JULIETTE + IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | +#else + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | +#endif + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else + /* This code is for the corrected Etrax-100 LX version 2... */ + +#define CACHED_BOOTROM (KSEG_A | 0x08000000UL) + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* bootrom */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x3 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#endif + + *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); + + /* The MMU has been enabled ever since head.S but just to make + * it totally obvious we do it here as well. + */ + + *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | + IO_STATE(R_MMU_CTRL, acc_excp, enable ) | + IO_STATE(R_MMU_CTRL, we_excp, enable ) ); + + *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ + + zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; + + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + + /* Use free_area_init_node instead of free_area_init, because the former + * is designed for systems where the DRAM starts at an address substantially + * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the + * mem_map page array. + */ + + free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); + mem_map = contig_page_data.node_mem_map; +} + +/* Initialize remaps of some I/O-ports. It is important that this + * is called before any driver is initialized. + */ + +static int +__init init_ioremap(void) +{ + + /* Give the external I/O-port addresses their values */ + +#ifdef CONFIG_CRIS_LOW_MAP + /* Simply a linear map (see the KSEG map above in paging_init) */ + port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | + MEM_NON_CACHEABLE); + port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | + MEM_NON_CACHEABLE); + port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | + MEM_NON_CACHEABLE); +#else + /* Note that nothing blows up just because we do this remapping + * it's ok even if the ports are not used or connected + * to anything (or connected to a non-I/O thing) */ + port_cse1_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSE1_START | MEM_NON_CACHEABLE), 16); + port_csp0_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP0_START | MEM_NON_CACHEABLE), 16); + port_csp4_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP4_START | MEM_NON_CACHEABLE), 16); +#endif + return 0; +} + +__initcall(init_ioremap); + +/* Helper function for the two below */ + +static inline void +flush_etrax_cacherange(void *startadr, int length) +{ + /* CACHED_BOOTROM is mapped to the boot-rom area (cached) which + * we can use to get fast dummy-reads of cachelines + */ + + volatile short *flushadr = (volatile short *)(((unsigned long)startadr & ~PAGE_MASK) | + CACHED_BOOTROM); + + length = length > 8192 ? 8192 : length; /* No need to flush more than cache size */ + + while(length > 0) { + *flushadr; /* dummy read to flush */ + flushadr += (32/sizeof(short)); /* a cacheline is 32 bytes */ + length -= 32; + } +} + +/* Due to a bug in Etrax100(LX) all versions, receiving DMA buffers + * will occationally corrupt certain CPU writes if the DMA buffers + * happen to be hot in the cache. + * + * As a workaround, we have to flush the relevant parts of the cache + * before (re) inserting any receiving descriptor into the DMA HW. + */ + +void +prepare_rx_descriptor(struct etrax_dma_descr *desc) +{ + flush_etrax_cacherange((void *)desc->buf, desc->sw_len ? desc->sw_len : 65536); +} + +/* Do the same thing but flush the entire cache */ + +void +flush_etrax_cache(void) +{ + flush_etrax_cacherange(0, 8192); +} diff --git a/arch/cris/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c similarity index 64% copy from arch/cris/mm/tlb.c copy to arch/cris/arch-v10/mm/tlb.c index f5a97c9799f..2ddb0a61cdb 100644 --- a/arch/cris/mm/tlb.c +++ b/arch/cris/arch-v10/mm/tlb.c @@ -1,37 +1,21 @@ /* - * linux/arch/cris/mm/tlb.c + * linux/arch/cris/arch-v10/mm/tlb.c * - * Copyright (C) 2000, 2001 Axis Communications AB + * Low level TLB handling + * + * + * Copyright (C) 2000-2002 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include +#include #include +#include #define D(x) -/* CRIS in Etrax100LX TLB */ - -#define NUM_TLB_ENTRIES 64 -#define NUM_PAGEID 64 -#define INVALID_PAGEID 63 -#define NO_CONTEXT -1 - /* The TLB can host up to 64 different mm contexts at the same time. * The running context is R_MMU_CONTEXT, and each TLB entry contains a * page_id that has to match to give a hit. In page_id_map, we keep track @@ -46,10 +30,6 @@ * of a flush causing. */ -struct mm_struct *page_id_map[NUM_PAGEID]; - -static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ - /* invalidate all TLB entries */ void @@ -58,11 +38,12 @@ flush_tlb_all(void) int i; unsigned long flags; - /* the vpn of i & 0xf is so we don't write similar TLB entries + /* the vpn of i & 0xf is so we dont write similar TLB entries * in the same 4-way entry group. details.. */ - save_and_cli(flags); /* flush needs to be atomic */ + local_save_flags(flags); + local_irq_disable(); for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | @@ -74,7 +55,7 @@ flush_tlb_all(void) IO_STATE(R_TLB_LO, we, no ) | IO_FIELD(R_TLB_LO, pfn, 0 ) ); } - restore_flags(flags); + local_irq_restore(flags); D(printk("tlb: flushed all\n")); } @@ -97,7 +78,8 @@ flush_tlb_mm(struct mm_struct *mm) * global pages. is it worth the extra I/O ? */ - save_and_cli(flags); /* flush needs to be atomic */ + local_save_flags(flags); + local_irq_disable(); for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { @@ -111,7 +93,7 @@ flush_tlb_mm(struct mm_struct *mm) IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } - restore_flags(flags); + local_irq_restore(flags); } /* invalidate a single page */ @@ -136,7 +118,8 @@ flush_tlb_page(struct vm_area_struct *vma, * and the virtual address requested */ - save_and_cli(flags); /* flush needs to be atomic */ + local_save_flags(flags); + local_irq_disable(); for(i = 0; i < NUM_TLB_ENTRIES; i++) { unsigned long tlb_hi; *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); @@ -153,13 +136,13 @@ flush_tlb_page(struct vm_area_struct *vma, IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } - restore_flags(flags); + local_irq_restore(flags); } /* invalidate a page range */ void -flush_tlb_range(struct vm_area_struct *vma, +flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { @@ -181,7 +164,8 @@ flush_tlb_range(struct vm_area_struct *vma, * and the virtual address range */ - save_and_cli(flags); /* flush needs to be atomic */ + local_save_flags(flags); + local_irq_disable(); for(i = 0; i < NUM_TLB_ENTRIES; i++) { unsigned long tlb_hi, vpn; *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); @@ -199,7 +183,7 @@ flush_tlb_range(struct vm_area_struct *vma, IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } - restore_flags(flags); + local_irq_restore(flags); } /* dump the entire TLB for debug purposes */ @@ -213,72 +197,17 @@ dump_tlb_all(void) printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", i, *R_TLB_HI, *R_TLB_LO); } - restore_flags(flags); + local_irq_restore(flags); } #endif -/* - * Initialize the context related info for a new mm_struct - * instance. - */ - -int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - mm->context = NO_CONTEXT; - return 0; -} - -/* the following functions are similar to those used in the PPC port */ - -static inline void -alloc_context(struct mm_struct *mm) -{ - struct mm_struct *old_mm; - - D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); - - /* did we replace an mm ? */ - - old_mm = page_id_map[map_replace_ptr]; - - if(old_mm) { - /* throw out any TLB entries belonging to the mm we replace - * in the map - */ - flush_tlb_mm(old_mm); - - old_mm->context = NO_CONTEXT; - } - - /* insert it into the page_id_map */ - - mm->context = map_replace_ptr; - page_id_map[map_replace_ptr] = mm; - - map_replace_ptr++; - - if(map_replace_ptr == INVALID_PAGEID) - map_replace_ptr = 0; /* wrap around */ -} - -/* - * if needed, get a new MMU context for the mm. otherwise nothing is done. - */ - -void -get_mmu_context(struct mm_struct *mm) -{ - if(mm->context == NO_CONTEXT) - alloc_context(mm); -} - /* called in schedule() just before actually doing the switch_to */ void @@ -305,43 +234,3 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); } - -/* called by __exit_mm to destroy the used MMU context if any before - * destroying the mm itself. this is only called when the last user of the mm - * drops it. - * - * the only thing we really need to do here is mark the used PID slot - * as empty. - */ - -void -destroy_context(struct mm_struct *mm) -{ - if(mm->context != NO_CONTEXT) { - D(printk("destroy_context %d (%p)\n", mm->context, mm)); - flush_tlb_mm(mm); /* TODO this might be redundant ? */ - page_id_map[mm->context] = NULL; - /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ - } -} - -/* called once during VM initialization, from init.c */ - -void __init -tlb_init(void) -{ - int i; - - /* clear the page_id map */ - - for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) - page_id_map[i] = NULL; - - /* invalidate the entire TLB */ - - flush_tlb_all(); - - /* the init_mm has context 0 from the boot */ - - page_id_map[0] = &init_mm; -} diff --git a/arch/cris/arch-v10/output_arch.ld b/arch/cris/arch-v10/output_arch.ld new file mode 100644 index 00000000000..2f328800699 --- /dev/null +++ b/arch/cris/arch-v10/output_arch.ld @@ -0,0 +1,2 @@ +/* At the time of this writing, there's no equivalent ld option. */ +OUTPUT_ARCH (cris) diff --git a/arch/cris/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S similarity index 86% rename from arch/cris/vmlinux.lds.S rename to arch/cris/arch-v10/vmlinux.lds.S index 3a5f1a36da3..b2c27e147f2 100644 --- a/arch/cris/vmlinux.lds.S +++ b/arch/cris/arch-v10/vmlinux.lds.S @@ -10,11 +10,11 @@ #include #include - + jiffies = jiffies_64; SECTIONS { - . = 0x ## CONFIG_ETRAX_DRAM_VIRTUAL_BASE; + . = DRAM_VIRTUAL_BASE; dram_start = .; ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -53,12 +53,19 @@ SECTIONS . = ALIGN(8192); /* Init code and data */ __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; + __start___param = .; + __param : { *(__param) } + __stop___param = .; .initcall.init : { __initcall_start = .; *(.initcall1.init); @@ -68,24 +75,27 @@ SECTIONS *(.initcall5.init); *(.initcall6.init); *(.initcall7.init); - __initcall_end = .; + __initcall_end = .; } + .con_initcall.init : { __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; - } - .security_initcall.init : { - __security_initcall_start = .; - *(.security_initcall.init) - __security_initcall_end = .; - + } + SECURITY_INIT + + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; /* We fill to the next page, so we can discard all init pages without needing to consider what payload might be appended to the kernel image. */ - FILL (0); + FILL (0); . = ALIGN (8192); } + __vmlinux_end = .; /* last address of the physical file */ __init_end = .; diff --git a/arch/cris/defconfig b/arch/cris/defconfig index 9d40dd31657..7af178b7832 100644 --- a/arch/cris/defconfig +++ b/arch/cris/defconfig @@ -27,93 +27,13 @@ CONFIG_BINFMT_ELF=y CONFIG_ETRAX100LX=y # CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set -CONFIG_CRIS_LOW_MAP=y -CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 CONFIG_ETRAX_DRAM_SIZE=8 CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3" -CONFIG_ETRAX_PA_LEDS=y -# CONFIG_ETRAX_PB_LEDS is not set -# CONFIG_ETRAX_CSP0_LEDS is not set -# CONFIG_ETRAX_NO_LEDS is not set -CONFIG_ETRAX_LED1G=2 -CONFIG_ETRAX_LED1R=2 -CONFIG_ETRAX_LED2G=2 -CONFIG_ETRAX_LED2R=2 -CONFIG_ETRAX_LED3R=2 -CONFIG_ETRAX_LED3G=2 -CONFIG_ETRAX_LED4R=2 -CONFIG_ETRAX_LED4G=2 -CONFIG_ETRAX_LED5R=2 -CONFIG_ETRAX_LED5G=2 -CONFIG_ETRAX_LED6R=2 -CONFIG_ETRAX_LED6G=2 -CONFIG_ETRAX_LED7R=2 -CONFIG_ETRAX_LED7G=2 -CONFIG_ETRAX_LED8Y=2 -CONFIG_ETRAX_LED9Y=2 -CONFIG_ETRAX_LED10Y=2 -CONFIG_ETRAX_LED11Y=2 -CONFIG_ETRAX_LED12R=2 -CONFIG_ETRAX_DEBUG_PORT0=y -# CONFIG_ETRAX_DEBUG_PORT1 is not set -# CONFIG_ETRAX_DEBUG_PORT2 is not set -# CONFIG_ETRAX_DEBUG_PORT3 is not set -CONFIG_ETRAX_RESCUE_SER0=y -# CONFIG_ETRAX_RESCUE_SER1 is not set -# CONFIG_ETRAX_RESCUE_SER2 is not set -# CONFIG_ETRAX_RESCUE_SER3 is not set -CONFIG_ETRAX_DEF_R_WAITSTATES=95a6 -CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 -# CONFIG_ETRAX_SDRAM is not set -CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 -CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 -CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d -CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 -CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 -CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e -CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 -# CONFIG_ETRAX_SOFT_SHUTDOWN is not set # # Drivers for ETRAX 100LX built-in interfaces # -CONFIG_ETRAX_ETHERNET=y -CONFIG_NET_ETHERNET=y -# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set -CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y -# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set -CONFIG_ETRAX_SERIAL=y -CONFIG_ETRAX_SERIAL_PORT0=y -# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set -CONFIG_ETRAX_SERIAL_PORT1=y -# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set -# CONFIG_ETRAX_SERIAL_PORT2 is not set -# CONFIG_ETRAX_SERIAL_PORT3 is not set -# CONFIG_ETRAX_RS485 is not set -# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set -# CONFIG_ETRAX_IDE is not set -CONFIG_ETRAX_AXISFLASHMAP=y -CONFIG_ETRAX_PTABLE_SECTOR=65536 -CONFIG_MTD=y -CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_INTELEXT is not set -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_AMDSTD=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_ETRAX_I2C=y -CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y -# CONFIG_ETRAX_I2C_EEPROM is not set -CONFIG_ETRAX_GPIO=y -CONFIG_ETRAX_PA_BUTTON_BITMASK=02 -CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 -CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF -CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 -CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF -# CONFIG_ETRAX_USB_HOST is not set -# CONFIG_USB is not set -# CONFIG_ETRAX_DS1302 is not set # # Memory Technology Devices (MTD) diff --git a/arch/cris/drivers/axisflashmap.c b/arch/cris/drivers/axisflashmap.c deleted file mode 100644 index 6db4078e068..00000000000 --- a/arch/cris/drivers/axisflashmap.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Physical mapping layer for MTD using the Axis partitiontable format - * - * Copyright (c) 2001 Axis Communications AB - * - * This file is under the GPL. - * - * First partition is always sector 0 regardless of if we find a partitiontable - * or not. In the start of the next sector, there can be a partitiontable that - * tells us what other partitions to define. If there isn't, we use a default - * partition split defined below. - * - * $Log: axisflashmap.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.17 2001/11/12 19:42:38 pkj - * Fixed compiler warnings. - * - * Revision 1.16 2001/11/08 11:18:58 jonashg - * Always read from uncached address to avoid problems with flushing - * cachelines after write and MTD-erase. No performance loss have been - * seen yet. - * - * Revision 1.15 2001/10/19 12:41:04 jonashg - * Name of probe has changed in MTD. - * - * Revision 1.14 2001/09/21 07:14:10 jonashg - * Made root filesystem (cramfs) use mtdblock driver when booting from flash. - * - * Revision 1.13 2001/08/15 13:57:35 jonashg - * Entire MTD updated to the linux 2.4.7 version. - * - * Revision 1.12 2001/06/11 09:50:30 jonashg - * Oops, 2MB is 0x200000 bytes. - * - * Revision 1.11 2001/06/08 11:39:44 jonashg - * Changed sizes and offsets in axis_default_partitions to use - * CONFIG_ETRAX_PTABLE_SECTOR. - * - * Revision 1.10 2001/05/29 09:42:03 jonashg - * Use macro for end marker length instead of sizeof. - * - * Revision 1.9 2001/05/29 08:52:52 jonashg - * Gave names to the magic fours (size of the ptable end marker). - * - * Revision 1.8 2001/05/28 15:36:20 jonashg - * * Removed old comment about ptable location in flash (it's a CONFIG_ option). - * * Variable ptable was initialized twice to the same value. - * - * Revision 1.7 2001/04/05 13:41:46 markusl - * Updated according to review remarks - * - * Revision 1.6 2001/03/07 09:21:21 bjornw - * No need to waste .data - * - * Revision 1.5 2001/03/06 16:27:01 jonashg - * Probe the entire flash area for flash devices. - * - * Revision 1.4 2001/02/23 12:47:15 bjornw - * Uncached flash in LOW_MAP moved from 0xe to 0x8 - * - * Revision 1.3 2001/02/16 12:11:45 jonashg - * MTD driver amd_flash is now included in MTD CVS repository. - * (It's now in drivers/mtd). - * - * Revision 1.2 2001/02/09 11:12:22 jonashg - * Support for AMD compatible non-CFI flash chips. - * Only tested with Toshiba TC58FVT160 so far. - * - * Revision 1.1 2001/01/12 17:01:18 bjornw - * * Added axisflashmap.c, a physical mapping for MTD that reads and understands - * Axis partition-table format. - * - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef CONFIG_CRIS_LOW_MAP -#define FLASH_UNCACHED_ADDR KSEG_8 -#define FLASH_CACHED_ADDR KSEG_5 -#else -#define FLASH_UNCACHED_ADDR KSEG_E -#define FLASH_CACHED_ADDR KSEG_F -#endif - -/* - * WINDOW_SIZE is the total size where the flash chips may be mapped. - * MTD probes should find all devices there and it does not matter - * if there are unmapped gaps or aliases (mirrors of flash devices). - * The MTD probes will ignore them. - */ - -#define WINDOW_SIZE (128 * 1024 * 1024) - -extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */ - -/* - * Map driver - * - * Ok this is the scoop - we need to access the flash both with and without - * the cache - without when doing all the fancy flash interfacing, and with - * when we do actual copying because otherwise it will be slow like molasses. - */ - -static __u8 flash_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs); -} - -static __u16 flash_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs); -} - -static __u32 flash_read32(struct map_info *map, unsigned long ofs) -{ - return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs); -} - -static void flash_copy_from(struct map_info *map, void *to, - unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len); -} - -static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static void flash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static void flash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static struct map_info axis_map = { - .name = "Axis flash", - .size = WINDOW_SIZE, - .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, - .read8 = flash_read8, - .read16 = flash_read16, - .read32 = flash_read32, - .copy_from = flash_copy_from, - .write8 = flash_write8, - .write16 = flash_write16, - .write32 = flash_write32, -}; - -/* If no partition-table was found, we use this default-set. - */ - -#define MAX_PARTITIONS 7 -#define NUM_DEFAULT_PARTITIONS 3 - -/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the - * size of one flash block and "filesystem"-partition needs 5 blocks to be able - * to use JFFS. - */ -static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { - { - .name = "boot firmware", - .size = CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0 - }, - { - .name = "kernel", - .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), - .offset = CONFIG_ETRAX_PTABLE_SECTOR - }, - { - .name = "filesystem", - .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) - } -}; - -static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { - { - .name = "part0", - .size = 0, - .offset = 0 - }, - { - .name = "part1", - .size = 0, - .offset = 0 - }, - { - .name = "part2", - .size = 0, - .offset = 0 - }, - { - .name = "part3", - .size = 0, - .offset = 0 - }, - { - .name = "part4", - .size = 0, - .offset = 0 - }, - { - .name = "part5", - .size = 0, - .offset = 0 - }, - { - .name = "part6", - .size = 0, - .offset = 0 - }, -}; - -/* - * This is the master MTD device for which all the others are just - * auto-relocating aliases. - */ -static struct mtd_info *mymtd; - -/* CFI-scan the flash, and if there was a chip, read the partition-table - * and register the partitions with MTD. - */ - -static int __init -init_axis_flash(void) -{ - int pidx = 0; - struct partitiontable_head *ptable_head; - struct partitiontable_entry *ptable; - int use_default_ptable = 1; /* Until proven otherwise */ - const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n"; - - printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n", - WINDOW_SIZE, FLASH_CACHED_ADDR); - -#ifdef CONFIG_MTD_CFI - mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map); -#endif - -#ifdef CONFIG_MTD_AMDSTD - if (!mymtd) { - mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map); - } -#endif - - if(!mymtd) { - printk("%s: No flash chip found!\n", axis_map.name); - return -ENXIO; - } - - mymtd->module = THIS_MODULE; - - ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + - CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); - pidx++; /* first partition is always set to the default */ - - if ((ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size < - (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + - PARTITIONTABLE_END_MARKER_SIZE)) - && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + - ptable_head->size - - PARTITIONTABLE_END_MARKER_SIZE) - == PARTITIONTABLE_END_MARKER)) { - /* Looks like a start, sane length and end of a - * partition table, lets check csum etc. - */ - int ptable_ok = 0; - struct partitiontable_entry *max_addr = - (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head) + - ptable_head->size); - unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; - unsigned char *p; - unsigned long csum = 0; - - ptable = (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head)); - - /* Lets be PARANOID, and check the checksum. */ - p = (unsigned char*) ptable; - - while (p <= (unsigned char*)max_addr) { - csum += *p++; - csum += *p++; - csum += *p++; - csum += *p++; - } - /* printk(" total csum: 0x%08X 0x%08X\n", - csum, ptable_head->checksum); */ - ptable_ok = (csum == ptable_head->checksum); - - /* Read the entries and use/show the info. */ - printk(" Found %s partition table at 0x%08lX-0x%08lX.\n", - (ptable_ok ? "valid" : "invalid"), - (unsigned long)ptable_head, - (unsigned long)max_addr); - - /* We have found a working bootblock. Now read the - partition table. Scan the table. It ends when - there is 0xffffffff, that is, empty flash. */ - - while (ptable_ok - && ptable->offset != 0xffffffff - && ptable < max_addr - && pidx < MAX_PARTITIONS) { - - axis_partitions[pidx].offset = offset + ptable->offset; - axis_partitions[pidx].size = ptable->size; - - printk(pmsg, pidx, axis_partitions[pidx].offset, - axis_partitions[pidx].size); - pidx++; - ptable++; - } - use_default_ptable = !ptable_ok; - } - - if (use_default_ptable) { - printk(" Using default partition table\n"); - return add_mtd_partitions(mymtd, axis_default_partitions, - NUM_DEFAULT_PARTITIONS); - } else { - if (romfs_in_flash) { - axis_partitions[pidx].name = "romfs"; - axis_partitions[pidx].size = romfs_length; - axis_partitions[pidx].offset = romfs_start - - FLASH_CACHED_ADDR; - axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; - - printk(" Adding readonly partition for romfs image:\n"); - printk(pmsg, pidx, axis_partitions[pidx].offset, - axis_partitions[pidx].size); - pidx++; - } - return add_mtd_partitions(mymtd, axis_partitions, pidx); - } -} - -/* This adds the above to the kernels init-call chain */ - -module_init(init_axis_flash); - diff --git a/arch/cris/drivers/bluetooth/Makefile b/arch/cris/drivers/bluetooth/Makefile deleted file mode 100644 index b3cbffc6c1a..00000000000 --- a/arch/cris/drivers/bluetooth/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -include $(APPS)/Rules.elinux - -all: - -install: src/bluetooth.c include/btcommon.h - ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth - if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \ - echo '' >> ../Config.in; \ - echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \ - echo ' source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \ - echo 'fi' >> ../Config.in; \ - fi - if ! grep bluetooth/src/bt.o ../Makefile; then \ - perl -pi -e "s:include:obj-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src\n\ninclude:" ../Makefile; \ - fi - -clean: - -src/bluetooth.c: - @echo "You must install the OpenBT src directory before install can be done here!" - @exit 1 - -include/btcommon.h: - @echo "You must install the OpenBT include directory before install can be done here!" - @exit 1 diff --git a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c deleted file mode 100644 index 533e2738c46..00000000000 --- a/arch/cris/drivers/gpio.c +++ /dev/null @@ -1,460 +0,0 @@ -/* $Id: gpio.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $ - * - * Etrax general port I/O device - * - * Copyright (c) 1999, 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions, write) - * - * $Log: gpio.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.12 2001/11/12 19:42:15 pkj - * * Corrected return values from gpio_leds_ioctl(). - * * Fixed compiler warnings. - * - * Revision 1.11 2001/10/30 14:39:12 johana - * Added D() around gpio_write printk. - * - * Revision 1.10 2001/10/25 10:24:42 johana - * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast - * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB - * from ~60 seconds to 4 seconds). - * Added save_flags/cli/restore_flags in ioctl. - * - * Revision 1.9 2001/05/04 14:16:07 matsfg - * Corrected spelling error - * - * Revision 1.8 2001/04/27 13:55:26 matsfg - * Moved initioremap. - * Turns off all LEDS on init. - * Added support for shutdown and powerbutton. - * - * Revision 1.7 2001/04/04 13:30:08 matsfg - * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping - * - * Revision 1.6 2001/03/26 16:03:06 bjornw - * Needs linux/config.h - * - * Revision 1.5 2001/03/26 14:22:03 bjornw - * Namechange of some config options - * - * Revision 1.4 2001/02/27 13:52:48 bjornw - * malloc.h -> slab.h - * - * Revision 1.3 2001/01/24 15:06:48 bjornw - * gpio_wq correct type - * - * Revision 1.2 2001/01/18 16:07:30 bjornw - * 2.4 port - * - * Revision 1.1 2001/01/18 15:55:16 bjornw - * Verbatim copy of etraxgpio.c from elinux 2.0 added - * - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define GPIO_MAJOR 120 /* experimental MAJOR number */ - -#define D(x) - -static char gpio_name[] = "etrax gpio"; - -#if 0 -static wait_queue_head_t *gpio_wq; -#endif - -static int gpio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static ssize_t gpio_write(struct file * file, const char * buf, size_t count, - loff_t *off); -static int gpio_open(struct inode *inode, struct file *filp); -static int gpio_release(struct inode *inode, struct file *filp); -static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); - -/* private data per open() of this driver */ - -struct gpio_private { - struct gpio_private *next; - volatile unsigned char *port, *shadow; - volatile unsigned char *dir, *dir_shadow; - unsigned char changeable_dir; - unsigned char changeable_bits; - unsigned char highalarm, lowalarm; - unsigned char clk_mask; - unsigned char data_mask; - unsigned char write_msb; - wait_queue_head_t alarm_wq; - int minor; -}; - -/* linked list of alarms to check for */ - -static struct gpio_private *alarmlist = 0; - -#define NUM_PORTS 2 -static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA }; -static volatile unsigned char *shads[2] = { - &port_pa_data_shadow, &port_pb_data_shadow }; - -/* What direction bits that are user changeable 1=changeable*/ -#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR -#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 -#endif -#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR -#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 -#endif - -#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS -#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF -#endif -#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS -#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF -#endif - - -static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR, - CONFIG_ETRAX_PB_CHANGEABLE_DIR }; -static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS, - CONFIG_ETRAX_PB_CHANGEABLE_BITS }; - -static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR }; - -static volatile unsigned char *dir_shadow[2] = { - &port_pa_dir_shadow, &port_pb_dir_shadow }; - -#define LEDS 2 - -static unsigned int -gpio_poll(struct file *filp, - struct poll_table_struct *wait) -{ - /* TODO poll on alarms! */ -#if 0 - if (!ANYTHING_WANTED) { - D(printk("gpio_select sleeping task\n")); - select_wait(&gpio_wq, table); - return 0; - } - D(printk("gpio_select ready\n")); -#endif - return 1; -} - -static ssize_t gpio_write(struct file * file, const char * buf, size_t count, - loff_t *off) -{ - struct gpio_private *priv = (struct gpio_private *)file->private_data; - unsigned char data, clk_mask, data_mask, write_msb; - unsigned long flags; - ssize_t retval = count; - if (verify_area(VERIFY_READ, buf, count)) { - return -EFAULT; - } - clk_mask = priv->clk_mask; - data_mask = priv->data_mask; - /* It must have been configured using the IO_CFG_WRITE_MODE */ - /* Perhaps a better error code? */ - if (clk_mask == 0 || data_mask == 0) { - return -EPERM; - } - write_msb = priv->write_msb; - D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); - while (count--) { - int i; - data = *buf++; - if (priv->write_msb) { - for (i = 7; i >= 0;i--) { - save_flags(flags); cli(); - *priv->port = *priv->shadow &= ~clk_mask; - if (data & 1<port = *priv->shadow |= data_mask; - else - *priv->port = *priv->shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *priv->port = *priv->shadow |= clk_mask; - restore_flags(flags); - } - } else { - for (i = 0; i <= 7;i++) { - save_flags(flags); cli(); - *priv->port = *priv->shadow &= ~clk_mask; - if (data & 1<port = *priv->shadow |= data_mask; - else - *priv->port = *priv->shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *priv->port = *priv->shadow |= clk_mask; - restore_flags(flags); - } - } - } - return retval; -} - -static int -gpio_open(struct inode *inode, struct file *filp) -{ - struct gpio_private *priv; - int p = minor(inode->i_rdev); - - if (p >= NUM_PORTS && p != LEDS) - return -EINVAL; - - priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), - GFP_KERNEL); - - if (!priv) - return -ENOMEM; - - priv->minor = p; - - /* initialize the io/alarm struct and link it into our alarmlist */ - - priv->next = alarmlist; - alarmlist = priv; - priv->port = ports[p]; - priv->shadow = shads[p]; - - priv->changeable_dir = changeable_dir[p]; - priv->changeable_bits = changeable_bits[p]; - priv->dir = dir[p]; - priv->dir_shadow = dir_shadow[p]; - - priv->highalarm = 0; - priv->lowalarm = 0; - priv->clk_mask = 0; - priv->data_mask = 0; - init_waitqueue_head(&priv->alarm_wq); - - filp->private_data = (void *)priv; - - return 0; -} - -static int -gpio_release(struct inode *inode, struct file *filp) -{ - struct gpio_private *p = alarmlist; - struct gpio_private *todel = (struct gpio_private *)filp->private_data; - - /* unlink from alarmlist and free the private structure */ - - if (p == todel) { - alarmlist = todel->next; - } else { - while (p->next != todel) - p = p->next; - p->next = todel->next; - } - - kfree(todel); - - return 0; -} - -/* Main device API. ioctl's to read/set/clear bits, as well as to - * set alarms to wait for using a subsequent select(). - */ - -static int -gpio_leds_ioctl(unsigned int cmd, unsigned long arg); - -static int -gpio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - struct gpio_private *priv = (struct gpio_private *)file->private_data; - if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { - return -EINVAL; - } - - switch (_IOC_NR(cmd)) { - case IO_READBITS: - // read the port - return *priv->port; - case IO_SETBITS: - save_flags(flags); cli(); - // set changeable bits with a 1 in arg - *priv->port = *priv->shadow |= - ((unsigned char)arg & priv->changeable_bits); - restore_flags(flags); - break; - case IO_CLRBITS: - save_flags(flags); cli(); - // clear changeable bits with a 1 in arg - *priv->port = *priv->shadow &= - ~((unsigned char)arg & priv->changeable_bits); - restore_flags(flags); - break; - case IO_HIGHALARM: - // set alarm when bits with 1 in arg go high - priv->highalarm |= (unsigned char)arg; - break; - case IO_LOWALARM: - // set alarm when bits with 1 in arg go low - priv->lowalarm |= (unsigned char)arg; - break; - case IO_CLRALARM: - // clear alarm for bits with 1 in arg - priv->highalarm &= ~(unsigned char)arg; - priv->lowalarm &= ~(unsigned char)arg; - break; - case IO_READDIR: - /* Read direction 0=input 1=output */ - return *priv->dir_shadow; - case IO_SETINPUT: - save_flags(flags); cli(); - /* Set direction 0=unchanged 1=input */ - *priv->dir = *priv->dir_shadow &= - ~((unsigned char)arg & priv->changeable_dir); - restore_flags(flags); - return *priv->dir_shadow; - case IO_SETOUTPUT: - save_flags(flags); cli(); - /* Set direction 0=unchanged 1=output */ - *priv->dir = *priv->dir_shadow |= - ((unsigned char)arg & priv->changeable_dir); - restore_flags(flags); - return *priv->dir_shadow; - case IO_SHUTDOWN: - SOFT_SHUTDOWN(); - break; - case IO_GET_PWR_BT: -#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) - return (*R_PORT_G_DATA & - ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); -#else - return 0; -#endif - break; - case IO_CFG_WRITE_MODE: - priv->clk_mask = arg & 0xFF; - priv->data_mask = (arg >> 8) & 0xFF; - priv->write_msb = (arg >> 16) & 0x01; - /* Check if we're allowed to change the bits and - * the direction is correct - */ - if (!((priv->clk_mask & priv->changeable_bits) && - (priv->data_mask & priv->changeable_bits) && - (priv->clk_mask & *priv->dir_shadow) && - (priv->data_mask & *priv->dir_shadow))) - { - priv->clk_mask = 0; - priv->data_mask = 0; - return -EPERM; - } - break; - default: - if (priv->minor == LEDS) - return gpio_leds_ioctl(cmd, arg); - else - return -EINVAL; - } - - return 0; -} - -static int -gpio_leds_ioctl(unsigned int cmd, unsigned long arg) -{ - unsigned char green; - unsigned char red; - - switch (_IOC_NR(cmd)) { - case IO_LEDACTIVE_SET: - green = ((unsigned char) arg) & 1; - red = (((unsigned char) arg) >> 1) & 1; - LED_ACTIVE_SET_G(green); - LED_ACTIVE_SET_R(red); - break; - - case IO_LED_SETBIT: - LED_BIT_SET(arg); - break; - - case IO_LED_CLRBIT: - LED_BIT_CLR(arg); - break; - - default: - return -EINVAL; - } - - return 0; -} - -struct file_operations gpio_fops = { - .owner = THIS_MODULE, - .poll = gpio_poll, - .ioctl = gpio_ioctl, - .write = gpio_write, - .open = gpio_open, - .release = gpio_release, -}; - -/* main driver initialization routine, called from mem.c */ - -static __init int -gpio_init(void) -{ - extern void init_ioremap(void); - int res; -#if defined (CONFIG_ETRAX_CSP0_LEDS) - int i; -#endif - - /* do the formalities */ - - res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); - if (res < 0) { - printk(KERN_ERR "gpio: couldn't get a major number.\n"); - return res; - } - - /* Clear all leds */ -#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) - init_ioremap(); - LED_NETWORK_SET(0); - LED_ACTIVE_SET(0); - LED_DISK_READ(0); - LED_DISK_WRITE(0); - -#if defined (CONFIG_ETRAX_CSP0_LEDS) - for (i = 0; i < 32; i++) { - LED_BIT_SET(i); - } -#endif - -#endif - - printk("ETRAX 100LX GPIO driver v2.2, (c) 2001 Axis Communications AB\n"); - - return res; -} - -/* this makes sure that gpio_init is called during kernel boot */ - -module_init(gpio_init); diff --git a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c deleted file mode 100644 index 89ae840968e..00000000000 --- a/arch/cris/drivers/ide.c +++ /dev/null @@ -1,877 +0,0 @@ -/* $Id: ide.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - * - * Etrax specific IDE functions, like init and PIO-mode setting etc. - * Almost the entire ide.c is used for the rest of the Etrax ATA driver. - * Copyright (c) 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Mikael Starvik (pio setup stuff) - * - * $Log: ide.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.19 2001/05/09 12:53:16 johana - * Added #include - * - * Revision 1.18 2001/05/09 12:37:00 johana - * Use DMA_NBR macros from dma.h. - * - * Revision 1.17 2001/04/23 13:36:30 matsfg - * Changed CONFIG_IDE_DELAY to CONFIG_ETRAX_IDE_DELAY - * - * Revision 1.16 2001/04/05 08:30:07 matsfg - * Corrected cse1 and csp0 reset. - * - * Revision 1.15 2001/04/04 14:34:06 bjornw - * Re-instated code that mysteriously disappeared during review updates. - * - * Revision 1.14 2001/04/04 13:45:12 matsfg - * Calls REG_SHADOW_SET for cse1 reset so only the resetbit is affected - * - * Revision 1.13 2001/04/04 13:26:40 matsfg - * memmapping is done in init.c - * - * Revision 1.12 2001/04/04 11:37:56 markusl - * Updated according to review remarks - * - * Revision 1.11 2001/03/29 12:49:14 matsfg - * Changed check for ata_tot_size from >= to >. - * Sets sw_len to 0 if size is exactly 65536. - * - * Revision 1.10 2001/03/16 09:39:30 matsfg - * Support for reset on port CSP0 - * - * Revision 1.9 2001/03/01 13:11:18 bjornw - * 100 -> HZ - * - * Revision 1.8 2001/03/01 09:32:56 matsfg - * Moved IDE delay to a CONFIG-parameter instead - * - * Revision 1.7 2001/02/23 13:46:38 bjornw - * Spellling check - * - * Revision 1.6 2001/02/22 15:44:30 bjornw - * * Use ioremap when mapping the CSE1 memory-mapped reset-line for LX v2 - * * sw_len for a 65536 descriptor is 0, not 65536 - * * Express concern for G27 reset code - * - * Revision 1.5 2001/02/16 07:35:38 matsfg - * Now handles DMA request blocks between 64k and 128k by split into two descriptors. - * - * Revision 1.4 2001/01/10 21:14:32 bjornw - * Initialize hwif->ideproc, for the new way of handling ide_xxx_data - * - * Revision 1.3 2000/12/01 17:48:18 bjornw - * - atapi_output_bytes now uses DMA - * - dma_active check removed - the kernel does proper serializing and it had - * a race-condition anyway - * - ide_build_dmatable had a nameclash - * - re-added the RESET_DMA thingys because sometimes the interface can get - * stuck apparently - * - added ide_release_dma - * - * Revision 1.2 2000/11/29 17:31:29 bjornw - * 2.4 port - * - * - The "register addresses" stored in the hwif are now 32-bit fields that - * don't need to be shifted into correct positions in R_ATA_CTRL_DATA - * - PIO-mode detection temporarily disabled since ide-modes.c is not compiled - * - All DMA uses virt_to_phys conversions for DMA buffers and descriptor ptrs - * - Probably correct ide_dma_begin semantics in dmaproc now for ATAPI devices - * - Removed RESET_DMA when starting a new transfer - why was this necessary ? - * - Indentation fix - * - * - */ - -/* Regarding DMA: - * - * There are two forms of DMA - "DMA handshaking" between the interface and the drive, - * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's - * something built-in in the Etrax. However only some drives support the DMA-mode handshaking - * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the - * device can't do DMA handshaking for some stupid reason. We don't need to do that. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* number of Etrax DMA descriptors */ -#define MAX_DMA_DESCRS 64 - -#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET -/* address where the memory-mapped IDE reset bit lives, if used */ -static volatile unsigned long *reset_addr; -#endif - -#define LOWDB(x) -#define D(x) - -void OUT_BYTE(unsigned char data, ide_ioreg_t reg) { - LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg)); - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ - *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */ - while(!(*R_ATA_STATUS_DATA & - IO_MASK(R_ATA_STATUS_DATA, tr_rdy))); /* wait for transmitter ready */ -} - -unsigned char IN_BYTE(ide_ioreg_t reg) { - int status; - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ - *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */ - while(!((status = *R_ATA_STATUS_DATA) & - IO_MASK(R_ATA_STATUS_DATA, dav))); /* wait for available */ - LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg)); - return (unsigned char)status; /* data was in the lower 16 bits in the status reg */ -} - -/* PIO timing (in R_ATA_CONFIG) - * - * _____________________________ - * ADDRESS : ________/ - * - * _______________ - * DIOR : ____________/ \__________ - * - * _______________ - * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX - * - * - * DIOR is unbuffered while address and data is buffered. - * This creates two problems: - * 1. The DIOR pulse is to early (because it is unbuffered) - * 2. The rise time of DIOR is long - * - * There are at least three different plausible solutions - * 1. Use a pad capable of larger currents in Etrax - * 2. Use an external buffer - * 3. Make the strobe pulse longer - * - * Some of the strobe timings below are modified to compensate - * for this. This implies a slight performance decrease. - * - * THIS SHOULD NEVER BE CHANGED! - * - * TODO: Is this true for the latest LX boards still ? - */ - -#define ATA_DMA2_STROBE 4 -#define ATA_DMA2_HOLD 0 -#define ATA_DMA1_STROBE 4 -#define ATA_DMA1_HOLD 1 -#define ATA_DMA0_STROBE 12 -#define ATA_DMA0_HOLD 9 -#define ATA_PIO4_SETUP 1 -#define ATA_PIO4_STROBE 5 -#define ATA_PIO4_HOLD 0 -#define ATA_PIO3_SETUP 1 -#define ATA_PIO3_STROBE 5 -#define ATA_PIO3_HOLD 1 -#define ATA_PIO2_SETUP 1 -#define ATA_PIO2_STROBE 6 -#define ATA_PIO2_HOLD 2 -#define ATA_PIO1_SETUP 2 -#define ATA_PIO1_STROBE 11 -#define ATA_PIO1_HOLD 4 -#define ATA_PIO0_SETUP 4 -#define ATA_PIO0_STROBE 19 -#define ATA_PIO0_HOLD 4 - -static int e100_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq); -static void e100_ideproc (ide_ide_action_t func, struct ata_device *drive, - void *buffer, unsigned int length); - -/* - * good_dma_drives() lists the model names (from "hdparm -i") - * of drives which do not support mword2 DMA but which are - * known to work fine with this interface under Linux. - */ - -const char *good_dma_drives[] = {"Micropolis 2112A", - "CONNER CTMA 4000", - "CONNER CTT8000-A", - NULL}; - -static void tune_e100_ide(struct ata_device *drive, byte pio) -{ - unsigned long flags; - - pio = 4; - /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */ - - save_flags(flags); - cli(); - - /* set pio mode! */ - - switch(pio) { - case 0: - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) ); - break; - case 1: - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) ); - break; - case 2: - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) ); - break; - case 3: - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) ); - break; - case 4: - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); - break; - } - restore_flags(flags); -} - -void __init -init_e100_ide (void) -{ - volatile unsigned int dummy; - int h; - - printk("ide: ETRAX 100LX built-in ATA DMA controller\n"); - - /* first initialize the channel interface data */ - - for(h = 0; h < MAX_HWIFS; h++) { - struct ata_channel *hwif = &ide_hwifs[h]; - - hwif->chipset = ide_etrax100; - hwif->tuneproc = &tune_e100_ide; - hwif->udma = &e100_dmaproc; - hwif->ata_read = e100_ide_input_data; - hwif->ata_write = e100_ide_output_data; - hwif->atapi_read = e100_atapi_read; - hwif->atapi_write = e100_atapi_write; - } - /* actually reset and configure the etrax100 ide/ata interface */ - - /* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */ - - /* de-assert bus-reset */ -#ifdef CONFIG_ETRAX_IDE_PB7_RESET - port_pb_dir_shadow = port_pb_dir_shadow | - IO_STATE(R_PORT_PB_DIR, dir7, output); - *R_PORT_PB_DIR = port_pb_dir_shadow; - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1); -#endif -#ifdef CONFIG_ETRAX_IDE_G27_RESET - *R_PORT_G_DATA = 0; -#endif - - *R_ATA_CTRL_DATA = 0; - *R_ATA_TRANSFER_CNT = 0; - *R_ATA_CONFIG = 0; - - genconfig_shadow = (genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, dma2) & - ~IO_MASK(R_GEN_CONFIG, dma3) & - ~IO_MASK(R_GEN_CONFIG, ata)) | - ( IO_STATE( R_GEN_CONFIG, dma3, ata ) | - IO_STATE( R_GEN_CONFIG, dma2, ata ) | - IO_STATE( R_GEN_CONFIG, ata, select ) ); - - *R_GEN_CONFIG = genconfig_shadow; - -#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - init_ioremap(); - REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0); -#endif - -#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET - init_ioremap(); - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0); -#endif - - /* wait some */ - udelay(25); - -#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1); -#endif -#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1); -#endif -#ifdef CONFIG_ETRAX_IDE_G27_RESET - *R_PORT_G_DATA = 0; /* de-assert bus-reset */ -#endif - - /* make a dummy read to set the ata controller in a proper state */ - dummy = *R_ATA_STATUS_DATA; - - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); - - *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) | - IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) ); - - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/ - - *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | - IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); - - printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY); - - h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ); - while(time_before(jiffies, h)) ; - - /* reset the dma channels we will use */ - - RESET_DMA(ATA_TX_DMA_NBR); - RESET_DMA(ATA_RX_DMA_NBR); - WAIT_DMA(ATA_TX_DMA_NBR); - WAIT_DMA(ATA_RX_DMA_NBR); - -} - -static etrax_dma_descr mydescr; - -/* - * The following routines are mainly used by the ATAPI drivers. - * - * These routines will round up any request for an odd number of bytes, - * so if an odd bytecount is specified, be sure that there's at least one - * extra byte allocated for the buffer. - */ -static void -e100_atapi_read(struct ata_device *drive, void *buffer, unsigned int bytecount) -{ - ide_ioreg_t data_reg = IDE_DATA_REG; - - D(printk("atapi_read, dreg 0x%x, buffer 0x%x, count %d\n", - data_reg, buffer, bytecount)); - - if(bytecount & 1) { - printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); - bytecount++; /* to round off */ - } - - /* make sure the DMA channel is available */ - RESET_DMA(ATA_RX_DMA_NBR); - WAIT_DMA(ATA_RX_DMA_NBR); - - /* setup DMA descriptor */ - - mydescr.sw_len = bytecount; - mydescr.ctrl = d_eol; - mydescr.buf = virt_to_phys(buffer); - - /* start the dma channel */ - - *R_DMA_CH3_FIRST = virt_to_phys(&mydescr); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - /* initiate a multi word dma read using PIO handshaking */ - - *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); - - *R_ATA_CTRL_DATA = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, read) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - /* wait for completion */ - - LED_DISK_READ(1); - WAIT_DMA(ATA_RX_DMA_NBR); - LED_DISK_READ(0); - -#if 0 - /* old polled transfer code - * this should be moved into a new function that can do polled - * transfers if DMA is not available - */ - - /* initiate a multi word read */ - - *R_ATA_TRANSFER_CNT = wcount << 1; - - *R_ATA_CTRL_DATA = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, read) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - /* svinto has a latency until the busy bit actually is set */ - - nop(); nop(); - nop(); nop(); - nop(); nop(); - nop(); nop(); - nop(); nop(); - - /* unit should be busy during multi transfer */ - while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) { - while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav))) - status = *R_ATA_STATUS_DATA; - *ptr++ = (unsigned short)(status & 0xffff); - } -#endif -} - -static void -e100_atapi_write(struct ata_device *drive, void *buffer, unsigned int bytecount) -{ - ide_ioreg_t data_reg = IDE_DATA_REG; - - D(printk("atapi_write, dreg 0x%x, buffer 0x%x, count %d\n", - data_reg, buffer, bytecount)); - - if(bytecount & 1) { - printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); - bytecount++; - } - - /* make sure the DMA channel is available */ - RESET_DMA(ATA_TX_DMA_NBR); - WAIT_DMA(ATA_TX_DMA_NBR); - - /* setup DMA descriptor */ - - mydescr.sw_len = bytecount; - mydescr.ctrl = d_eol; - mydescr.buf = virt_to_phys(buffer); - - /* start the dma channel */ - - *R_DMA_CH2_FIRST = virt_to_phys(&mydescr); - *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - - /* initiate a multi word dma write using PIO handshaking */ - - *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1); - - *R_ATA_CTRL_DATA = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, write) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - /* wait for completion */ - - LED_DISK_WRITE(1); - WAIT_DMA(ATA_TX_DMA_NBR); - LED_DISK_WRITE(0); - -#if 0 - /* old polled write code - see comment in input_bytes */ - - /* wait for busy flag */ - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); - - /* initiate a multi word write */ - - *R_ATA_TRANSFER_CNT = bytecount >> 1; - - ctrl = data_reg | - IO_STATE(R_ATA_CTRL_DATA, rw, write) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | - IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - LED_DISK_WRITE(1); - - /* Etrax will set busy = 1 until the multi pio transfer has finished - * and tr_rdy = 1 after each succesful word transfer. - * When the last byte has been transferred Etrax will first set tr_tdy = 1 - * and then busy = 0 (not in the same cycle). If we read busy before it - * has been set to 0 we will think that we should transfer more bytes - * and then tr_rdy would be 0 forever. This is solved by checking busy - * in the inner loop. - */ - - do { - *R_ATA_CTRL_DATA = ctrl | *ptr++; - while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) && - (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))); - } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); - - LED_DISK_WRITE(0); -#endif - -} - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -static void -e100_ide_input_data (struct ata_device *drive, void *buffer, unsigned int wcount) -{ - e100_atapi_read(drive, buffer, wcount << 2); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -static void -e100_ide_output_data (struct ata_device *drive, void *buffer, unsigned int wcount) -{ - e100_atapi_write(drive, buffer, wcount << 2); -} - -/* we only have one DMA channel on the chip for ATA, so we can keep these statically */ -static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS]; -static unsigned int ata_tot_size; - - -/* - * This prepares a dma request. Returns 0 if all went okay, returns 1 - * otherwise. - */ - -static int e100_udma_new_table(struct ata_channel *ch, struct request *rq) -{ - struct buffer_head *bh = rq->bh; - unsigned long size, addr; - unsigned int count = 0; - - ata_tot_size = 0; - - do { - /* - * Determine addr and size of next buffer area. We assume that - * individual virtual buffers are always composed linearly in - * physical memory. For example, we assume that any 8kB buffer - * is always composed of two adjacent physical 4kB pages rather - * than two possibly non-adjacent physical 4kB pages. - */ - if (bh == NULL) { /* paging and tape requests have (rq->bh == NULL) */ - addr = virt_to_phys (rq->buffer); - size = rq->nr_sectors << 9; - } else { - /* group sequential buffers into one large buffer */ - addr = virt_to_phys (bh->b_data); - size = bh->b_size; - while ((bh = bh->b_reqnext) != NULL) { - if ((addr + size) != virt_to_phys (bh->b_data)) - break; - size += bh->b_size; - } - } - - /* did we run out of descriptors? */ - - if(count >= MAX_DMA_DESCRS) { - printk("%s: too few DMA descriptors\n", ch->name); - return 1; - } - - /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more - than 65536 words per transfer, so in that case we need to either - 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with - the descriptors, or - 2) simply do the request here, and get dma_intr to only ide_end_request on - those blocks that were actually set-up for transfer. - */ - - if(ata_tot_size + size > 131072) { - printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, size); - return 1; - } - - /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle - size > 131072 only one split is necessary */ - - if(size > 65536) { - /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ - ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ - ata_descrs[count].ctrl = 0; - ata_descrs[count].buf = addr; - ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); - count++; - ata_tot_size += 65536; - /* size and addr should refere to not handled data */ - size -= 65536; - addr += 65536; - } - /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ - if(size == 65536) { - ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */ - } - else { - ata_descrs[count].sw_len = size; - } - ata_descrs[count].ctrl = 0; - ata_descrs[count].buf = addr; - ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); - count++; - ata_tot_size += size; - - } while (bh != NULL); - - if (count) { - /* set the end-of-list flag on the last descriptor */ - ata_descrs[count - 1].ctrl |= d_eol; - /* return and say all is ok */ - return 0; - } - - printk("%s: empty DMA table?\n", ch->name); - return 1; /* let the PIO routines handle this weirdness */ -} - -static int config_drive_for_dma (struct ata_device *drive) -{ - const char **list; - struct hd_driveid *id = drive->id; - - if (id && (id->capability & 1)) { - /* Enable DMA on any drive that supports mword2 DMA */ - if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) { - drive->using_dma = 1; - return 0; /* DMA enabled */ - } - - /* Consult the list of known "good" drives */ - list = good_dma_drives; - while (*list) { - if (!strcmp(*list++,id->model)) { - drive->using_dma = 1; - return 0; /* DMA enabled */ - } - } - } - return 1; /* DMA not enabled */ -} - -/* - * etrax_dma_intr() is the handler for disk read/write DMA interrupts - */ -static ide_startstop_t etrax_dma_intr(struct ata_device *drive, struct request *rq) -{ - int i, dma_stat; - - LED_DISK_READ(0); - LED_DISK_WRITE(0); - - dma_stat = drive->channel->udma(ide_dma_end, drive, rq); - /* get drive status */ - if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) { - if (!dma_stat) { - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(drive, rq, 1); - } - return ATA_OP_FINISHED; - } - printk("%s: bad DMA status\n", drive->name); - } - return ata_error(drive, rq, __FUNCTION__); -} - -/* - * e100_dmaproc() initiates/aborts DMA read/write operations on a drive. - * - * The caller is assumed to have selected the drive and programmed the drive's - * sector address using CHS or LBA. All that remains is to prepare for DMA - * and then issue the actual read/write DMA/PIO command to the drive. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * ide_dma_begin afterwards. - * - * Returns 0 if all went well. - * Returns 1 if DMA read/write could not be started, in which case - * the caller should revert to PIO for the current request. - */ - -static int e100_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) -{ - static unsigned int reading; /* static to support ide_dma_begin semantics */ - int atapi = 0; - - D(printk("e100_dmaproc func %d\n", func)); - - switch (func) { - case ide_dma_verbose: - return 0; - case ide_dma_check: - return config_drive_for_dma (drive); - case ide_dma_off: - case ide_dma_off_quietly: - /* ok.. we don't really need to do anything I think. */ - return 0; - case ide_dma_write: - reading = 0; - break; - case ide_dma_read: - reading = 1; - break; - case ide_dma_begin: - /* begin DMA, used by ATAPI devices which want to issue the - * appropriate IDE command themselves. - * - * they have already called ide_dma_read/write to set the - * static reading flag, now they call ide_dma_begin to do - * the real stuff. we tell our code below not to issue - * any IDE commands itself and jump into it. - */ - atapi++; - goto dma_begin; - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - /* TODO: check if something went wrong with the DMA */ - return 0; - - default: - printk("e100_dmaproc: unsupported func %d\n", func); - return 1; - } - - /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction - * then they call ide_dma_begin after they have issued the appropriate drive command - * themselves to actually start the chipset DMA. so we just return here if we're - * not a diskdrive. - */ - - if (drive->type != ATA_DISK) - return 0; - - dma_begin: - - if(reading) { - - RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_RX_DMA_NBR); - - /* set up the Etrax DMA descriptors */ - - if(e100_udma_new_table(drive->channel, rq)) - return 1; - - if(!atapi) { - /* set the irq handler which will finish the request when DMA is done */ - ata_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - - /* issue cmd to drive */ - OUT_BYTE(WIN_READDMA, IDE_COMMAND_REG); - } - - /* begin DMA */ - *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - /* initiate a multi word dma read using DMA handshaking */ - - *R_ATA_TRANSFER_CNT = - IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); - - *R_ATA_CTRL_DATA = - IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | - IO_STATE(R_ATA_CTRL_DATA, rw, read) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - LED_DISK_READ(1); - - D(printk("dma read of %d bytes.\n", ata_tot_size)); - - } else { - /* writing */ - - RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_TX_DMA_NBR); - - /* set up the Etrax DMA descriptors */ - - if(e100_udma_new_table(drive->channel, rq)) - return 1; - - if(!atapi) { - /* set the irq handler which will finish the request when DMA is done */ - ata_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - - /* issue cmd to drive */ - OUT_BYTE(WIN_WRITEDMA, IDE_COMMAND_REG); - } - - /* begin DMA */ - *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs); - *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - - /* initiate a multi word dma write using DMA handshaking */ - *R_ATA_TRANSFER_CNT = - IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1); - - *R_ATA_CTRL_DATA = - IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | - IO_STATE(R_ATA_CTRL_DATA, rw, write) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); - - LED_DISK_WRITE(1); - - D(printk("dma write of %d bytes.\n", ata_tot_size)); - } - - /* DMA started successfully */ - return 0; -} - -/* ide.c calls this, but we don't need to do anything particular */ - -/* Dear maintainer of this architecture please note that it would be a little - * more clever :-) to put this up into some header as static inline, so the - * spurious code below would just vanish. - * - * --- Marcin Dalecki - */ - -void ide_release_dma(struct ata_channel *ch) -{ - /* empty */ -} diff --git a/arch/cris/drivers/lpslave/Makefile b/arch/cris/drivers/lpslave/Makefile deleted file mode 100644 index 6d7982db01e..00000000000 --- a/arch/cris/drivers/lpslave/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for parallel port slave drivers -# - -obj-y = e100lpslavenet.o e100lpslave_code.o - -e100lpslave_code.o: e100lpslave.o e100lpslaveld - $(CROSS_COMPILE)ld -qmagic -Te100lpslaveld e100lpslave.o -o e100lpslave - $(CROSS_COMPILE)objcopy -O binary --remove-section=.data --remove-section=.bss e100lpslave e100lpslave.text - $(CROSS_COMPILE)objcopy -O binary --remove-section=.text --remove-section=.bss e100lpslave e100lpslave.data - cat e100lpslave.text e100lpslave.data |\ - ./bintocarr.pl e100lpslaveprog |\ - $(CC) $(CFLAGS) -pipe -o e100lpslave_code.o -c -x c - - ls -l e100lpslave.text e100lpslave.data - rm -f e100lpslave e100lpslave.text e100lpslave.data diff --git a/arch/cris/drivers/lpslave/bintocarr.pl b/arch/cris/drivers/lpslave/bintocarr.pl deleted file mode 100644 index c03dd8b718b..00000000000 --- a/arch/cris/drivers/lpslave/bintocarr.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# $Id: bintocarr.pl,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ -# Copy of mkjulbin.pl made by Olof -# convert a binary stdin to a C-file containing a char array of the input -# first argument is the symbol name - -$symbol = shift @ARGV; - -print "#include \n\n"; -#print "unsigned char $symbol", "[] __initdata = {\n"; -print "unsigned char $symbol", "[] = {\n"; - -my $char; - -$bcount = 0; - -while(read STDIN, $char, 1) { - printf("0x%x, ", ord($char)); - $bcount++; - if(!($bcount % 16)) { - print "\n"; - } -} - -print "\n};\n"; - -$lensymb = ("_" . ($symbol . "_length")); - -print "__asm__(\"\\t.globl $lensymb\\n$lensymb = $bcount\\n\");\n"; - diff --git a/arch/cris/drivers/lpslave/e100lpslave.README b/arch/cris/drivers/lpslave/e100lpslave.README deleted file mode 100644 index eb580a9d2da..00000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.README +++ /dev/null @@ -1,54 +0,0 @@ -***** MODIFICATIONS -To use a 5600 as a slave device it has to somewhat modified. -This has to be done on a 5600 (art no 16144 R2) to automatically set it to parallel port boot mode: - -1) -Close to the LPT1 connector there are two resistors, between the "Pulse" inductor and -the LS245. The one closest to the LS245 is a 4k7 pull up (R105). Remove it. - -2) -Between the other "Pulse" inductor and Etrax there is a black 5-pin inverter -(D15). Short connectors 2 and 3 with a solder blob. - - -***** PINOUT -To use this driver use cables connected like this: -DSUB25-Male DSUB25Male - -1 10 -2-9 2-9 -10 1 -11 14 -12 18 -13 NC -14 11 -15 NC -16 NC -17 NC -18 12 -19 NC -20-25 20-25 - -Thus the cables are symmetrical with most cables straight through, -some crossed (1-10, 11-14 and 12-18) -and some Not connected (NC 13,15,16,17 and 19). - - -******* Only for reference -To ease the use of flat-cable connectors, here are the notes of wich wires to cross and cut with pin 1 being cable 1: -Cross: -1 19 -2 21 -10 23 -Cut: -4 -6 -8 -12 -25 - -jonas.dellenvall@axis.com - - - - diff --git a/arch/cris/drivers/lpslave/e100lpslave.S b/arch/cris/drivers/lpslave/e100lpslave.S deleted file mode 100644 index 44efe0771fc..00000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.S +++ /dev/null @@ -1,429 +0,0 @@ - ;; $Id: e100lpslave.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - ;; - ;; Etrax100 slave network<->parport forwarder - ;; - ;; Copyright (c) 1999 Bjorn Wesen, Axis Communications AB - ;; - ;; We got 784 bytes (par loader size) to do DMA forwarding - ;; between DMA0/1 (ethernet) and DMA3/4 (par port 0 RX/1 TX) - ;; - -#include -#if 0 -#define ASSEMBLER_MACROS_ONLY -#endif -#include - -#define BUFSIZE 0x600 - - ;; R_IRQ_READ2 - -#define DMA1EOPBIT 3 -#define DMA0EOPBIT 1 -#define DMA3EOPBIT 7 -#define DMA4DESCBIT 8 - - ;; R_IRQ_READ0 - -#define PAR0ECPCMDBIT 11 - - ;; get host CMDs - -#include "e100lpslave.h" - -start: - ;; disable interrupts. we are not going to use them at all. - - di - - ;; setup DMA connections and port configuration - - movu.w 0x84, r0 ; DMA2/3/4/5 to par ports - move.d r0, [R_GEN_CONFIG] - - ;; setup port PA dirs and turn on the LED to show were alive - - movu.w 0x0cfb, r0 ; PA2-PA3 out, PA2 inactive - move.d r0, [R_PORT_PA_SET] - - ;; enable MDIO output pin - moveq IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable), r0 - move.d r0, [R_NETWORK_MGM_CTRL] - - ;; accept broadcast frames, and enable station address 0 - moveq IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | \ - IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable), r0 - move.d r0, [R_NETWORK_REC_CONFIG] - - ;; use MII CLK mode, and enable the controller - moveq IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | \ - IO_STATE(R_NETWORK_GEN_CONFIG, enable, on), r0 - move.d r0, [R_NETWORK_GEN_CONFIG] - - move.d IO_STATE(R_PAR0_CONFIG, ioe, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iseli, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | \ - IO_STATE(R_PAR0_CONFIG, istrb, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iinit, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iperr, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iack, noninv) | \ - IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | \ - IO_STATE(R_PAR0_CONFIG, ifault, noninv) | \ - IO_STATE(R_PAR0_CONFIG, isel, noninv) | \ - IO_STATE(R_PAR0_CONFIG, dma, enable) | \ - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | \ - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | \ - IO_STATE(R_PAR0_CONFIG, enable, on) | \ - IO_STATE(R_PAR0_CONFIG, force, on) | \ - IO_STATE(R_PAR0_CONFIG, mode, ecp_rev), r0 ; Reverse ECP - PAR0 is RX - - move.d r0, [R_PAR0_CONFIG] - - move.d IO_STATE(R_PAR1_CONFIG, ioe, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iseli, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | \ - IO_STATE(R_PAR1_CONFIG, istrb, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iinit, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iperr, inv) | \ - IO_STATE(R_PAR1_CONFIG, iack, noninv) | \ - IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | \ - IO_STATE(R_PAR1_CONFIG, ifault, noninv) | \ - IO_STATE(R_PAR1_CONFIG, isel, noninv) | \ - IO_STATE(R_PAR1_CONFIG, dma, enable) | \ - IO_STATE(R_PAR1_CONFIG, rle_in, disable) | \ - IO_STATE(R_PAR1_CONFIG, rle_out, disable) | \ - IO_STATE(R_PAR1_CONFIG, enable, on) | \ - IO_STATE(R_PAR1_CONFIG, force, on) | \ - IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd), r0 ; Forward ECP - PAR1 is TX - - move.d r0, [R_PAR1_CONFIG] - - moveq IO_FIELD(R_PAR1_DELAY, setup, 0), r0 ; setup time of value * 160 + 20 == 20 ns - move.d r0, [R_PAR1_DELAY] - - ;; we got four descriptors, that can be active at the same time: - ;; 1) from network - ;; 2) to parport - ;; 3) from parport - ;; 4) to network - ;; - ;; we got four buffers, each can hold a max packet (we use 1536 bytes) - ;; buffers 1 and 2 are used from network to parport, while - ;; buffers 3 and 4 are used from parport to network. - ;; - ;; a double buffering scheme is used, so that new data can be read - ;; into a buffer pair while the last data is written out from the - ;; last buffer. if the read buffer is done before the write buffer, - ;; the reading will halt until the writing is done, at which point - ;; writing starts from the newly read and reading can start with - ;; the newly written. - ;; - - move.d R_DMA_CH0_FIRST, r1 ; we use this as base for subsequent DMA ops - moveq IO_STATE(R_DMA_CH1_CMD, cmd, start), r6 - move.d FN1desc, r7 - move.d R_IRQ_READ0, r9 - - ;; start receiving from network - - jsr startdmaFPTN - jsr startdmaFNTP - - - - ;; ------------------- MAIN LOOP - - ;; IRQ bits: parport rcv is par0_ecp_cmd, then dma3_eop - ;; network rcv is dma1_eop - ;; parport tx is dma4_desc - ;; network tx is dma0_eop - -mainloop: - - ;; ------- first handle the parport -> network link - - ;; check if we got something from the parport - - move.d [r9], r0 ; r0 <- *R_IRQ_READ0 - btstq PAR0ECPCMDBIT, r0 - bpl noparecp - nop - - ;; ack it by reading PAR0_STATUS_DATA - - move.d [R_PAR0_STATUS_DATA], r0 - - ;; trigger EOP on DMA3 (par0 incoming channel) - - moveq IO_STATE(R_SET_EOP, ch3_eop, set), r0 - move.d r0, [R_SET_EOP] - -noparecp: - - ;; if we simultaneously have parport rx EOP and - ;; network TX eop, we can swap buffers and start a new RX/TX - - move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 - btstq DMA3EOPBIT, r0 ; check parport rx - bpl noswap1 - btstq DMA0EOPBIT, r0 ; check network tx - bpl noswap1 - nop - - ;; prepare to swap buffer ptrs (FN3b <-> TN4b) - - move.d [r4 = r7 + 56], r0; FP3b - move.d [r3 = r7 + 72], r2; TN4b - - ;; but first check if this was a Host Command Packet - - move.d [r0], r5 ; r5 <- first 4 bytes in PAR-received packet - bne handle_command ; if non-zero, it was a host command - addq 4, r0 ; skip command (in delay slot - handle_command requires this) - move.d r0, [r3] ; write to To Network descriptor - subq 4, r2 ; undo the skipping done last swap - move.d r2, [r4] ; write to From Parport descriptor - - ;; clear the interrupts - - moveq IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do), r0 - move.b r0, [r1 + (R_DMA_CH0_CLR_INTR - R_DMA_CH0_FIRST)] - move.b r0, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] - - ;; copy received length to outgoing network length - - move.w [r7 + 60], r0 ; FPhlen - subq 4, r0 ; skip command - move.w r0, [r7 + 64] ; TN4desc - - ;; restart DMAs - - jsr startdmaFPTN - -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS -#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) - ;; Turn off the LED signaling an outgoing network packet - movu.b [LEDOff], r0 -#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) - ;; Light the LED signaling an outgoing network packet - movu.b [LEDAmber], r0 -#else -#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -#endif - move.b r0, [R_PORT_PA_DATA] - move.d 0x00011000, r0 - move.d r0,[LEDCount] -#endif - -noswap1: - ;; ----- now check the network -> parport link - - - ;; if we simultaneously have network rx EOP and - ;; parport TX desc, we can swap buffers and start a new RX/TX - - move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 - btstq DMA1EOPBIT, r0 ; check network rx - bpl noswap2 - btstq DMA4DESCBIT, r0 ; check parport tx - bpl noswap2 - nop - - ;; prepare to swap buffer ptrs (FP1b <-> TP2b) - - move.d [r4 = r7 + 8], r0; FN1b - move.d [r3 = r7 + 24], r2; TP2b - move.d r0, [r3] ; write to To Parport descriptor - move.d r2, [r4] ; write to From Network descriptor - - ;; clear the interrupts - - moveq IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | \ - IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do), r0 - move.b r0, [r1 + (R_DMA_CH1_CLR_INTR - R_DMA_CH0_FIRST)] - move.b r0, [r1 + (R_DMA_CH4_CLR_INTR - R_DMA_CH0_FIRST)] - - ;; copy received network length to outgoing parport length - - move.w [r7 + 12], r0 ; FNhlen - move.w r0, [r7 + 16] ; TP2desc - - ;; restart DMAs - - jsr startdmaFNTP -#if 0 -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - ;; Light the LED signaling an incoming networkpacket - movu.b 0xFB, r0 - move.b r0, [R_PORT_PA_DATA] - move.d 0x00010000, r0 - move.d r0,[LEDCount] -#endif -#endif - -noswap2: -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - - ;; Count down LED counter, and turn off the network LED if required - move.d [LEDCount], r0 - beq mainloop - nop - - subq 1, r0 - move.d r0, [LEDCount] - bne mainloop - nop - -#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) - ;; Light the network LED , and start over the main loop - movu.b [LEDAmber], r0 -#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) - ;; Turn off the network LED, and start over the main loop - movu.b [LEDOff], r0 -#else -#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -#endif - move.b r0, [R_PORT_PA_DATA] -#endif - - ba mainloop - nop - - ;; --- some useful subroutines. - -handle_command: - ;; handle command. we also need to clear the PAR0 RX EOP IRQ, and - ;; restart the PAR0 dma. command is in R5, packet after cmd is in R0 - - moveq IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do), r2 - move.b r2, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] - - cmpq HOST_CMD_SETMAC, r5 - bne no_setmac - nop - - ;; copy station address (6 bytes) from packet to hardware - - move.d [r0+], r2 - move.d R_NETWORK_SA_0, r3 - move.d r2, [r3] - move.w [r0], r2 - move.w r2, [r3 + 4] - -no_setmac: - move noswap1, SRP - ba startdmaFP - nop - - ;; start DMAs, from parport and to network - -startdmaFPTN: - - ;; start transmitting to the network (CH0) - - move.d TN4desc, r8 - move.d r8, [r1] ; TN4desc -> FIRST0 - move.b r6, [r1 + (R_DMA_CH0_CMD - R_DMA_CH0_FIRST)] ; start -> CMD0 - -startdmaFP: - - ;; start receiving from parport (CH3) - - move.d FP3desc, r8 - move.d r8, [r1 + (R_DMA_CH3_FIRST - R_DMA_CH0_FIRST)] ; FP3desc -> FIRST3 - move.b r6, [r1 + (R_DMA_CH3_CMD - R_DMA_CH0_FIRST)] ; start -> CMD3 - - ret - nop - - ;; start DMAs, from network and to parport - -startdmaFNTP: - - ;; start transmitting to the parport (CH4) - - move.d TP2desc, r8 - move.d r8, [r1 + (R_DMA_CH4_FIRST - R_DMA_CH0_FIRST)] ; TP2desc -> FIRST4 - move.b r6, [r1 + (R_DMA_CH4_CMD - R_DMA_CH0_FIRST)] ; start -> CMD4 - - ;; start receiving from network (CH1) (r7 already contains FN1desc) - - move.d r7, [r1 + (R_DMA_CH1_FIRST - R_DMA_CH0_FIRST)] ; FN1desc -> FIRST1 - move.b r6, [r1 + (R_DMA_CH1_CMD - R_DMA_CH0_FIRST)] ; start -> CMD1 - - ret - nop - - ;; --- DMA descriptors - each descriptor is 4 longwords (16 bytes) - ;; DONT MOVE THESE AROUND. Due to the as/ld "hole-in-the-head", - ;; we cant write stuff like (TP2b - TP2desc) but the offsets - ;; have to be hardcoded. - - .data - - ;; 0 from network -FN1desc: - .word BUFSIZE ; sw_len - .word 0x0001 ; ctrl, d_eol is only flag we need - .dword 0 ; next -FN1b: .dword buffers ; buffer 1 8 - .word 0 ; hw_len - .word 0 ; status - - ;; 16 to parport -TP2desc: - .word 2 ; sw_len, filled in by code - .word 0x0004 ; ctrl, d_wait because ecp cmd in next - .dword TP2desc2 ; next -TP2b: .dword buffers + BUFSIZE ; buffer 2 24 - .word 0 ; hw_len - .word 0 ; status - - ;; 32 to parport second descriptor, for the ECP command -TP2desc2: - .word 0x0001 ; sw_len, 1 byte (ecp command) - .word 0x0019 ; ctrl, d_ecp | d_eol | d_int - .dword 0 ; next - .dword TP2desc2 ; buffer, dont care - .word 0 ; hw_len - .word 0 ; status - - ;; 48 from parport -FP3desc: - .word BUFSIZE ; sw_len - .word 0x0001 ; ctrl, d_eol is only flag we need - .dword 0 ; next -FP3b: .dword buffers + BUFSIZE * 2 ; 56 buffer 3 -FPhlen: .word 0 ; 60 hw_len - .word 0 ; status - - ;; 64 to network -TN4desc: - .word 2 ; sw_len, filled in by code - .word 0x0007 ; ctrl, d_eop | d_eol | d_wait - .dword 0 ; next -TN4b: .dword buffers + BUFSIZE * 3 + 4 ; 72 buffer 4 (the +4 is to offset the anti-skipping) - .word 0 ; hw_len - .word 0 ; status - -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS -LEDCount: - .dword 0 -LEDOff: - .word 0xff -LEDGreen: - .word 0xfb -LEDRed: - .word 0xf7 -LEDAmber: - .word 0xf3 -LED: - .word 0xf7 -#endif - - ;; after the prog we put the buffers. not in the asm program, we just use - ;; the address generated - -buffers: - - ;; END diff --git a/arch/cris/drivers/lpslave/e100lpslave.h b/arch/cris/drivers/lpslave/e100lpslave.h deleted file mode 100644 index 7c9cfd91e36..00000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.h +++ /dev/null @@ -1,2 +0,0 @@ -#define HOST_CMD_SENDPACK 0 -#define HOST_CMD_SETMAC 1 diff --git a/arch/cris/drivers/lpslave/e100lpslaveld b/arch/cris/drivers/lpslave/e100lpslaveld deleted file mode 100644 index 4d51ff40ef6..00000000000 --- a/arch/cris/drivers/lpslave/e100lpslaveld +++ /dev/null @@ -1,22 +0,0 @@ -MEMORY - { - cache : ORIGIN = 0x380000f0, - LENGTH = 784 - } - -SECTIONS -{ - .text : - { - *(.text) - } > cache - .data : - { - *(.data) - *(COMMON) - } > cache - .bss : - { - *(.bss) - } > cache -} diff --git a/arch/cris/drivers/lpslave/e100lpslavenet.c b/arch/cris/drivers/lpslave/e100lpslavenet.c deleted file mode 100644 index 29e98e46c32..00000000000 --- a/arch/cris/drivers/lpslave/e100lpslavenet.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* $Id: e100lpslavenet.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - * - * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller. - * - * Copyright (c) 1998-2001 Axis Communications AB. - * - * The outline of this driver comes from skeleton.c. - * - * $Log: e100lpslavenet.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.4 2001/06/21 16:55:26 olof - * Minimized par port setup time to gain bandwidth - * - * Revision 1.3 2001/06/21 15:49:02 olof - * Removed setting of default MAC address - * - * Revision 1.2 2001/06/11 15:39:52 olof - * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave. - * - * Revision 1.1 2001/06/06 08:56:26 olof - * Added support for slave Etrax defined by CONFIG_ETRAX_ETHERNET_LPSLAVE - * - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include /* DMA and register descriptions */ -#include /* LED_* I/O functions */ -#include -#include -#include -#include - -#include "e100lpslave.h" - -/* #define ETHDEBUG */ -#define D(x) - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static const char* cardname = "Etrax 100LX ethernet slave controller"; - -/* A default ethernet address. Highlevel SW will set the real one later */ - -static struct sockaddr default_mac = { - 0, - { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } -}; - -/* Information that need to be kept for each board. */ -struct net_local { - struct net_device_stats stats; - - /* Tx control lock. This protects the transmit buffer ring - * state along with the "tx full" state of the driver. This - * means all netif_queue flow control actions are protected - * by this lock as well. - */ - spinlock_t lock; -}; - -/* Dma descriptors etc. */ - -#define RX_BUF_SIZE 32768 -#define ETHER_HEAD_LEN 14 - -#define PAR0_ECP_IRQ_NBR 4 - -#define RX_DESC_BUF_SIZE 256 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ - RX_DESC_BUF_SIZE) - -/* Size of slave etrax boot image */ -#define ETRAX_PAR_BOOT_LENGTH 784 - -static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to - to be processed */ -static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ -static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ - -static unsigned char RxBuf[RX_BUF_SIZE]; - -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); -static etrax_dma_descr TxDescList[3] __attribute__ ((aligned(4))); - /* host command, data, bogus ECP command */ - -static struct sk_buff *tx_skb; - -/* Index to functions, as function prototypes. */ - -static int etrax_ethernet_lpslave_init(struct net_device *dev); - -static int e100_open(struct net_device *dev); -static int e100_set_mac_address(struct net_device *dev, void *addr); -static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void ecp_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100_rx(struct net_device *dev); -static int e100_close(struct net_device *dev); -static struct net_device_stats *e100_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length); -static void update_rx_stats(struct net_device_stats *); -static void update_tx_stats(struct net_device_stats *); -static void e100_reset_transceiver(void); - -static void boot_slave(unsigned char *code); - -#ifdef ETHDEBUG -static void dump_parport_status(void); -#endif - -#define tx_done(dev) (*R_DMA_CH0_CMD == 0) - -static unsigned long host_command; -extern unsigned char e100lpslaveprog; - -/* - * This driver uses PAR0 to recevice data from slave ETRAX and PAR1 to boot - * and send data to slave ETRAX. - * Used ETRAX100 DMAchannels with corresponding IRQ: - * PAR0 RX : DMA3 - IRQ 19 - * PAR1 TX : DMA4 - IRQ 20 - * IRQ 4 is used to detect ECP commands from slave ETRAX - * - * NOTE! PAR0 and PAR1 shares DMA and IRQ numbers with SER2 and SER3 - */ - - -/* - * Check for a network adaptor of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - */ -static int __init -etrax_ethernet_lpslave_init(void) -{ - struct net_device *dev; - int i, err; - int anOffset = 0; - - printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n"); - - dev = alloc_etherdev(sizeof(struct net_lock)); - if (!dev) - return -ENOMEM; - - dev->base_addr = 2; - - /* now setup our etrax specific stuff */ - - dev->irq = DMA3_RX_IRQ_NBR; /* we really use DMATX as well... */ - dev->dma = PAR0_RX_DMA_NBR; - - /* fill in our handlers so the network layer can talk to us in the future */ - - dev->open = e100_open; - dev->hard_start_xmit = e100_send_packet; - dev->stop = e100_close; - dev->get_stats = e100_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->set_mac_address = e100_set_mac_address; - - /* Initialise the list of Etrax DMA-descriptors */ - - /* Initialise receive descriptors */ - - for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].ctrl = 0; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - anOffset += RX_DESC_BUF_SIZE; - } - - RxDescList[i].ctrl = d_eol; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - - /* Initialise initial pointers */ - - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - - /* setup some TX descriptor data */ - - TxDescList[0].sw_len = 4; - TxDescList[0].ctrl = 0; - TxDescList[0].buf = virt_to_phys(&host_command); - TxDescList[0].next = virt_to_phys(&TxDescList[1]); - - err = register_netdev(dev); - if (err) - kfree(dev); - - return err; -} - -/* set MAC address of the interface. called from the core after a - * SIOCSIFADDR ioctl, and from the bootup above. - */ - -static int -e100_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - int i; - - /* remember it */ - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - /* Write it to the hardware. - * Note the way the address is wrapped: - * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); - * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); - */ - - tx_skb = 0; - e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); - - /* show it in the log as well */ - - printk("%s: changed MAC to ", dev->name); - - for (i = 0; i < 5; i++) - printk("%02X:", dev->dev_addr[i]); - - printk("%02X\n", dev->dev_addr[i]); - - return 0; -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ - -static int -e100_open(struct net_device *dev) -{ - unsigned long flags; - - /* configure the PAR0 (RX) and PAR1 (TX) ports - * - * perror is nAckReverse, which must be 1 at the TX side, - * and 0 at the RX side - * - * select is XFlag, which must be 1 at both sides - */ -#ifdef ETHDEBUG - printk("Setting up PAR ports\n"); -#endif - *R_PAR0_CONFIG = - /* We do not have an external buffer, don't care */ - IO_STATE(R_PAR0_CONFIG, ioe, noninv) | - /* Not connected, don't care */ - IO_STATE(R_PAR0_CONFIG, iseli, noninv) | - /* iautofd is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | - /* Not used in reverse direction, don't care */ - IO_STATE(R_PAR0_CONFIG, istrb, noninv) | - /* Not connected, don't care */ - IO_STATE(R_PAR0_CONFIG, iinit, noninv) | - /* perror is GND and reverse wants 0, noninv */ - IO_STATE(R_PAR0_CONFIG, iperr, noninv) | - /* ack is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, iack, noninv) | - /* busy is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | - /* fault is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, ifault, noninv) | - /* select is Vcc and we want 1, noninv */ - IO_STATE(R_PAR0_CONFIG, isel, noninv) | - /* We will run dma, enable */ - IO_STATE(R_PAR0_CONFIG, dma, enable) | - /* No run length encoding, disable */ - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | - /* No run length encoding, disable */ - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | - /* Enable parallel port */ - IO_STATE(R_PAR0_CONFIG, enable, on) | - /* Force mode regardless of pin status */ - IO_STATE(R_PAR0_CONFIG, force, on) | - /* We want ECP forward mode since PAR0 is RX */ - IO_STATE(R_PAR0_CONFIG, mode, ecp_rev); - - *R_PAR1_CONFIG = - /* We do not have an external buffer, don't care */ - IO_STATE(R_PAR1_CONFIG, ioe, noninv) | - - /* Not connected, don't care */ - IO_STATE(R_PAR1_CONFIG, iseli, noninv) | - - /* HostAck must indicate data cycle, noninv */ - IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | - - /* HostClk has no external inverter, noninv */ - IO_STATE(R_PAR1_CONFIG, istrb, noninv) | - - /* Not connected, don't care */ - IO_STATE(R_PAR1_CONFIG, iinit, noninv) | - - /* nAckReverse must be 1 in forward mode but is grounded, inv */ - IO_STATE(R_PAR1_CONFIG, iperr, inv) | - - /* PeriphClk must be 1 in forward mode, noninv */ - IO_STATE(R_PAR1_CONFIG, iack, noninv) | - - /* PeriphAck has no external inverter, noninv */ - IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | - - /* nPerihpRequest has no external inverter, noniv */ - IO_STATE(R_PAR1_CONFIG, ifault, noninv) | - - /* Select is VCC and we want 1, noninv */ - IO_STATE(R_PAR1_CONFIG, isel, noninv) | - - /* No EPP mode, disable */ - IO_STATE(R_PAR1_CONFIG, ext_mode, disable) | - - /* We will run dma, enable */ - IO_STATE(R_PAR1_CONFIG, dma, enable) | - - /* No run length encoding, disable */ - IO_STATE(R_PAR1_CONFIG, rle_in, disable) | - - /* No run length encoding, disable */ - IO_STATE(R_PAR1_CONFIG, rle_out, disable) | - - /* Enable parallel port */ - IO_STATE(R_PAR1_CONFIG, enable, on) | - - /* Force mode regardless of pin status */ - IO_STATE(R_PAR1_CONFIG, force, on) | - - /* We want ECP forward mode since PAR1 is TX */ - IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd); - - /* Setup time of value * 160 + 20 ns == 20 ns below */ - *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0); - - *R_PAR1_CTRL = 0; - - while ((((*R_PAR1_STATUS)&0xE000) >> 13) != 5); /* Wait for ECP_FWD mode */ -#ifdef ETHDEBUG - dump_parport_status(); -#endif - - /* make sure ECP irq is acked when we enable it below */ - - (void)*R_PAR0_STATUS_DATA; - (void)*R_PAR1_STATUS_DATA; - - /* Reset and wait for the DMA channels */ - - RESET_DMA(4); /* PAR1_TX_DMA_NBR */ - RESET_DMA(3); /* PAR0_RX_DMA_NBR */ - WAIT_DMA(4); - WAIT_DMA(3); - - /* boot the slave Etrax, by sending code on PAR1. - * do this before we start up the IRQ handlers and stuff, - * beacuse we simply poll for completion in boot_slave. - */ - - boot_slave(&e100lpslaveprog); - - /* allocate the irq corresponding to the receiving DMA */ - - if (request_irq(DMA3_RX_IRQ_NBR, e100rx_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate DMA3_RX_IRQ_NBR\n"); - goto grace_exit; - } - - /* allocate the irq corresponding to the transmitting DMA */ - - if (request_irq(DMA4_TX_IRQ_NBR, e100tx_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate DMA4_TX_IRQ_NBR\n"); - goto grace_exit; - } - - /* allocate the irq used for detecting ECP commands on the RX port (PAR0) */ - - if (request_irq(PAR0_ECP_IRQ_NBR, ecp_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate PAR0_ECP_IRQ_NBR\n"); - grace_exit: - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - - return -EAGAIN; - } - -#if 0 - /* We are not allocating DMA since DMA4 is reserved for 'cascading' - * and will always fail with the current dma.c - */ - - /* - * Always allocate the DMA channels after the IRQ, - * and clean up on failure. - */ - - if(request_dma(PAR0_RX_DMA_NBR, cardname)) { - printk("Failed to allocate PAR0_RX_DMA_NBR\n"); - goto grace_exit; - } - - if(request_dma(PAR1_TX_DMA_NBR, cardname)) { - printk("Failed to allocate PAR1_TX_DMA_NBR\n"); - grace_exit: - /* this will cause some 'trying to free free irq' but what the heck... */ - - free_dma(PAR1_TX_DMA_NBR); - free_dma(PAR0_RX_DMA_NBR); - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - - return -EAGAIN; - } -#endif - -#ifdef ETHDEBUG - printk("Par port IRQ and DMA allocated\n"); -#endif - save_flags(flags); - cli(); - - /* enable the irq's for PAR0/1 DMA */ - - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma3_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set); - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, par0_ecp_cmd, set); - - tx_skb = 0; - - /* make sure the irqs are cleared */ - - *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - - /* Write the MAC address to the slave HW */ - udelay(5000); - e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); - - /* make sure the rec and transmit error counters are cleared */ - - (void)*R_REC_COUNTERS; /* dummy read */ - (void)*R_TR_COUNTERS; /* dummy read */ - - /* start the receiving DMA channel so we can receive packets from now on */ - - *R_DMA_CH3_FIRST = virt_to_phys(myNextRxDesc); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - restore_flags(flags); - - /* We are now ready to accept transmit requeusts from - * the queueing layer of the networking. - */ -#ifdef ETHDEBUG - printk("Starting slave network transmit queue\n"); -#endif - netif_start_queue(dev); - - return 0; -} - -static void -e100_reset_transceiver(void) -{ - /* To do: Reboot and setup slave Etrax */ -} - -/* Called by upper layers if they decide it took too long to complete - * sending a packet - we need to reset and stuff. - */ - -static void -e100_tx_timeout(struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ problem" : "network cable problem"); - - /* remember we got an error */ - - np->stats.tx_errors++; - - /* reset the TX DMA in case it has hung on something */ - - RESET_DMA(4); - WAIT_DMA(4); - - /* Reset the transceiver. */ - - e100_reset_transceiver(); - - /* and get rid of the packet that never got an interrupt */ - - dev_kfree_skb(tx_skb); - tx_skb = 0; - - /* tell the upper layers we're ok again */ - - netif_wake_queue(dev); -} - - -/* This will only be invoked if the driver is _not_ in XOFF state. - * What this means is that we need not check it, and that this - * invariant will hold if we make sure that the netif_*_queue() - * calls are done at the proper times. - */ - -static int -e100_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - -#ifdef ETHDEBUG - unsigned char *temp_data_ptr = buf; - int i; - - printk("Sending a packet of length %d:\n", length); - /* dump the first bytes in the packet */ - for(i = 0; i < 8; i++) { - printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, - temp_data_ptr[0],temp_data_ptr[1],temp_data_ptr[2], - temp_data_ptr[3],temp_data_ptr[4],temp_data_ptr[5], - temp_data_ptr[6],temp_data_ptr[7]); - temp_data_ptr += 8; - } -#endif - spin_lock_irq(&np->lock); /* protect from tx_interrupt */ - - tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ - dev->trans_start = jiffies; - - e100_hardware_send_packet(HOST_CMD_SENDPACK, buf, length); - - /* this simple TX driver has only one send-descriptor so we're full - * directly. If this had a send-ring instead, we would only do this if - * the ring got full. - */ - - netif_stop_queue(dev); - - spin_unlock_irq(&np->lock); - - return 0; -} - -/* - * The typical workload of the driver: - * Handle the network interface interrupts. - */ - -static void -e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma3_eop, active)) { - - /* acknowledge the eop interrupt */ - - *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); - - /* check if one or more complete packets were indeed received */ - - while(*R_DMA_CH3_FIRST != virt_to_phys(myNextRxDesc)) { - /* Take out the buffer and give it to the OS, then - * allocate a new buffer to put a packet in. - */ - e100_rx(dev); - ((struct net_local *)dev->priv)->stats.rx_packets++; - /* restart/continue on the channel, for safety */ - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, restart); - /* clear dma channel 3 eop/descr irq bits */ - *R_DMA_CH3_CLR_INTR = - IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH3_CLR_INTR, clr_descr, do); - - /* now, we might have gotten another packet - so we have to loop back and check if so */ - } - } -} - -/* the transmit dma channel interrupt - * - * this is supposed to free the skbuff which was pending during transmission, - * and inform the kernel that we can send one more buffer - */ - -static void -e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - struct net_local *np = (struct net_local *)dev->priv; - -#ifdef ETHDEBUG - printk("We got tx interrupt\n"); -#endif - /* check for a dma4_eop interrupt */ - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma4_descr, active)) { - /* This protects us from concurrent execution of - * our dev->hard_start_xmit function above. - */ - - spin_lock(&np->lock); - - /* acknowledge the eop interrupt */ - - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - - /* skip *R_DMA_CH4_FIRST == 0 test since we use d_wait... */ - if(tx_skb) { - - np->stats.tx_bytes += tx_skb->len; - np->stats.tx_packets++; - /* dma is ready with the transmission of the data in tx_skb, so now we can release the skb memory */ - dev_kfree_skb_irq(tx_skb); - tx_skb = 0; - netif_wake_queue(dev); - } else { - printk(KERN_WARNING "%s: tx weird interrupt\n", - cardname); - } - - spin_unlock(&np->lock); - } -} - -static void -ecp_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct net_local *lp = (struct net_local *)dev->priv; - unsigned long temp, irqbits = *R_IRQ_MASK0_RD; - - /* check for ecp irq */ - if(irqbits & IO_MASK(R_IRQ_MASK0_RD, par0_ecp_cmd)) { - /* acknowledge by reading the bit */ - temp = *R_PAR0_STATUS_DATA; - /* force an EOP on the incoming channel, so we'll get an rx interrupt */ - *R_SET_EOP = IO_STATE(R_SET_EOP, ch3_eop, set); - } -} - -/* We have a good packet(s), get it/them out of the buffers. */ -static void -e100_rx(struct net_device *dev) -{ - struct sk_buff *skb; - int length=0; - int i; - struct net_local *np = (struct net_local *)dev->priv; - struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; - unsigned char *skb_data_ptr; - - /* If the packet is broken down in many small packages then merge - * count how much space we will need to alloc with skb_alloc() for - * it to fit. - */ - - while (!(myNextRxDesc->status & d_eop)) { - length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } - - length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ - -#ifdef ETHDEBUG - printk("Got a packet of length %d:\n", length); - /* dump the first bytes in the packet */ - skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); - for(i = 0; i < 8; i++) { - printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, - skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], - skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); - skb_data_ptr += 8; - } -#endif - - skb = dev_alloc_skb(length - ETHER_HEAD_LEN); - if (!skb) { - np->stats.rx_errors++; - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - return; - } - - skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ - skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ - -#ifdef ETHDEBUG - printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", - skb->head, skb->data, skb->tail, skb->end); - printk("copying packet to 0x%x.\n", skb_data_ptr); -#endif - - /* this loop can be made using max two memcpy's if optimized */ - - while(mySaveRxDesc != myNextRxDesc) { - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->sw_len); - skb_data_ptr += mySaveRxDesc->sw_len; - mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); - } - - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->hw_len); - - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - - /* Send the packet to the upper layers */ - - netif_rx(skb); - - /* Prepare for next packet */ - - myNextRxDesc->status = 0; - myPrevRxDesc = myNextRxDesc; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - - myPrevRxDesc->ctrl |= d_eol; - myLastRxDesc->ctrl &= ~d_eol; - myLastRxDesc = myPrevRxDesc; - - return; -} - -/* The inverse routine to net_open(). */ -static int -e100_close(struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - - printk("Closing %s.\n", dev->name); - - netif_stop_queue(dev); - - *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, par0_ecp_cmd, clr); - - *R_IRQ_MASK2_CLR = - IO_STATE(R_IRQ_MASK2_CLR, dma3_eop, clr) | - IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr); - - /* Stop the receiver and the transmitter */ - - RESET_DMA(3); - RESET_DMA(4); - - /* Flush the Tx and disable Rx here. */ - - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - - free_dma(PAR1_TX_DMA_NBR); - free_dma(PAR0_RX_DMA_NBR); - - /* Update the statistics here. */ - - update_rx_stats(&np->stats); - update_tx_stats(&np->stats); - - return 0; -} - -static void -update_rx_stats(struct net_device_stats *es) -{ - unsigned long r = *R_REC_COUNTERS; - /* update stats relevant to reception errors */ - es->rx_fifo_errors += r >> 24; /* fifo overrun */ - es->rx_crc_errors += r & 0xff; /* crc error */ - es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */ - es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */ -} - -static void -update_tx_stats(struct net_device_stats *es) -{ - unsigned long r = *R_TR_COUNTERS; - /* update stats relevant to transmission errors */ - es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */ - es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */ -} - -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct net_local *lp = (struct net_local *)dev->priv; - - update_rx_stats(&lp->stats); - update_tx_stats(&lp->stats); - - return &lp->stats; -} - -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. - */ -static void -set_multicast_list(struct net_device *dev) -{ - /* To do */ -} - -void -e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length) -{ - static char bogus_ecp[] = { 42, 42 }; - int i; - - -#ifdef ETHDEBUG - printk("e100 send pack, buf 0x%x len %d\n", buf, length); -#endif - - host_command = hostcmd; - - /* Configure the tx dma descriptor. Desc 0 is already configured.*/ - - TxDescList[1].sw_len = length; - /* bug workaround - etrax100 needs d_wait on the descriptor _before_ - * a descriptor containing an ECP command - */ - TxDescList[1].ctrl = d_wait; - TxDescList[1].buf = virt_to_phys(buf); - TxDescList[1].next = virt_to_phys(&TxDescList[2]); - - /* append the ecp dummy descriptor - its only purpose is to - * make the receiver generate an irq due to the ecp command - * so the receiver knows where packets end - */ - - TxDescList[2].sw_len = 1; - TxDescList[2].ctrl = d_ecp | d_eol | d_int; - TxDescList[2].buf = virt_to_phys(bogus_ecp); - - - /* setup the dma channel and start it */ - - *R_DMA_CH4_FIRST = virt_to_phys(TxDescList); - *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); - -#ifdef ETHDEBUG - printk("done\n"); -#endif -} - -/* send a chunk of code to the slave chip to boot it. */ - -static void -boot_slave(unsigned char *code) -{ - int i; - -#ifdef ETHDEBUG - printk(" booting slave ETRAX...\n"); -#endif - *R_PORT_PB_DATA = 0x7F; /* Reset slave */ - udelay(15); /* Time enough to reset WAN tranciever */ - *R_PORT_PB_DATA = 0xFF; /* Reset slave */ - - /* configure the tx dma data descriptor */ - - TxDescList[1].sw_len = ETRAX_PAR_BOOT_LENGTH; - TxDescList[1].ctrl = d_eol | d_int; - - TxDescList[1].buf = virt_to_phys(code); - TxDescList[1].next = 0; - - /* setup the dma channel and start it */ - *R_DMA_CH4_FIRST = virt_to_phys(&TxDescList[1]); - *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); - - /* wait for completion */ - while(!(*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma4_descr))); - - /* ack the irq */ - - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - -#if 0 - /* manual transfer of boot code - requires dma turned off */ - for (i=0; i> 13; - printk("Reg mode: %u (ecp_fwd(5), ecp_rev(6))\n", temp); - - temp = (*R_PAR1_STATUS)&0x1000; - temp = temp >> 12; - printk("Reg perr: %u (ecp_rev(0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0800; - temp = temp >> 11; - printk("Reg ack: %u (inactive (1), active (0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0400; - temp = temp >> 10; - printk("Reg busy: %u (inactive (0), active (1))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0200; - temp = temp >> 9; - printk("Reg fault: %u (inactive (1), active (0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0100; - temp = temp >> 8; - printk("Reg sel: %u (inactive (0), active (1), xflag(1))\n", temp); - - temp = (*R_PAR1_STATUS)&0x02; - temp = temp >> 1; - printk("Reg tr_rdy: %u (busy (0), ready (1))\n", temp); - -} -#endif /* ETHDEBUG */ - -static int -etrax_init_module(void) -{ - return etrax_ethernet_lpslave_init(); -} - -module_init(etrax_init_module); diff --git a/arch/cris/drivers/parport.c b/arch/cris/drivers/parport.c deleted file mode 100644 index 443e51a111b..00000000000 --- a/arch/cris/drivers/parport.c +++ /dev/null @@ -1,572 +0,0 @@ -/* $Id: parport.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - * - * Elinux parallel port driver - * NOTE! - * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 - * this should be handled if both are enabled at the same time. - * THIS IS NOT HANDLED YET! - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Fredrik Hugosson - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK printk -#else -static inline int DPRINTK(void *nothing, ...) {return 0;} -#endif - -/* - * Etrax100 DMAchannels: - * Par0 out : DMA2 - * Par0 in : DMA3 - * Par1 out : DMA4 - * Par1 in : DMA5 - * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding - * DMA and DMA irq - */ - -//#define CONFIG_PAR0_INT 1 -//#define CONFIG_PAR1_INT 1 - -#define SETF(var, reg, field, val) \ - var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val) - -#define SETS(var, reg, field, val) \ - var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val) - -struct etrax100par_struct { - /* parallell port control */ - volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ - const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ - volatile u32 *reg_config; /* R_PARx_CONFIG */ - volatile u32 *reg_delay; /* R_PARx_DELAY */ - - /* DMA control */ - int odma; - unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - - volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - - volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - - /* Non DMA interrupt stuff */ - unsigned long int_irq; /* R_VECT_MASK_RD */ - const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ - volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ - const volatile u32 *irq_read; /* R_IRQ_READX */ - volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ - unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ - unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ - unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ - unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ - int portnr; - - /* ----- end of fields initialised in port_table[] below ----- */ - - struct parport *port; - - /* Shadow registers */ - volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ - volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ - volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */ -}; - -/* Always have the complete structs here, even if the port is not used! - * (that way we can index this by the port number) - */ -static struct etrax100par_struct port_table[] = { - { - R_PAR0_CTRL_DATA, - R_PAR0_STATUS_DATA, - R_PAR0_CONFIG, - R_PAR0_DELAY, - /* DMA interrupt stuff */ - 2, - 1U << 4, /* uses DMA 2 and 3 */ - R_DMA_CH2_CLR_INTR, - R_DMA_CH2_FIRST, - R_DMA_CH2_CMD, - R_DMA_CH3_CLR_INTR, - R_DMA_CH3_FIRST, - R_DMA_CH3_CMD, - /* Non DMA interrupt stuff */ - IO_BITNR(R_VECT_MASK_RD, par0), - R_IRQ_MASK0_RD, - R_IRQ_MASK0_CLR, - R_IRQ_READ0, - R_IRQ_MASK0_SET, - IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ - IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ - IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ - IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ - 0 - }, - { - R_PAR1_CTRL_DATA, - R_PAR1_STATUS_DATA, - R_PAR1_CONFIG, - R_PAR1_DELAY, - /* DMA interrupt stuff */ - 4, - 1U << 8, /* uses DMA 4 and 5 */ - - R_DMA_CH4_CLR_INTR, - R_DMA_CH4_FIRST, - R_DMA_CH4_CMD, - R_DMA_CH5_CLR_INTR, - R_DMA_CH5_FIRST, - R_DMA_CH5_CMD, - /* Non DMA interrupt stuff */ - IO_BITNR(R_VECT_MASK_RD, par1), - R_IRQ_MASK1_RD, - R_IRQ_MASK1_CLR, - R_IRQ_READ1, - R_IRQ_MASK1_SET, - IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ - IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ - IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ - IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ - 1 - } -}; - - -#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct)) - -static void -parport_etrax_write_data(struct parport *p, unsigned char value) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static unsigned char -parport_etrax_read_data(struct parport *p) -{ - unsigned char ret; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); - - DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); - return ret; -} - - -static void -parport_etrax_write_control(struct parport *p, unsigned char control) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); - - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, - (control & PARPORT_CONTROL_STROBE) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, - (control & PARPORT_CONTROL_AUTOFD) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, - (control & PARPORT_CONTROL_INIT) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, - (control & PARPORT_CONTROL_SELECT) > 0); - - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static unsigned char -parport_etrax_read_control( struct parport *p) -{ - unsigned char ret = 0; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_STROBE; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_AUTOFD; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_INIT; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_SELECT; - - DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); - return ret; -} - - -static unsigned char -parport_etrax_frob_control(struct parport *p, unsigned char mask, - unsigned char val) -{ - unsigned char old; - - DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", - p->portnum, mask, val); - old = parport_etrax_read_control(p); - parport_etrax_write_control(p, (old & ~mask) ^ val); - return old; -} - - -static unsigned char -parport_etrax_read_status(struct parport *p) -{ - unsigned char ret = 0; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) - ret |= PARPORT_STATUS_ERROR; - if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) - ret |= PARPORT_STATUS_SELECT; - if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) - ret |= PARPORT_STATUS_PAPEROUT; - if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) - ret |= PARPORT_STATUS_ACK; - if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) - ret |= PARPORT_STATUS_BUSY; - - DPRINTK("* E100 PP %d: status register %04x\n", - p->portnum, *info->reg_status_data); - DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); - return ret; -} - - -static void -parport_etrax_enable_irq(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - *info->irq_mask_set = info->irq_mask_tx; - DPRINTK("* E100 PP %d: enable irq\n", p->portnum); -} - - -static void -parport_etrax_disable_irq(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - *info->irq_mask_clr = info->irq_mask_tx; - DPRINTK("* E100 PP %d: disable irq\n", p->portnum); -} - - -static void -parport_etrax_data_forward(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: forward mode\n", p->portnum); - SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static void -parport_etrax_data_reverse(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: reverse mode\n", p->portnum); - SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static void -parport_etrax_init_state(struct pardevice *dev, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_init_state\n"); -} - - -static void -parport_etrax_save_state(struct parport *p, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_save_state\n"); -} - - -static void -parport_etrax_restore_state(struct parport *p, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_restore_state\n"); -} - - -static void -parport_etrax_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - - -static void -parport_etrax_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - - -static struct -parport_operations pp_etrax_ops = { - parport_etrax_write_data, - parport_etrax_read_data, - - parport_etrax_write_control, - parport_etrax_read_control, - parport_etrax_frob_control, - - parport_etrax_read_status, - - parport_etrax_enable_irq, - parport_etrax_disable_irq, - - parport_etrax_data_forward, - parport_etrax_data_reverse, - - parport_etrax_init_state, - parport_etrax_save_state, - parport_etrax_restore_state, - - parport_etrax_inc_use_count, - parport_etrax_dec_use_count, - - parport_ieee1284_epp_write_data, - parport_ieee1284_epp_read_data, - parport_ieee1284_epp_write_addr, - parport_ieee1284_epp_read_addr, - - parport_ieee1284_ecp_write_data, - parport_ieee1284_ecp_read_data, - parport_ieee1284_ecp_write_addr, - - parport_ieee1284_write_compat, - parport_ieee1284_read_nibble, - parport_ieee1284_read_byte, -}; - - -static void -parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct etrax100par_struct *info = (struct etrax100par_struct *) - ((struct parport *)dev_id)->private_data; - DPRINTK("* E100 PP %d: Interrupt received\n", - ((struct parport *)dev_id)->portnum); - *info->irq_mask_clr = info->irq_mask_tx; - parport_generic_irq(irq, (struct parport *)dev_id, regs); -} - -/* ----------- Initialisation code --------------------------------- */ - -static void __init -parport_etrax_show_parallel_version(void) -{ - printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); -} - -#ifdef CONFIG_ETRAX_PAR0_DMA -#define PAR0_USE_DMA 1 -#else -#define PAR0_USE_DMA 0 -#endif - -#ifdef CONFIG_ETRAX_PAR1_DMA -#define PAR1_USE_DMA 1 -#else -#define PAR1_USE_DMA 0 -#endif - -static void __init -parport_etrax_init_registers(void) -{ - struct etrax100par_struct *info; - int i; - - for (i = 0, info = port_table; i < 2; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - info->reg_config_shadow = - IO_STATE(R_PAR0_CONFIG, iseli, inv) | - IO_STATE(R_PAR0_CONFIG, iautofd, inv) | - IO_STATE(R_PAR0_CONFIG, istrb, inv) | - IO_STATE(R_PAR0_CONFIG, iinit, inv) | - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | - IO_STATE(R_PAR0_CONFIG, enable, on) | - IO_STATE(R_PAR0_CONFIG, force, off) | - IO_STATE(R_PAR0_CONFIG, ign_ack, wait) | - IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe) | - IO_STATE(R_PAR0_CONFIG, mode, manual); - - if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA)) - info->reg_config_shadow |= - IO_STATE(R_PAR0_CONFIG, dma, enable); - else - info->reg_config_shadow |= - IO_STATE(R_PAR0_CONFIG, dma, disable); - - *info->reg_config = info->reg_config_shadow; - - info->reg_ctrl_data_shadow = - IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop) | - IO_STATE(R_PAR0_CTRL_DATA, oe, enable) | - IO_STATE(R_PAR0_CTRL_DATA, seli, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, strb, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, init, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data) | - IO_FIELD(R_PAR0_CTRL_DATA, data, 0); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; - - /* Clear peri int without setting shadow */ - *info->reg_ctrl_data = info->reg_ctrl_data_shadow | - IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack); - - info->reg_delay_shadow = - IO_FIELD(R_PAR0_DELAY, setup, 5) | - IO_FIELD(R_PAR0_DELAY, strobe, 5) | - IO_FIELD(R_PAR0_DELAY, hold, 5); - *info->reg_delay = info->reg_delay_shadow; - } - -#ifdef CONFIG_ETRAX_PARALLEL_PORT0 -#ifdef CONFIG_ETRAX_PAR0_DMA - RESET_DMA(PAR0_TX_DMA_NBR); - WAIT_DMA(PAR0_TX_DMA_NBR); -#ifdef CONFIG_ETRAX_SERIAL_PORT2 - printk(" Warning - DMA clash with ser2!\n"); -#endif /* SERIAL_PORT2 */ -#endif /* DMA */ -#endif /* PORT0 */ - -#ifdef CONFIG_ETRAX_PARALLEL_PORT1 -#ifdef CONFIG_ETRAX_PAR1_DMA - RESET_DMA(PAR1_TX_DMA_NBR); - WAIT_DMA(PAR1_TX_DMA_NBR); -#ifdef CONFIG_ETRAX_SERIAL_PORT3 - printk(" Warning - DMA clash with ser3!\n"); -#endif /* SERIAL_PORT3 */ -#endif /* DMA */ -#endif /* PORT1 */ -} - - -int __init -parport_etrax_init(void) -{ - struct parport *p; - int port_exists = 0; - int i; - struct etrax100par_struct *info; - const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" }; - - parport_etrax_show_parallel_version(); - parport_etrax_init_registers(); - - for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - p = parport_register_port((unsigned long)0, info->int_irq, - PARPORT_DMA_NONE, &pp_etrax_ops); - if (!p) - continue; - - info->port = p; - p->private_data = info; - /* Axis FIXME: Set mode flags. */ - /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */ - - if(request_irq(info->int_irq, parport_etrax_interrupt, - SA_SHIRQ, names[i], p)) { - parport_unregister_port (p); - continue; - } - - printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n", - p->name, i); - parport_proc_register(p); - parport_announce_port(p); - port_exists = 1; - } - - return port_exists; -} - -void __exit -parport_etrax_exit(void) -{ - int i; - struct etrax100par_struct *info; - - for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - if (info->int_irq != PARPORT_IRQ_NONE) - free_irq(info->int_irq, info->port); - parport_proc_unregister(info->port); - parport_unregister_port(info->port); - } -} diff --git a/arch/cris/drivers/sync_serial.c b/arch/cris/drivers/sync_serial.c deleted file mode 100644 index 59d62e01c73..00000000000 --- a/arch/cris/drivers/sync_serial.c +++ /dev/null @@ -1,900 +0,0 @@ -/* - * Simple synchronous serial port driver for ETRAX 100LX. - * - * Synchronous serial ports are used for continous streamed data like audio. - * The default setting for this driver is compatible with the STA 013 MP3 - * decoder. The driver can easily be tuned to fit other audio encoder/decoders - * and SPI - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Mikael Starvik - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The receiver is a bit tricky beacuse of the continous stream of data. */ -/* */ -/* Two DMA descriptors are linked together. Each DMA descriptor is */ -/* responsible for one half of a common buffer. */ -/* */ -/* ------------------------------ */ -/* | ---------- ---------- | */ -/* --> | Descr1 |-->| Descr2 |--- */ -/* ---------- ---------- */ -/* | | */ -/* v v */ -/* ----------------------------- */ -/* | BUFFER | */ -/* ----------------------------- */ -/* | | */ -/* readp writep */ -/* */ -/* If the application keeps up the pace readp will be right after writep.*/ -/* If the application can't keep the pace we have to throw away data. */ -/* The idea is that readp should be ready with the data pointed out by */ -/* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ -/* the rest of the data pointed out by Descr1 and set readp to the start */ -/* of Descr2 */ - -#define SYNC_SERIAL_MAJOR 125 - -/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ -/* words can be handled */ - -#define IN_BUFFER_SIZE 12288 -#define OUT_BUFFER_SIZE 4096 - -#define DEFAULT_FRAME_RATE 0 -#define DEFAULT_WORD_RATE 7 - -#define DEBUG(x) - -/* Define some macros to access ETRAX 100 registers */ -#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_FIELD(##reg##, field, val) -#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_STATE(##reg##, field, val) - -typedef struct sync_port -{ - /* Etrax registers and bits*/ - volatile unsigned * const status; - volatile unsigned * const ctrl_data; - volatile unsigned * const output_dma_first; - volatile unsigned char * const output_dma_cmd; - volatile unsigned char * const output_dma_clr_irq; - volatile unsigned * const input_dma_first; - volatile unsigned char * const input_dma_cmd; - volatile unsigned char * const input_dma_clr_irq; - volatile unsigned * const data_out; - volatile unsigned * const data_in; - char data_avail_bit; /* In R_IRQ_MASK1_RD */ - char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ - char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ - char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ - char output_dma_bit; /* In R_IRQ_MASK2_RD */ - - int enabled; /* 1 if port is enabled */ - int use_dma; /* 1 if port uses dma */ - int port_nbr; /* Port 0 or 1 */ - unsigned ctrl_data_shadow; /* Register shadow */ - char busy; /* 1 if port is busy */ - wait_queue_head_t out_wait_q; - wait_queue_head_t in_wait_q; - struct etrax_dma_descr out_descr; - struct etrax_dma_descr in_descr1; - struct etrax_dma_descr in_descr2; - char out_buffer[OUT_BUFFER_SIZE]; - int out_count; /* Remaining bytes for current transfer */ - char* outp; /* Current position in out_buffer */ - char in_buffer[IN_BUFFER_SIZE]; - volatile char* readp; /* Next byte to be read by application */ - volatile char* writep; /* Next byte to be written by etrax */ - int odd_output; /* 1 if writing odd nible in 12 bit mode */ - int odd_input; /* 1 if reading odd nible in 12 bit mode */ -} sync_port; - - -static int etrax_sync_serial_init(void); -static void initialize_port(int portnbr); -static int sync_serial_open(struct inode *, struct file*); -static int sync_serial_release(struct inode*, struct file*); -static int sync_serial_ioctl(struct inode*, struct file*, - unsigned int cmd, unsigned long arg); -static ssize_t sync_serial_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t sync_serial_manual_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t sync_serial_read(struct file *file, char *buf, - size_t count, loff_t *ppos); -static void send_word(sync_port* port); -static void start_dma(struct sync_port *port, const char* data, int count); -static void start_dma_in(sync_port* port); -static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); - -/* The ports */ -static struct sync_port ports[]= -{ - { - R_SYNC_SERIAL1_STATUS, /* status */ - R_SYNC_SERIAL1_CTRL, /* ctrl_data */ - R_DMA_CH8_FIRST, /* output_dma_first */ - R_DMA_CH8_CMD, /* output_dma_cmd */ - R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH9_FIRST, /* input_dma_first */ - R_DMA_CH9_CMD, /* input_dma_cmd */ - R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ - R_SYNC_SERIAL1_TR_DATA, /* data_out */ - R_SYNC_SERIAL1_REC_DATA,/* data in */ - IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ - IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ - IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ - }, - { - R_SYNC_SERIAL3_STATUS, /* status */ - R_SYNC_SERIAL3_CTRL, /* ctrl_data */ - R_DMA_CH4_FIRST, /* output_dma_first */ - R_DMA_CH4_CMD, /* output_dma_cmd */ - R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH5_FIRST, /* input_dma_first */ - R_DMA_CH5_CMD, /* input_dma_cmd */ - R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ - R_SYNC_SERIAL3_TR_DATA, /* data_out */ - R_SYNC_SERIAL3_REC_DATA,/* data in */ - IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ - IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ - IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ - } -}; - -/* Register shadows */ -static unsigned sync_serial_prescale_shadow = 0; -static unsigned gen_config_ii_shadow = 0; - -#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) - -static struct file_operations sync_serial_fops = { - .owner = THIS_MODULE, - .write = sync_serial_write, - .read = sync_serial_read, - .ioctl = sync_serial_ioctl, - .open = sync_serial_open, - .release = sync_serial_release -}; - -static int __init etrax_sync_serial_init(void) -{ - ports[0].enabled = 0; - ports[1].enabled = 0; - - if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) - { - printk("unable to get major for synchronous serial port\n"); - return -EBUSY; - } - - /* Deselect synchronous serial ports */ - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, ser3, select); - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - /* Initialize Ports */ -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) - ports[0].enabled = 1; - SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) - ports[0].use_dma = 1; - initialize_port(0); - if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0])) - panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) - panic("Can't allocate sync serial port 1 IRQ"); - RESET_DMA(8); WAIT_DMA(8); - RESET_DMA(9); WAIT_DMA(9); - *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); - *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); - start_dma_in(&ports[0]); -#else - ports[0].use_dma = 0; - initialize_port(0); - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0])) - panic("Can't allocate sync serial manual irq"); - *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); -#endif -#endif - -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - ports[1].enabled = 1; - SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) - ports[1].use_dma = 1; - initialize_port(1); - if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1])) - panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1])) - panic("Can't allocate sync serial port 1 IRQ"); - RESET_DMA(4); WAIT_DMA(4); - RESET_DMA(5); WAIT_DMA(5); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); - start_dma_in(&ports[1]); -#else - ports[1].use_dma = 0; - initialize_port(1); - if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ - { - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1])) - panic("Can't allocate sync serial manual irq"); - } - *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); -#endif -#endif - - *R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */ - - /* Set up timing */ - *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = ( - IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); - - /* Select synchronous ports */ - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - printk("ETRAX 100LX synchronous serial port driver\n"); - return 0; -} - -static void initialize_port(int portnbr) -{ - struct sync_port* port = &ports[portnbr]; - - DEBUG(printk("Init sync serial port %d\n", portnbr)); - - port->port_nbr = portnbr; - port->busy = 0; - port->readp = port->in_buffer; - port->writep = port->in_buffer + IN_BUFFER_SIZE/2; - port->odd_input = 0; - - init_waitqueue_head(&port->out_wait_q); - init_waitqueue_head(&port->in_wait_q); - - port->ctrl_data_shadow = - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz) | - IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) | - IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore) | - IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped) | - IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable) | - IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | - IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | - IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | - IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg) | - IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)| - IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)| - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)| - IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high); - - if (port->use_dma) - port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, on); - else - port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, off); - - *port->ctrl_data = port->ctrl_data_shadow; -} - -static int sync_serial_open(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - DEBUG(printk("Open sync serial port %d\n", dev)); - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - if (ports[dev].busy) - { - DEBUG(printk("Device is busy.. \n")); - return -EBUSY; - } - ports[dev].busy = 1; - return 0; -} - -static int sync_serial_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - ports[dev].busy = 0; - return 0; -} - -static int sync_serial_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int return_val = 0; - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - sync_port* port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -1; - } - port = &ports[dev]; - - /* Disable port while changing config */ - if (dev) - { - RESET_DMA(4); WAIT_DMA(4); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); - } - else - { - RESET_DMA(8); WAIT_DMA(8); - *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); - } - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - switch(cmd) - { - case SSP_SPEED: - if (GET_SPEED(arg) == CODEC) - { - if (dev) - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec); - else - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec); - - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg)); - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg)); - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg)); - } - else - { - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg)); - if (dev) - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate); - else - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate); - } - break; - case SSP_MODE: - if (arg > 5) - return -EINVAL; - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg); - break; - case SSP_FRAME_SYNC: - if (arg & NORMAL_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); - else if (arg & EARLY_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early); - - if (arg & BIT_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit); - else if (arg & WORD_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); - else if (arg & EXTENDED_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended); - - if (arg & SYNC_ON) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); - else if (arg & SYNC_OFF) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off); - - if (arg & WORD_SIZE_8) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); - else if (arg & WORD_SIZE_12) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit); - else if (arg & WORD_SIZE_16) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit); - else if (arg & WORD_SIZE_24) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit); - else if (arg & WORD_SIZE_32) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit); - - if (arg & BIT_ORDER_MSB) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); - else if (arg & BIT_ORDER_LSB) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb); - - if (arg & FLOW_CONTROL_ENABLE) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled); - else if (arg & FLOW_CONTROL_DISABLE) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); - - if (arg & CLOCK_NOT_GATED) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal); - else if (arg & CLOCK_GATED) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated); - - break; - case SSP_IPOLARITY: - if (arg & CLOCK_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); - else if (arg & CLOCK_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos); - - if (arg & FRAME_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal); - else if (arg & FRAME_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); - - if (arg & STATUS_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal); - else if (arg & STATUS_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted); - break; - case SSP_OPOLARITY: - if (arg & CLOCK_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal); - else if (arg & CLOCK_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); - - if (arg & FRAME_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal); - else if (arg & FRAME_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); - - if (arg & STATUS_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal); - else if (arg & STATUS_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted); - break; - case SSP_SPI: - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); - if (arg & SPI_SLAVE) - { - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT); - } - else - { - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT); - } - break; - default: - return_val = -1; - } - /* Set config and enable port */ - *port->ctrl_data = port->ctrl_data_shadow; - *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow; - if (dev) - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); - else - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); - - *R_GEN_CONFIG_II = gen_config_ii_shadow; - return return_val; -} - -static ssize_t sync_serial_manual_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - sync_port* port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - - port = &ports[dev]; - if (copy_from_user(port->out_buffer, buf, count)) - return -EFAULT; - port->outp = port->out_buffer; - port->out_count = count; - port->odd_output = 1; - add_wait_queue(&port->out_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - *R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */ - send_word(port); /* Start sender by sending first word */ - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->out_wait_q, &wait); - if (signal_pending(current)) - { - return -EINTR; - } - return count; -} - -static ssize_t sync_serial_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - sync_port *port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); - - count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count; - - /* Make sure transmitter is running */ - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); - *port->ctrl_data = port->ctrl_data_shadow; - - if (!port->use_dma) - { - return sync_serial_manual_write(file, buf, count, ppos); - } - - if (copy_from_user(port->out_buffer, buf, count)) - return -EFAULT; - add_wait_queue(&port->out_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - start_dma(port, buf, count); - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->out_wait_q, &wait); - if (signal_pending(current)) - { - return -EINTR; - } - return count; -} - -static ssize_t sync_serial_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - int avail; - sync_port *port; - char* start; - char* end; - unsigned long flags; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - DEBUG(printk("Read dev %d count %d\n", dev, count)); - - /* Make sure receiver is running */ - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); - *port->ctrl_data = port->ctrl_data_shadow; - - /* Calculate number of available bytes */ - while (port->readp == port->writep) /* No data */ - { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); - if (signal_pending(current)) - { - return -EINTR; - } - } - - /* Save pointers to avoid that they are modified by interrupt */ - start = port->readp; - end = port->writep; - - /* Lazy read, never return wrapped data. */ - if (end > start) - avail = end - start; - else - avail = port->in_buffer + IN_BUFFER_SIZE - start; - - count = count > avail ? avail : count; - if (copy_to_user(buf, start, count)) - return -EFAULT; - - /* Disable interrupts while updating readp */ - save_flags(flags); - cli(); - port->readp += count; - if (port->readp == port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ - port->readp = port->in_buffer; - restore_flags(flags); - - DEBUG(printk("%d bytes read\n", count)); - return count; -} - -static void send_word(sync_port* port) -{ - switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) - { - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): - port->out_count--; - *port->data_out = *port->outp++; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): - port->out_count--; - if (port->odd_output) - *port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1)); - else - *port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1)); - port->odd_output = !port->odd_output; - port->outp++; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): - port->out_count-=2; - *port->data_out = *(unsigned short *)port->outp; - port->outp+=2; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): - port->out_count-=3; - *port->data_out = *(unsigned int *)port->outp; - port->outp+=3; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): - port->out_count-=4; - *port->data_out = *(unsigned int *)port->outp; - port->outp+=4; - break; - } -} - -static void start_dma(struct sync_port* port, const char* data, int count) -{ - port->out_descr.hw_len = 0; - port->out_descr.next = 0; - port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait; - port->out_descr.sw_len = count; - port->out_descr.buf = virt_to_phys(port->out_buffer); - port->out_descr.status = 0; - - *port->output_dma_first = virt_to_phys(&port->out_descr); - *port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); -} - -static void start_dma_in(sync_port* port) -{ - if (port->writep > port->in_buffer + IN_BUFFER_SIZE) - { - panic("Offset too large in sync serial driver\n"); - return; - } - port->in_descr1.hw_len = 0; - port->in_descr1.ctrl = d_int; - port->in_descr1.status = 0; - port->in_descr1.next = virt_to_phys(&port->in_descr2); - port->in_descr2.hw_len = 0; - port->in_descr2.next = virt_to_phys(&port->in_descr1); - port->in_descr2.ctrl = d_int; - port->in_descr2.status = 0; - - /* Find out which descriptor to start */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - { - /* Start descriptor 2 */ - port->in_descr1.sw_len = IN_BUFFER_SIZE/2; /* All data available in 1 */ - port->in_descr1.buf = virt_to_phys(port->in_buffer); - port->in_descr2.sw_len = port->in_buffer + IN_BUFFER_SIZE - port->writep; - port->in_descr2.buf = virt_to_phys(port->writep); - *port->input_dma_first = virt_to_phys(&port->in_descr2); - } - else - { - /* Start descriptor 1 */ - port->in_descr1.sw_len = port->in_buffer + IN_BUFFER_SIZE/2 - port->writep; - port->in_descr1.buf = virt_to_phys(port->writep); - port->in_descr2.sw_len = IN_BUFFER_SIZE/2; - port->in_descr2.buf = virt_to_phys(port->in_buffer + IN_BUFFER_SIZE / 2); - *port->input_dma_first = virt_to_phys(&port->in_descr1); - } - *port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); -} - -static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned long ireg = *R_IRQ_MASK2_RD; - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - sync_port *port = &ports[i]; - if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */ - { - /* Clear IRQ */ - *port->output_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ - } - } -} - -static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned long ireg = *R_IRQ_MASK2_RD; - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - int update = 0; - sync_port *port = &ports[i]; - - if (!port->enabled) - { - continue; - } - - if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */ - { - /* DMA has reached end of descriptor */ - *port->input_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - - /* Find out which descriptor that is ready */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - { - /* Descr 2 was ready. Restart DMA at descriptor 1 */ - port->writep = port->in_buffer; - - /* Throw away data? */ - if (port->readp < port->in_buffer + IN_BUFFER_SIZE/2) - port->readp = port->in_buffer + IN_BUFFER_SIZE/2; - } - else - { - /* Descr 1 was ready. Restart DMA at descriptor 2 */ - port->writep = port->in_buffer + IN_BUFFER_SIZE/2; - - /* Throw away data? */ - if (port->readp >= port->in_buffer + IN_BUFFER_SIZE/2) - port->readp = port->in_buffer; - } - start_dma_in(port); - wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ - } - } -} - -static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - sync_port* port = &ports[i]; - - if (!port->enabled) - { - continue; - } - - if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit)) /* Data received? */ - { - /* Read data */ - switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) - { - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): - *port->writep++ = *(volatile char *)port->data_in; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): - { - int data = *(unsigned short *)port->data_in; - if (port->odd_input) - { - *port->writep |= (data & 0x0f00) >> 8; - *(port->writep + 1) = data & 0xff; - } - else - { - *port->writep = (data & 0x0ff0) >> 4; - *(port->writep + 1) = (data & 0x0f) << 4; - } - port->odd_input = !port->odd_input; - port->writep+=1; - } - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): - *(unsigned short*)port->writep = *(volatile unsigned short *)port->data_in; - port->writep+=2; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): - *(unsigned int*)port->writep = *port->data_in; - port->writep+=3; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): - *(unsigned int*)port->writep = *port->data_in; - port->writep+=4; - break; - } - - if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ - port->writep = port->in_buffer; - wake_up_interruptible(&port->in_wait_q); /* Wake up application */ - } - - if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */ - { - if (port->out_count) /* More data to send */ - send_word(port); - else /* transmission finished */ - { - *R_IRQ_MASK1_CLR = 1 << port->ready_irq_bit; /* Turn off IRQ */ - wake_up_interruptible(&port->out_wait_q); /* Wake up application */ - } - } - } -} - -module_init(etrax_sync_serial_init); diff --git a/arch/cris/drivers/usb-host.c b/arch/cris/drivers/usb-host.c deleted file mode 100644 index 3a6326f735a..00000000000 --- a/arch/cris/drivers/usb-host.c +++ /dev/null @@ -1,2516 +0,0 @@ -/* - * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) - * - * Copyright (c) 2001 Axis Communications AB. - * - * $Id: usb-host.c,v 1.11 2001/09/26 11:52:16 bjornw Exp $ - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "usb-host.h" - -#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR -#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR -#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR - -static const char *usb_hcd_version = "$Revision: 1.11 $"; - -#undef KERN_DEBUG -#define KERN_DEBUG "" - -#undef USB_DEBUG_RH -#undef USB_DEBUG_EP -#undef USB_DEBUG_DESC -#undef USB_DEBUG_TRACE -#undef USB_DEBUG_CTRL -#undef USB_DEBUG_BULK -#undef USB_DEBUG_INTR - -#ifdef USB_DEBUG_RH -#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg) -#else -#define dbg_rh(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_EP -#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg) -#else -#define dbg_ep(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_CTRL -#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg) -#else -#define dbg_ctrl(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_BULK -#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg) -#else -#define dbg_bulk(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_INTR -#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg) -#else -#define dbg_intr(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_TRACE -#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n")) -#define DBFEXIT (printk(KERN_DEBUG __FILE__ ": Exiting : " __FUNCTION__ "\n")) -#else -#define DBFENTER (NULL) -#define DBFEXIT (NULL) -#endif - -/*------------------------------------------------------------------- - Virtual Root Hub - -------------------------------------------------------------------*/ - -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, /* __u16 bcdUSB; v1.0 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static __u8 root_hub_hub_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x02, /* __u8 bNbrPorts; */ - 0x00, /* __u16 wHubCharacteristics; */ - 0x00, - 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ -}; - - -#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break -#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ -{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} - -static submit_urb_count = 0; - -//#define ETRAX_USB_INTR_IRQ -//#define ETRAX_USB_INTR_ERROR_FATAL - -#define RX_BUF_SIZE 32768 -#define RX_DESC_BUF_SIZE 64 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / RX_DESC_BUF_SIZE) - -#define NBR_OF_EP_DESC 32 - -#define MAX_INTR_INTERVAL 128 - -static __u32 ep_usage_bitmask; -static __u32 ep_really_active; - -static unsigned char RxBuf[RX_BUF_SIZE]; -static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); - -static volatile USB_IN_Desc_t *myNextRxDesc; -static volatile USB_IN_Desc_t *myLastRxDesc; -static volatile USB_IN_Desc_t *myPrevRxDesc; - -static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); -static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); - -static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4))); -static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); - -static struct urb *URB_List[NBR_OF_EP_DESC]; -static kmem_cache_t *usb_desc_cache; -static struct usb_bus *etrax_usb_bus; - -static void dump_urb (struct urb *urb); -static void init_rx_buffers(void); -static int etrax_rh_unlink_urb (struct urb *urb); -static void etrax_rh_send_irq(struct urb *urb); -static void etrax_rh_init_int_timer(struct urb *urb); -static void etrax_rh_int_timer_do(unsigned long ptr); - -static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, - char packsize, char slow); -static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp); -static int etrax_usb_allocate_epid(void); -static void etrax_usb_free_epid(char epid); -static void cleanup_sb(USB_SB_Desc_t *sb); - -static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags); -static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags); - -static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags); - -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags); -static int etrax_usb_unlink_urb(struct urb *urb); -static int etrax_usb_get_frame_number(struct usb_device *usb_dev); -static int etrax_usb_allocate_dev(struct usb_device *usb_dev); -static int etrax_usb_deallocate_dev(struct usb_device *usb_dev); - -static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs); - -static int etrax_rh_submit_urb (struct urb *urb); - -static int etrax_usb_hc_init(void); -static void etrax_usb_hc_cleanup(void); - -static struct usb_operations etrax_usb_device_operations = -{ - etrax_usb_allocate_dev, - etrax_usb_deallocate_dev, - etrax_usb_get_frame_number, - etrax_usb_submit_urb, - etrax_usb_unlink_urb -}; - -#ifdef USB_DEBUG_DESC -static void dump_urb(struct urb *urb) -{ - printk("\nurb :0x%08X\n", urb); - printk("next :0x%08X\n", urb->next); - printk("dev :0x%08X\n", urb->dev); - printk("pipe :0x%08X\n", urb->pipe); - printk("status :%d\n", urb->status); - printk("transfer_flags :0x%08X\n", urb->transfer_flags); - printk("transfer_buffer :0x%08X\n", urb->transfer_buffer); - printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length); - printk("actual_length :%d\n", urb->actual_length); - printk("setup_packet :0x%08X\n", urb->setup_packet); - printk("start_frame :%d\n", urb->start_frame); - printk("number_of_packets :%d\n", urb->number_of_packets); - printk("interval :%d\n", urb->interval); - printk("error_count :%d\n", urb->error_count); - printk("context :0x%08X\n", urb->context); - printk("complete :0x%08X\n\n", urb->complete); -} - -static void dump_in_desc(USB_IN_Desc_t *in) -{ - printk("\nUSB_IN_Desc at 0x%08X\n", in); - printk(" sw_len : 0x%04X (%d)\n", in->sw_len, in->sw_len); - printk(" command : 0x%04X\n", in->command); - printk(" next : 0x%08X\n", in->next); - printk(" buf : 0x%08X\n", in->buf); - printk(" hw_len : 0x%04X (%d)\n", in->hw_len, in->hw_len); - printk(" status : 0x%04X\n\n", in->status); -} - -static void dump_sb_desc(USB_SB_Desc_t *sb) -{ - printk("\nUSB_SB_Desc at 0x%08X\n", sb); - printk(" sw_len : 0x%04X (%d)\n", sb->sw_len, sb->sw_len); - printk(" command : 0x%04X\n", sb->command); - printk(" next : 0x%08X\n", sb->next); - printk(" buf : 0x%08X\n\n", sb->buf); -} - - -static void dump_ep_desc(USB_EP_Desc_t *ep) -{ - printk("\nUSB_EP_Desc at 0x%08X\n", ep); - printk(" hw_len : 0x%04X (%d)\n", ep->hw_len, ep->hw_len); - printk(" command : 0x%08X\n", ep->command); - printk(" sub : 0x%08X\n", ep->sub); - printk(" nep : 0x%08X\n\n", ep->nep); -} - - -#else -#define dump_urb(...) (NULL) -#define dump_ep_desc(...) (NULL) -#define dump_sb_desc(...) (NULL) -#define dump_in_desc(...) (NULL) -#endif - -static void init_rx_buffers(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].command = 0; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); - RxDescList[i].hw_len = 0; - RxDescList[i].status = 0; - } - - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); - RxDescList[i].hw_len = 0; - RxDescList[i].status = 0; - - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - - *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); - *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_ctrl_ep(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { - TxCtrlEPList[i].hw_len = 0; - TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); - TxCtrlEPList[i].sub = 0; - TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]); - } - - TxCtrlEPList[i].hw_len = 0; - TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | - IO_FIELD(USB_EP_command, epid, i); - - TxCtrlEPList[i].sub = 0; - TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]); - - *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); - *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_bulk_ep(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { - TxBulkEPList[i].hw_len = 0; - TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); - TxBulkEPList[i].sub = 0; - TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]); - } - - TxBulkEPList[i].hw_len = 0; - TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | - IO_FIELD(USB_EP_command, epid, i); - - TxBulkEPList[i].sub = 0; - TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]); - - *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]); - *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_intr_ep(void) -{ - int i; - - DBFENTER; - - TxIntrSB_zout.sw_len = 0; - TxIntrSB_zout.next = 0; - TxIntrSB_zout.buf = 0; - TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, zout) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { - TxIntrEPList[i].hw_len = 0; - TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | - IO_STATE(USB_EP_command, enable, yes) | - IO_FIELD(USB_EP_command, epid, 0); - TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); - TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]); - } - - TxIntrEPList[i].hw_len = 0; - TxIntrEPList[i].command = - IO_STATE(USB_EP_command, eof, yes) | - IO_STATE(USB_EP_command, enable, yes) | - IO_FIELD(USB_EP_command, epid, 0); - TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); - TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]); - - *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - DBFEXIT; -} - - -static int etrax_usb_unlink_intr_urb(struct urb *urb) -{ - struct usb_device *usb_dev = urb->dev; - etrax_hc_t *hc = usb_dev->bus->hcpriv; - - USB_EP_Desc_t *tmp_ep; - USB_EP_Desc_t *first_ep; - - USB_EP_Desc_t *ep_desc; - USB_SB_Desc_t *sb_desc; - - char epid; - char devnum; - char endpoint; - char slow; - int maxlen; - int i; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - slow = usb_pipeslow(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - err("Trying to unlink urb that is not in traffic queue!!"); - return -1; /* fix this */ - } - - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop); - /* Somehow wait for the DMA to finish current activities */ - i = jiffies + 100; - while (time_before(jiffies, i)) - ; - - first_ep = &TxIntrEPList[0]; - tmp_ep = first_ep; - - do { - if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command) - == epid) { - /* Unlink it !!! */ - dbg_intr("Found urb to unlink for epid %d", epid); - - ep_desc = phys_to_virt(tmp_ep->nep); - tmp_ep->nep = ep_desc->nep; - kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub)); - kmem_cache_free(usb_desc_cache, ep_desc); - } - - tmp_ep = phys_to_virt(tmp_ep->nep); - - } while (tmp_ep != first_ep); - - /* We should really try to move the EP register to an EP that is not removed - instead of restarting, but this will work too */ - *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - clear_bit(epid, (void *)&ep_really_active); - URB_List[epid] = NULL; - etrax_usb_free_epid(epid); - - DBFEXIT; - - return 0; -} - -void etrax_usb_do_intr_recover(int epid) -{ - USB_EP_Desc_t *first_ep, *tmp_ep; - - first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); - tmp_ep = first_ep; - - do { - if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && - !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { - tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); - } - - tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); - - } while (tmp_ep != first_ep); -} - -static int etrax_usb_submit_intr_urb(struct urb *urb, mem_flags) -{ - USB_EP_Desc_t *tmp_ep; - USB_EP_Desc_t *first_ep; - - USB_SB_Desc_t *sb_desc; - - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - int interval; - int i; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - slow = usb_pipeslow(urb->pipe); - interval = urb->interval; - - dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d", - devnum, endpoint, maxlen, slow); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - urb_priv->first_sb = 0; - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - INIT_LIST_HEAD(&urb_priv->ep_in_list); - urb->hcpriv = urb_priv; - - /* This is safe since there cannot be any other URB's for this epid */ - URB_List[epid] = urb; -#if 0 - first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); -#else - first_ep = &TxIntrEPList[0]; -#endif - - /* Round of the interval to 2^n, it is obvious that this code favours - smaller numbers, but that is actually a good thing */ - for (i = 0; interval; i++) { - interval = interval >> 1; - } - - urb->interval = interval = 1 << (i - 1); - - dbg_intr("Interval rounded to %d", interval); - - tmp_ep = first_ep; - i = 0; - do { - if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { - if ((i % interval) == 0) { - /* Insert the traffic ep after tmp_ep */ - USB_EP_Desc_t *traffic_ep; - USB_SB_Desc_t *traffic_sb; - - traffic_ep = (USB_EP_Desc_t *) - kmem_cache_alloc(usb_desc_cache, mem_flags); - traffic_sb = (USB_SB_Desc_t *) - kmem_cache_alloc(usb_desc_cache, mem_flags); - - traffic_ep->hw_len = 0; - traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) | - IO_STATE(USB_EP_command, enable, yes); - traffic_ep->sub = virt_to_phys(traffic_sb); - - if (usb_pipein(urb->pipe)) { - traffic_sb->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - traffic_sb->next = 0; - traffic_sb->buf = 0; - traffic_sb->command = IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - } else if (usb_pipeout(urb->pipe)) { - traffic_sb->sw_len = urb->transfer_buffer_length; - traffic_sb->next = 0; - traffic_sb->buf = virt_to_phys(urb->transfer_buffer); - traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, out) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes) | - IO_STATE(USB_SB_command, full, yes); - } - - traffic_ep->nep = tmp_ep->nep; - tmp_ep->nep = virt_to_phys(traffic_ep); - dbg_intr("One ep sucessfully inserted"); - } - i++; - } - tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); - } while (tmp_ep != first_ep); - - set_bit(epid, (void *)&ep_really_active); - - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - DBFEXIT; - - return 0; -} - - -static int handle_intr_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - - DBFENTER; - - old_urb = URB_List[epid]; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - unsigned long flags; - etrax_urb_priv_t *urb_priv; - struct list_head *entry; - struct in_chunk *in; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - - save_flags(flags); - cli(); - - list_for_each(entry, &urb_priv->ep_in_list) { - in = list_entry(entry, struct in_chunk, list); - memcpy(old_urb->transfer_buffer, in->data, in->length); - old_urb->actual_length = in->length; - old_urb->status = status; - - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - list_del(entry); - kfree(in->data); - kfree(in); - } - - restore_flags(flags); - - } else if (status != 0) { - warn("Some sort of error for INTR EP !!!!"); -#ifdef ETRAX_USB_INTR_ERROR_FATAL - /* This means that an INTR error is fatal for that endpoint */ - etrax_usb_unlink_intr_urb(old_urb); - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } -#else - /* In this case we reenable the disabled endpoint(s) */ - etrax_usb_do_intr_recover(epid); -#endif - } - - DBFEXIT; -} - -static int etrax_rh_unlink_urb (struct urb *urb) -{ - etrax_hc_t *hc; - - DBFENTER; - - hc = urb->dev->bus->hcpriv; - - if (hc->rh.urb == urb) { - hc->rh.send = 0; - del_timer(&hc->rh.rh_int_timer); - } - - DBFEXIT; - return 0; -} - -static void etrax_rh_send_irq(struct urb *urb) -{ - __u16 data = 0; - etrax_hc_t *hc = urb->dev->bus->hcpriv; -// static prev_wPortStatus_1 = 0; -// static prev_wPortStatus_2 = 0; - -/* DBFENTER; */ - - -/* - dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); - dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING); -*/ - - data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; - data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; - - *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); - urb->actual_length = 1; - urb->status = 0; - - - if (data && hc->rh.send && urb->complete) { - dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); - dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); - - urb->complete(urb); - } - -/* DBFEXIT; */ -} - -static void etrax_rh_init_int_timer(struct urb *urb) -{ - etrax_hc_t *hc; - -/* DBFENTER; */ - - hc = urb->dev->bus->hcpriv; - hc->rh.interval = urb->interval; - init_timer(&hc->rh.rh_int_timer); - hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; - hc->rh.rh_int_timer.data = (unsigned long)urb; - hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); - add_timer(&hc->rh.rh_int_timer); - -/* DBFEXIT; */ -} - -static void etrax_rh_int_timer_do(unsigned long ptr) -{ - struct urb *urb; - etrax_hc_t *hc; - -/* DBFENTER; */ - - urb = (struct urb *)ptr; - hc = urb->dev->bus->hcpriv; - - if (hc->rh.send) { - etrax_rh_send_irq(urb); - } - - etrax_rh_init_int_timer(urb); - -/* DBFEXIT; */ -} - -static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow) -{ - unsigned long flags; - - DBFENTER; - - save_flags(flags); - cli(); - - if (test_bit(epid, (void *)&ep_usage_bitmask)) { - restore_flags(flags); - - warn("Trying to setup used epid %d", epid); - DBFEXIT; - return; - } - - set_bit(epid, (void *)&ep_usage_bitmask); - dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d", - epid, devnum, endpoint, packsize); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); - nop(); - *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | - IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | - IO_FIELD(R_USB_EPT_DATA, dev, devnum) | - IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | - IO_FIELD(R_USB_EPT_DATA, low_speed, slow); - - restore_flags(flags); - - DBFEXIT; -} - -static void etrax_usb_free_epid(char epid) -{ - unsigned long flags; - - DBFENTER; - - if (!test_bit(epid, (void *)&ep_usage_bitmask)) { - warn("Trying to free unused epid %d", epid); - DBFEXIT; - return; - } - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); - nop(); - while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) - printk("+"); - *R_USB_EPT_DATA = 0; - clear_bit(epid, (void *)&ep_usage_bitmask); - - restore_flags(flags); - - dbg_ep("epid: %d freed", epid); - - DBFEXIT; -} - - -static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp) -{ - int i; - unsigned long flags; - __u32 data; - - DBFENTER; - - save_flags(flags); - - /* Skip first ep_id since it is reserved when intr. or iso traffic is used */ - for (i = 0; i < NBR_OF_EP_DESC; i++) { - if (test_bit(i, (void *)&ep_usage_bitmask)) { - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); - nop(); - data = *R_USB_EPT_DATA; - if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && - (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && - (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && - (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && - (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) { - restore_flags(flags); - - dbg_ep("Found ep_id %d for devnum %d, endpoint %d", - i, devnum, endpoint); - DBFEXIT; - return i; - } - } - } - - restore_flags(flags); - - dbg_ep("Found no ep_id for devnum %d, endpoint %d", - devnum, endpoint); - DBFEXIT; - return -1; -} - -static int etrax_usb_allocate_epid(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < NBR_OF_EP_DESC; i++) { - if (!test_bit(i, (void *)&ep_usage_bitmask)) { - dbg_ep("Found free ep_id at %d", i); - DBFEXIT; - return i; - } - } - - dbg_ep("Found no free ep_id's"); - DBFEXIT; - return -1; -} - -static int etrax_usb_submit_bulk_urb(struct urb *urb, int mem_flags) -{ - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - - struct urb *tmp_urb; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - slow = usb_pipeslow(urb->pipe); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb->status = -EINPROGRESS; - - save_flags(flags); - cli(); - - if (URB_List[epid]) { - /* Find end of list and add */ - for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) - dump_urb(tmp_urb); - - tmp_urb->next = urb; - restore_flags(flags); - } else { - /* If this is the first URB, add the URB and do HW add */ - URB_List[epid] = urb; - restore_flags(flags); - etrax_usb_do_bulk_hw_add(urb, epid, maxlen, mem_flags); - } - - DBFEXIT; - - return 0; -} - -static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags) -{ - USB_SB_Desc_t *sb_desc_1; - - etrax_urb_priv_t *urb_priv; - - unsigned long flags; - __u32 r_usb_ept_data; - - DBFENTER; - - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - if (usb_pipeout(urb->pipe)) { - - dbg_bulk("Bulk transfer for epid %d is OUT", epid); - dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length); - dbg_bulk("actual_length == %d", urb->actual_length); - - if (urb->transfer_buffer_length > 0xffff) { - panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n"); - } - - sb_desc_1->sw_len = urb->transfer_buffer_length; /* was actual_length */ - sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, out) | - -#if 0 - IO_STATE(USB_SB_command, full, no) | -#else - IO_STATE(USB_SB_command, full, yes) | -#endif - - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); - - sb_desc_1->buf = virt_to_phys(urb->transfer_buffer); - sb_desc_1->next = 0; - - } else if (usb_pipein(urb->pipe)) { - - dbg_bulk("Transfer for epid %d is IN", epid); - dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length); - dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen); - - sb_desc_1->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - dbg_bulk("sw_len got %d", sb_desc_1->sw_len); - dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); - - sb_desc_1->command = - IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_1->buf = 0; - sb_desc_1->next = 0; - - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - } - - urb_priv->first_sb = sb_desc_1; - - urb->hcpriv = (void *)urb_priv; - - /* Reset toggle bits and reset error count, remeber to di and ei */ - /* Warning: it is possible that this locking doesn't work with bottom-halves */ - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { - panic("Hold was set in %s\n", __FUNCTION__); - } - - *R_USB_EPT_DATA &= - ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | - IO_MASK(R_USB_EPT_DATA, error_count_out)); - - if (usb_pipeout(urb->pipe)) { - char toggle = - usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); - *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); - *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); - } else { - char toggle = - usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); - *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); - *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); - } - - /* Enable the EP descr. */ - - set_bit(epid, (void *)&ep_really_active); - - TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1); - TxBulkEPList[epid].hw_len = 0; - TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); - - restore_flags(flags); - - if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { - *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); - - } - - DBFEXIT; -} - -static int handle_bulk_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - etrax_urb_priv_t *hc_priv; - unsigned long flags; - - DBFENTER; - - clear_bit(epid, (void *)&ep_really_active); - - old_urb = URB_List[epid]; - URB_List[epid] = old_urb->next; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - etrax_urb_priv_t *urb_priv; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - save_flags(flags); - cli(); - if (urb_priv->eot == 1) { - old_urb->actual_length = urb_priv->rx_offset; - } else { - if (urb_priv->rx_offset == 0) { - status = 0; - } else { - status = -EPROTO; - } - - old_urb->actual_length = 0; - err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset); - } - - restore_flags(flags); - } - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (usb_pipeout(old_urb->pipe)) { - char toggle = - IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); - usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), - usb_pipeout(old_urb->pipe), toggle); - } else { - char toggle = - IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); - usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), - usb_pipeout(old_urb->pipe), toggle); - } - restore_flags(flags); - - /* If there are any more URB's in the list we'd better start sending */ - if (URB_List[epid]) { - etrax_usb_do_bulk_hw_add(URB_List[epid], epid, - usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, - usb_pipeout(URB_List[epid]->pipe)), - GFP_KERNEL); - } -#if 1 - else { - /* This means that this EP is now free, deconfigure it */ - etrax_usb_free_epid(epid); - } -#endif - - /* Remember to free the SB's */ - hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - DBFEXIT; -} - -/* ---------------------------------------------------------------------------- */ - -static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags) -{ - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - - struct urb *tmp_urb; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - slow = usb_pipeslow(urb->pipe); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb->status = -EINPROGRESS; - - save_flags(flags); - cli(); - - if (URB_List[epid]) { - /* Find end of list and add */ - for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) - dump_urb(tmp_urb); - - tmp_urb->next = urb; - restore_flags(flags); - } else { - /* If this is the first URB, add the URB and do HW add */ - URB_List[epid] = urb; - restore_flags(flags); - etrax_usb_do_ctrl_hw_add(urb, epid, maxlen, mem_flags); - } - - DBFEXIT; - - return 0; -} - -static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags) -{ - USB_SB_Desc_t *sb_desc_1; - USB_SB_Desc_t *sb_desc_2; - USB_SB_Desc_t *sb_desc_3; - - etrax_urb_priv_t *urb_priv; - - unsigned long flags; - __u32 r_usb_ept_data; - - - DBFENTER; - - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - if (!(sb_desc_1 && sb_desc_2)) { - panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n"); - } - - sb_desc_1->sw_len = 8; - sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, setup) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes); - - sb_desc_1->buf = virt_to_phys(urb->setup_packet); - sb_desc_1->next = virt_to_phys(sb_desc_2); - dump_sb_desc(sb_desc_1); - - if (usb_pipeout(urb->pipe)) { - dbg_ctrl("Transfer for epid %d is OUT", epid); - - /* If this Control OUT transfer has an optional data stage we add an OUT token - before the mandatory IN (status) token, hence the reordered SB list */ - - if (urb->transfer_buffer) { - dbg_ctrl("This OUT transfer has an extra data stage"); - sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - sb_desc_1->next = virt_to_phys(sb_desc_3); - - sb_desc_3->sw_len = urb->transfer_buffer_length; - sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes); - sb_desc_3->buf = virt_to_phys(urb->transfer_buffer); - sb_desc_3->next = virt_to_phys(sb_desc_2); - } - - sb_desc_2->sw_len = 1; - sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_2->buf = 0; - sb_desc_2->next = 0; - dump_sb_desc(sb_desc_2); - - } else if (usb_pipein(urb->pipe)) { - - dbg_ctrl("Transfer for epid %d is IN", epid); - dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); - dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); - - sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - sb_desc_2->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - dbg_ctrl("sw_len got %d", sb_desc_2->sw_len); - - sb_desc_2->command = - IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes); - - sb_desc_2->buf = 0; - sb_desc_2->next = virt_to_phys(sb_desc_3); - dump_sb_desc(sb_desc_2); - - sb_desc_3->sw_len = 1; - sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, zout) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_3->buf = 0; - sb_desc_3->next = 0; - dump_sb_desc(sb_desc_3); - - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - } - - urb_priv->first_sb = sb_desc_1; - - urb->hcpriv = (void *)urb_priv; - - /* Reset toggle bits and reset error count, remeber to di and ei */ - /* Warning: it is possible that this locking doesn't work with bottom-halves */ - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { - panic("Hold was set in %s\n", __FUNCTION__); - } - - - *R_USB_EPT_DATA &= - ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | - IO_MASK(R_USB_EPT_DATA, error_count_out) | - IO_MASK(R_USB_EPT_DATA, t_in) | - IO_MASK(R_USB_EPT_DATA, t_out)); - - /* Enable the EP descr. */ - - set_bit(epid, (void *)&ep_really_active); - - TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1); - TxCtrlEPList[epid].hw_len = 0; - TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); - - restore_flags(flags); - - dump_ep_desc(&TxCtrlEPList[epid]); - - if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) { - *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); - - } - - DBFEXIT; -} - -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags) -{ - etrax_hc_t *hc; - int rval = -EINVAL; - - DBFENTER; - - dump_urb(urb); - submit_urb_count++; - - hc = (etrax_hc_t*) urb->dev->bus->hcpriv; - - if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { - /* This request if for the Virtual Root Hub */ - rval = etrax_rh_submit_urb(urb); - - } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { - rval = etrax_usb_submit_ctrl_urb(urb, mem_flags); - - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - rval = etrax_usb_submit_bulk_urb(urb, mem_flags); - - } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - int bustime; - - if (urb->bandwidth == 0) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - rval = bustime; - } else { - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - rval = etrax_usb_submit_intr_urb(urb, mem_flags); - } - - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - warn("Isochronous traffic is not supported !!!"); - rval = -EINVAL; - } - - DBFEXIT; - - return rval; -} - -static int etrax_usb_unlink_urb(struct urb *urb) -{ - etrax_hc_t *hc = urb->dev->bus->hcpriv; - int epid; - int pos; - int devnum, endpoint, slow, maxlen; - etrax_urb_priv_t *hc_priv; - unsigned long flags; - - DBFENTER; - dump_urb(urb); - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - slow = usb_pipeslow(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - - if (epid == -1) - return 0; - - - if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { - int ret; - ret = etrax_rh_unlink_urb(urb); - DBFEXIT; - return ret; - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - int ret; - ret = etrax_usb_unlink_intr_urb(urb); - urb->status = -ENOENT; - if (urb->complete) { - urb->complete(urb); - } - DBFEXIT; - return ret; - } - - info("Unlink of BULK or CTRL"); - - save_flags(flags); - cli(); - - for (epid = 0; epid < 32; epid++) { - struct urb *u = URB_List[epid]; - pos = 0; - - for (; u; u = u->next) { - pos++; - if (u == urb) { - info("Found urb at epid %d, pos %d", epid, pos); - - if (pos == 1) { - if (usb_pipetype(u->pipe) == PIPE_CONTROL) { - if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { - /* The EP was enabled, disable it and wait */ - TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); - while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); - } - - } else if (usb_pipetype(u->pipe) == PIPE_BULK) { - if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { - TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); - while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); - } - } - - URB_List[epid] = u->next; - - } else { - struct urb *up; - for (up = URB_List[epid]; up->next != u; up = up->next); - up->next = u->next; - } - u->status = -ENOENT; - if (u->complete) { - u->complete(u); - } - - hc_priv = (etrax_urb_priv_t *)u->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - } - } - } - - restore_flags(flags); - - DBFEXIT; - return 0; -} - -static int etrax_usb_get_frame_number(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return (*R_USB_FM_NUMBER); -} - -static int etrax_usb_allocate_dev(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return 0; -} - -static int etrax_usb_deallocate_dev(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return 0; -} - -static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs) -{ - etrax_hc_t *hc = (etrax_hc_t *)vhc; - int epid; - char eol; - struct urb *urb; - USB_EP_Desc_t *tmp_ep; - USB_SB_Desc_t *tmp_sb; - - DBFENTER; - - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { - info("dma8_sub0_descr (BULK) intr."); - *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { - info("dma8_sub1_descr (CTRL) intr."); - *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { - info("dma8_sub2_descr (INT) intr."); - *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { - info("dma8_sub3_descr (ISO) intr."); - *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); - } - - DBFEXIT; -} - -static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs) -{ - int epid = 0; - struct urb *urb; - etrax_urb_priv_t *urb_priv; - - *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); - - while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { - if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { - - goto skip_out; - } - - if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { - - goto skip_out; - } - - epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); - - urb = URB_List[epid]; - - if (urb && usb_pipein(urb->pipe)) { - urb_priv = (etrax_urb_priv_t *)urb->hcpriv; - - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - struct in_chunk *in; - dbg_intr("Packet for epid %d in rx buffers", epid); - in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC); - in->length = myNextRxDesc->hw_len; - in->data = kmalloc(in->length, GFP_ATOMIC); - memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length); - list_add_tail(&in->list, &urb_priv->ep_in_list); -#ifndef ETRAX_USB_INTR_IRQ - etrax_usb_hc_intr_top_half(irq, vhc, regs); -#endif - - } else { - if ((urb_priv->rx_offset + myNextRxDesc->hw_len) > - urb->transfer_buffer_length) { - err("Packet (epid: %d) in RX buffer was bigger " - "than the URB has room for !!!", epid); - goto skip_out; - } - - memcpy(urb->transfer_buffer + urb_priv->rx_offset, - phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); - - urb_priv->rx_offset += myNextRxDesc->hw_len; - } - - if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { - urb_priv->eot = 1; - } - - } else { - err("This is almost fatal, inpacket for epid %d which does not exist " - " or is out !!!\nURB was at 0x%08X", epid, urb); - - goto skip_out; - } - - skip_out: - myPrevRxDesc = myNextRxDesc; - myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); - myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); - myLastRxDesc = myPrevRxDesc; - - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } -} - - - -static void cleanup_sb(USB_SB_Desc_t *sb) -{ - USB_SB_Desc_t *next_sb; - - DBFENTER; - - if (sb == NULL) { - err("cleanup_sb was given a NULL pointer"); - return; - } - - while (!(sb->command & IO_MASK(USB_SB_command, eol))) { - next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next); - kmem_cache_free(usb_desc_cache, sb); - sb = next_sb; - } - - kmem_cache_free(usb_desc_cache, sb); - - DBFEXIT; - -} - -static int handle_control_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - etrax_urb_priv_t *hc_priv; - - DBFENTER; - - clear_bit(epid, (void *)&ep_really_active); - - old_urb = URB_List[epid]; - URB_List[epid] = old_urb->next; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - unsigned long flags; - etrax_urb_priv_t *urb_priv; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - save_flags(flags); - cli(); - if (urb_priv->eot == 1) { - old_urb->actual_length = urb_priv->rx_offset; - dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset); - } else { - status = -EPROTO; - old_urb->actual_length = 0; - err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset); - } - - restore_flags(flags); - } - - /* If there are any more URB's in the list we'd better start sending */ - if (URB_List[epid]) { - etrax_usb_do_ctrl_hw_add(URB_List[epid], epid, - usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, - usb_pipeout(URB_List[epid]->pipe)), - GFP_KERNEL); - } -#if 1 - else { - /* This means that this EP is now free, deconfigure it */ - etrax_usb_free_epid(epid); - } -#endif - - /* Remember to free the SB's */ - hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - DBFEXIT; -} - - - -static void etrax_usb_hc_intr_bottom_half(void *data) -{ - struct usb_reg_context *reg = (struct usb_reg_context *)data; - struct urb *old_urb; - - int error_code; - int epid; - - __u32 r_usb_ept_data; - - etrax_hc_t *hc = reg->hc; - __u16 r_usb_rh_port_status_1; - __u16 r_usb_rh_port_status_2; - - DBFENTER; - - if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { - - /* - The Etrax RH does not include a wPortChange register, so this has - to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec - for details. - */ - - r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; - r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; - - dbg_rh("port_status pending"); - dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1); - dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2); - - /* C_PORT_CONNECTION is set on any transition */ - hc->rh.wPortChange_1 |= - ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != - (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? - (1 << RH_PORT_CONNECTION) : 0; - - hc->rh.wPortChange_2 |= - ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != - (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? - (1 << RH_PORT_CONNECTION) : 0; - - /* C_PORT_ENABLE is _only_ set on a one to zero transition */ - hc->rh.wPortChange_1 |= - ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) - && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_ENABLE) : 0; - - hc->rh.wPortChange_2 |= - ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) - && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_ENABLE) : 0; - - /* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */ - - /* C_PORT_RESET is _only_ set on a transition from the resetting state - to the enabled state */ - hc->rh.wPortChange_1 |= - ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) - && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_RESET) : 0; - - hc->rh.wPortChange_2 |= - ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) - && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_RESET) : 0; - - hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; - hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; - } - - for (epid = 0; epid < 32; epid++) { - - unsigned long flags; - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - r_usb_ept_data = *R_USB_EPT_DATA; - - restore_flags(flags); - - if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { - warn("Was hold for epid %d", epid); - continue; - } - - if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { - continue; - } - - - if (test_bit(epid, (void *)®->r_usb_epid_attn)) { - - if (URB_List[epid] == NULL) { - err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data); - err("submit urb has been called %d times..", submit_urb_count); - err("EPID_ATTN for epid %d, with NULL entry in list", epid); - return; - } - - dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid, - r_usb_ept_data); - - error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, - r_usb_ept_data); - - if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* no_error means that this urb was sucessfully sent or that we have - some undefinde error*/ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || - IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) { - /* Actually there were transmission errors */ - warn("Undefined error for endpoint %d", epid); - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPROTO); - } - - } else { - - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - etrax_usb_do_intr_recover(epid); - } else { - panic("Epid attention for epid %d (none INTR), with no errors and no " - "exessive retry r_usb_status is 0x%02X\n", - epid, reg->r_usb_status); - } - - } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { - panic("Epid attention for epid %d, with no errors and no " - "exessive retry r_usb_status is 0x%02X\n", - epid, reg->r_usb_status); - - } - - warn("Epid attention for epid %d, with no errors and no " - "exessive retry r_usb_status is 0x%02X", - epid, reg->r_usb_status); - warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out, - r_usb_ept_data)); - warn("IN error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in, - r_usb_ept_data)); - - - } - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { - warn("Stall for endpoint %d", epid); - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPIPE); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPIPE); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPIPE); - } - - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { - panic("USB bus error for endpoint %d\n", epid); - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { - warn("Buffer error for endpoint %d", epid); - - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPROTO); - } - - } - } else if (test_bit(epid, (void *)&ep_really_active)) { - /* Should really be else if (testbit(really active)) */ - - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - - if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) { - /* Now we have to verify that this CTRL endpoint got disabled - cause it reached end of list with no error */ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == - IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* - This means that the endpoint has no error, is disabled - and had inserted traffic, - i.e. transfer sucessfully completed - */ - dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); - handle_control_transfer_attn(epid, 0); - } - } - - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) { - /* Now we have to verify that this BULK endpoint go disabled - cause it reached end of list with no error */ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == - IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* - This means that the endpoint has no error, is disabled - and had inserted traffic, - i.e. transfer sucessfully completed - */ - dbg_bulk("Last SB for BULK %d sent sucessfully", epid); - handle_bulk_transfer_attn(epid, 0); - } - } - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, 0); - } - } - - } - - kfree(reg); - - DBFEXIT; -} - - -static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs) -{ - struct usb_reg_context *reg; - - DBFENTER; - - reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC); - - if (!(reg)) { - panic("kmalloc failed in top_half\n"); - } - - reg->hc = (etrax_hc_t *)vhc; - reg->r_usb_irq_mask_read = *R_USB_IRQ_MASK_READ; - reg->r_usb_status = *R_USB_STATUS; - -#if 0 - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { - panic("r_usb_status said perror\n"); - } - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { - panic("r_usb_status said ourun !!!\n"); - } -#endif - - reg->r_usb_epid_attn = *R_USB_EPID_ATTN; - - reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1; - reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2; - - reg->usb_bh.sync = 0; - reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half; - reg->usb_bh.data = reg; - - queue_task(®->usb_bh, &tq_immediate); - mark_bh(IMMEDIATE_BH); - - DBFEXIT; -} - -static int etrax_rh_submit_urb(struct urb *urb) -{ - struct usb_device *usb_dev = urb->dev; - etrax_hc_t *hc = usb_dev->bus->hcpriv; - unsigned int pipe = urb->pipe; - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; - void *data = urb->transfer_buffer; - int leni = urb->transfer_buffer_length; - int len = 0; - int status = 0; - int stat = 0; - int i; - - __u16 cstatus; - - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - - DBFENTER; - - if (usb_pipetype (pipe) == PIPE_INTERRUPT) { - dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); - hc->rh.urb = urb; - hc->rh.send = 1; - hc->rh.interval = urb->interval; - etrax_rh_init_int_timer(urb); - DBFEXIT; - - return 0; - } - - bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; - wValue = le16_to_cpu(cmd->wValue); - wIndex = le16_to_cpu(cmd->wIndex); - wLength = le16_to_cpu(cmd->wLength); - - dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); - dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); - dbg_rh("wIndex : 0x%04X (%d)", wIndex, wIndex); - dbg_rh("wLength : 0x%04X (%d)", wLength, wLength); - - switch (bmRType_bReq) { - - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *) data = cpu_to_le16 (1); - OK (2); - - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data = cpu_to_le32 (0); - OK (4); /* hub power ** */ - - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - if (wIndex == 1) { - *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); - *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); - } - else if (wIndex == 2) { - *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); - *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); - } - else { - dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); - OK(0); - } - - OK(4); - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case (RH_ENDPOINT_STALL): - OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case (RH_C_HUB_OVER_CURRENT): - OK (0); /* hub power over current ** */ - } - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_ENABLE): - if (wIndex == 1) { - - dbg_rh("trying to do disable of port 1"); - - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); - while (hc->rh.prev_wPortStatus_1 & - IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); - dbg_rh("Port 1 is disabled"); - - } else if (wIndex == 2) { - - dbg_rh("trying to do disable of port 2"); - - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); - while (hc->rh.prev_wPortStatus_2 & - IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); - dbg_rh("Port 2 is disabled"); - - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_SUSPEND): - /* Opposite to suspend should be resume, so well do a resume */ - if (wIndex == 1) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, resume)| - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else if (wIndex == 2) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port2) | - IO_STATE(R_USB_COMMAND, port_cmd, resume)| - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_POWER): - OK (0); /* port power ** */ - case (RH_C_PORT_CONNECTION): - - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); - } - else if (wIndex == 2) { - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); - } - else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_C_PORT_ENABLE): - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); - } - else if (wIndex == 2) { - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); - } - else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " - "with invalid wIndex == %d!!", wIndex); - } - OK (0); - case (RH_C_PORT_SUSPEND): -/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ - OK (0); - case (RH_C_PORT_OVER_CURRENT): - OK (0); /* port power over current ** */ - case (RH_C_PORT_RESET): - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); - } - else if (wIndex == 2) { - dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2); - - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); - dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2); - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " - "with invalid index == %d!!", wIndex); - } - - OK (0); - - } - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_SUSPEND): - if (wIndex == 1) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, suspend) | - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else if (wIndex == 2) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port2) | - IO_STATE(R_USB_COMMAND, port_cmd, suspend) | - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else { - dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_RESET): - if (wIndex == 1) { - int port1_retry; - - port1_redo: - dbg_rh("Doing reset of port 1"); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_sel, port1); - - /* We must once again wait at least 10ms for the device to recover */ - - port1_retry = 0; - while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) & - IO_STATE(R_USB_RH_PORT_STATUS_1, - enabled, yes))) { - printk(""); if (port1_retry++ >= 10000) {goto port1_redo;} - } - - /* This only seems to work if we use printk, - not even schedule() works !!! WHY ?? */ - - udelay(15000); - } - else if (wIndex == 2) { - int port2_retry; - - port2_redo: - dbg_rh("Doing reset of port 2"); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_sel, port2); - - /* We must once again wait at least 10ms for the device to recover */ - - port2_retry = 0; - while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) & - IO_STATE(R_USB_RH_PORT_STATUS_2, - enabled, yes))) { - printk(""); if (port2_retry++ >= 10000) {goto port2_redo;} - } - - /* This only seems to work if we use printk, - not even schedule() works !!! WHY ?? */ - - udelay(15000); - } - - /* Try to bring the HC into running state */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - dbg_rh("...Done"); - OK(0); - - case (RH_PORT_POWER): - OK (0); /* port power ** */ - case (RH_PORT_ENABLE): - /* There is no rh port enable command in the Etrax USB interface!!!! */ - OK (0); - - } - break; - - case RH_SET_ADDRESS: - hc->rh.devnum = wValue; - dbg_rh("RH address set to: %d", hc->rh.devnum); - OK (0); - - case RH_GET_DESCRIPTOR: - switch ((wValue & 0xff00) >> 8) { - case (0x01): /* device descriptor */ - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength)); - memcpy (data, root_hub_dev_des, len); - OK (len); - case (0x02): /* configuration descriptor */ - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength)); - memcpy (data, root_hub_config_des, len); - OK (len); - case (0x03): /* string descriptors */ - len = usb_root_hub_string (wValue & 0xff, - 0xff, "ETRAX 100LX", - data, wLength); - if (len > 0) { - OK(min_t(int, leni, len)); - } else - stat = -EPIPE; - } - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: - root_hub_hub_des[2] = hc->rh.numports; - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength)); - memcpy (data, root_hub_hub_des, len); - OK (len); - - case RH_GET_CONFIGURATION: - *(__u8 *) data = 0x01; - OK (1); - - case RH_SET_CONFIGURATION: - OK (0); - - default: - stat = -EPIPE; - } - - urb->actual_length = len; - urb->status = stat; - urb->dev=NULL; - if (urb->complete) { - urb->complete (urb); - } - DBFEXIT; - - return 0; -} - -static int __init etrax_usb_hc_init(void) -{ - static etrax_hc_t *hc; - struct usb_bus *bus; - struct usb_device *usb_rh; - - DBFENTER; - - info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version); - - hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); - - /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ - usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0); - if (!usb_desc_cache) { - panic("USB Desc Cache allocation failed !!!\n"); - } - - etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); - hc->bus = bus; - bus->hcpriv = hc; - - /* Initalize RH to the default address. - And make sure that we have no status change indication */ - hc->rh.numports = 2; /* The RH has two ports */ - hc->rh.devnum = 0; - hc->rh.wPortChange_1 = 0; - hc->rh.wPortChange_2 = 0; - - /* Also initate the previous values to zero */ - hc->rh.prev_wPortStatus_1 = 0; - hc->rh.prev_wPortStatus_2 = 0; - - /* Initialize the intr-traffic flags */ - hc->intr.sleeping = 0; - hc->intr.wq = NULL; - - /* Initially all ep's are free except ep 0 */ - ep_usage_bitmask = 0; - set_bit(0, (void *)&ep_usage_bitmask); - ep_really_active = 0; - - memset(URB_List, 0, sizeof(URB_List)); - - /* This code should really be moved */ - - if (request_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)")) { - err("Could not allocate DMA ch 8 for USB"); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)")) { - err("Could not allocate DMA ch 9 for USB"); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } -#if 0 /* Moved to head.S */ - *R_GEN_CONFIG = genconfig_shadow = - (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | - IO_MASK(R_GEN_CONFIG, usb2) | - IO_MASK(R_GEN_CONFIG, dma8) | - IO_MASK(R_GEN_CONFIG, dma9))) | - IO_STATE(R_GEN_CONFIG, dma8, usb) | - IO_STATE(R_GEN_CONFIG, dma9, usb) -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - | IO_STATE(R_GEN_CONFIG, usb1, select) -#endif -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - | IO_STATE(R_GEN_CONFIG, usb2, select) -#endif - ; -#endif - - usb_register_bus(hc->bus); - - /* We may have to set more bits, but these are the obvious ones */ - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); - - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); - - *R_USB_IRQ_MASK_SET = - IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) | - IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) | - IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) | -#ifdef ETRAX_USB_INTR_IRQ - IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) | -#endif - IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | - IO_STATE(R_USB_IRQ_MASK_SET, port_status, set); - - if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0, - "ETRAX 100LX built-in USB (HC)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, - "ETRAX 100LX built-in USB (Rx)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0, - "ETRAX 100LX built-in USB (Tx)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - /* Reset the USB interface (configures as HC) */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); -#if 1 - /* Initate PSTART to all unallocatable bit times */ - *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 10000); -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); -#endif - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - /* Here we must wait at least 10ms so the device has time to recover */ - udelay(15000); - - init_rx_buffers(); - init_tx_bulk_ep(); - init_tx_ctrl_ep(); - init_tx_intr_ep(); - - /* This works. It seems like the host_run command only has effect when a device is connected, - i.e. it has to be done when a interrup */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - usb_rh = usb_alloc_dev(NULL, hc->bus); - hc->bus->root_hub = usb_rh; - usb_connect(usb_rh); - usb_new_device(usb_rh); - - DBFEXIT; - - return 0; -} - -static void etrax_usb_hc_cleanup(void) -{ - DBFENTER; - - free_irq(ETRAX_USB_HC_IRQ, NULL); - free_irq(ETRAX_USB_RX_IRQ, NULL); - free_irq(ETRAX_USB_TX_IRQ, NULL); - - free_dma(USB_TX_DMA_NBR); - free_dma(USB_RX_DMA_NBR); - usb_deregister_bus(etrax_usb_bus); - - DBFEXIT; -} - -module_init(etrax_usb_hc_init); -module_exit(etrax_usb_hc_cleanup); diff --git a/arch/cris/drivers/usb-host.h b/arch/cris/drivers/usb-host.h deleted file mode 100644 index 434d50b2602..00000000000 --- a/arch/cris/drivers/usb-host.h +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef __LINUX_ETRAX_USB_H -#define __LINUX_ETRAX_USB_H - -#include -#include - -typedef struct USB_IN_Desc { - __u16 sw_len; - __u16 command; - unsigned long next; - unsigned long buf; - __u16 hw_len; - __u16 status; -} USB_IN_Desc_t; - -typedef struct USB_SB_Desc { - __u16 sw_len; - __u16 command; - unsigned long next; - unsigned long buf; - __u32 dummy; -} USB_SB_Desc_t; - -typedef struct USB_EP_Desc { - __u16 hw_len; - __u16 command; - unsigned long sub; - unsigned long nep; - __u32 dummy; -} USB_EP_Desc_t; - -struct virt_root_hub { - int devnum; - void *urb; - void *int_addr; - int send; - int interval; - int numports; - struct timer_list rh_int_timer; - __u16 wPortChange_1; - __u16 wPortChange_2; - __u16 prev_wPortStatus_1; - __u16 prev_wPortStatus_2; -}; - -struct etrax_usb_intr_traffic { - int sleeping; - int error; - struct wait_queue *wq; -}; - -typedef struct etrax_usb_hc { - struct usb_bus *bus; - struct virt_root_hub rh; - struct etrax_usb_intr_traffic intr; -} etrax_hc_t; - -typedef enum {idle, eot, nodata} etrax_usb_rx_state_t; - -typedef struct etrax_usb_urb_priv { - USB_SB_Desc_t *first_sb; - __u32 rx_offset; - etrax_usb_rx_state_t rx_state; - __u8 eot; - struct list_head ep_in_list; -} etrax_urb_priv_t; - - -struct usb_reg_context -{ - etrax_hc_t *hc; - __u32 r_usb_epid_attn; - __u8 r_usb_status; - __u32 r_usb_rh_port_status_1; - __u32 r_usb_rh_port_status_2; - __u32 r_usb_irq_mask_read; - struct tq_struct usb_bh; -#if 0 - __u32 r_usb_ept_data[32]; -#endif -}; - -struct in_chunk -{ - void *data; - int length; - char epid; - struct list_head list; -}; - - -/* --------------------------------------------------------------------------- - Virtual Root HUB - ------------------------------------------------------------------------- */ -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -/* Our Vendor Specific feature */ -#define RH_REMOVE_EP 0x00 - - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - -/* Field definitions for */ - -#define USB_IN_command__eol__BITNR 0 /* command macros */ -#define USB_IN_command__eol__WIDTH 1 -#define USB_IN_command__eol__no 0 -#define USB_IN_command__eol__yes 1 - -#define USB_IN_command__intr__BITNR 3 -#define USB_IN_command__intr__WIDTH 1 -#define USB_IN_command__intr__no 0 -#define USB_IN_command__intr__yes 1 - -#define USB_IN_status__eop__BITNR 1 /* status macros. */ -#define USB_IN_status__eop__WIDTH 1 -#define USB_IN_status__eop__no 0 -#define USB_IN_status__eop__yes 1 - -#define USB_IN_status__eot__BITNR 5 -#define USB_IN_status__eot__WIDTH 1 -#define USB_IN_status__eot__no 0 -#define USB_IN_status__eot__yes 1 - -#define USB_IN_status__error__BITNR 6 -#define USB_IN_status__error__WIDTH 1 -#define USB_IN_status__error__no 0 -#define USB_IN_status__error__yes 1 - -#define USB_IN_status__nodata__BITNR 7 -#define USB_IN_status__nodata__WIDTH 1 -#define USB_IN_status__nodata__no 0 -#define USB_IN_status__nodata__yes 1 - -#define USB_IN_status__epid__BITNR 8 -#define USB_IN_status__epid__WIDTH 5 - -#define USB_EP_command__eol__BITNR 0 -#define USB_EP_command__eol__WIDTH 1 -#define USB_EP_command__eol__no 0 -#define USB_EP_command__eol__yes 1 - -#define USB_EP_command__eof__BITNR 1 -#define USB_EP_command__eof__WIDTH 1 -#define USB_EP_command__eof__no 0 -#define USB_EP_command__eof__yes 1 - -#define USB_EP_command__intr__BITNR 3 -#define USB_EP_command__intr__WIDTH 1 -#define USB_EP_command__intr__no 0 -#define USB_EP_command__intr__yes 1 - -#define USB_EP_command__enable__BITNR 4 -#define USB_EP_command__enable__WIDTH 1 -#define USB_EP_command__enable__no 0 -#define USB_EP_command__enable__yes 1 - -#define USB_EP_command__hw_valid__BITNR 5 -#define USB_EP_command__hw_valid__WIDTH 1 -#define USB_EP_command__hw_valid__no 0 -#define USB_EP_command__hw_valid__yes 1 - -#define USB_EP_command__epid__BITNR 8 -#define USB_EP_command__epid__WIDTH 5 - -#define USB_SB_command__eol__BITNR 0 /* command macros. */ -#define USB_SB_command__eol__WIDTH 1 -#define USB_SB_command__eol__no 0 -#define USB_SB_command__eol__yes 1 - -#define USB_SB_command__eot__BITNR 1 -#define USB_SB_command__eot__WIDTH 1 -#define USB_SB_command__eot__no 0 -#define USB_SB_command__eot__yes 1 - -#define USB_SB_command__intr__BITNR 3 -#define USB_SB_command__intr__WIDTH 1 -#define USB_SB_command__intr__no 0 -#define USB_SB_command__intr__yes 1 - -#define USB_SB_command__tt__BITNR 4 -#define USB_SB_command__tt__WIDTH 2 -#define USB_SB_command__tt__zout 0 -#define USB_SB_command__tt__in 1 -#define USB_SB_command__tt__out 2 -#define USB_SB_command__tt__setup 3 - - -#define USB_SB_command__rem__BITNR 8 -#define USB_SB_command__rem__WIDTH 6 - -#define USB_SB_command__full__BITNR 6 -#define USB_SB_command__full__WIDTH 1 -#define USB_SB_command__full__no 0 -#define USB_SB_command__full__yes 1 - -#endif diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile dissimilarity index 82% index a340c8fb59f..7f6d9b43cf1 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -1,21 +1,13 @@ -# $Id: Makefile,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ -# -# Makefile for the linux kernel. -# - -extra-y := head.o - -obj-y := process.o signal.o entry.o traps.o irq.o \ - ptrace.o setup.o time.o sys_cris.o shadows.o \ - debugport.o semaphore.o - -obj-$(CONFIG_MODULES) += ksyms.o -obj-$(CONFIG_ETRAX_KGDB) += kgdb.o - -# This dependency isn't caught by mkdep. See entry.S. -entry.o: entryoffsets.s - -entryoffsets.s: entryoffsets.c - $(CC) $(CFLAGS) -S -c $< - -clean: +# $Id: Makefile,v 1.8 2003/04/09 05:20:47 starvik Exp $ +# +# Makefile for the linux kernel. +# + +obj-y := process.o traps.o irq.o ptrace.o setup.o \ + time.o sys_cris.o semaphore.o + +obj-$(CONFIG_MODULES) += ksyms.o +obj-$(CONFIG_MODULES) += module.o + +clean: + diff --git a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c deleted file mode 100644 index f1480acd104..00000000000 --- a/arch/cris/kernel/entryoffsets.c +++ /dev/null @@ -1,62 +0,0 @@ -/* linux/arch/cris/entryoffsets.c - * - * Copyright (C) 2001 Axis Communications AB - * - * Generate structure offsets for use in entry.S. No extra processing - * needed more than compiling this file to assembly code. Horrendous - * assembly code will be generated, so don't look at that. - * - * Authors: Hans-Peter Nilsson (hp@axis.com) - */ - -/* There can be string constants fallout from inline functions, so we'd - better make sure we don't assemble anything emitted from inclusions. */ -__asm__ (".if 0"); - -#include -#include -#include - -/* Exclude everything except the assembly by wrapping it in ".if 0". */ -#undef VAL -#define VAL(NAME, VALUE) \ -void NAME ## _fun (void) \ - { \ - __asm__ (".endif \n" \ - #NAME " = %0 \n" \ - ".if 0\n" \ - : : "i" (VALUE)); \ - } - -#undef OF -#define OF(NAME, TYPE, MEMBER) \ - VAL (NAME, offsetof (TYPE, MEMBER)) - -/* task_struct offsets. */ -#error OF (LTASK_SIGPENDING, struct task_struct, sigpending) -#error OF (LTASK_NEEDRESCHED, struct task_struct, need_resched) -#error OF (LTASK_PTRACE, struct task_struct, ptrace) -OF (LTASK_PID, struct task_struct, pid) - -/* pt_regs offsets. */ -OF (LORIG_R10, struct pt_regs, orig_r10) -OF (LR13, struct pt_regs, r13) -OF (LR12, struct pt_regs, r12) -OF (LR11, struct pt_regs, r11) -OF (LR10, struct pt_regs, r10) -OF (LR9, struct pt_regs, r9) -OF (LMOF, struct pt_regs, mof) -OF (LDCCR, struct pt_regs, dccr) -OF (LSRP, struct pt_regs, srp) -OF (LIRP, struct pt_regs, irp) - -/* thread_struct offsets. */ -OF (LTHREAD_KSP, struct thread_struct, ksp) -OF (LTHREAD_USP, struct thread_struct, usp) -OF (LTHREAD_DCCR, struct thread_struct, dccr) - -/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */ -VAL (LCLONE_VM, CLONE_VM) -VAL (LCLONE_UNTRACED, CLONE_UNTRACED) - -__asm__ (".endif"); diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index c63a5f02b00..934f8715b5a 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: irq.c,v 1.8 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/irq.c * @@ -23,7 +23,7 @@ #include #include -#include + #include #include #include @@ -34,47 +34,34 @@ #include #include #include +#include -#include #include -#include #include -#include - -char *hw_bp_msg = "BP 0x%x\n"; - -static inline void -mask_irq(unsigned int irq_nr) -{ - *R_VECT_MASK_CLR = 1 << irq_nr; -} - -static inline void -unmask_irq(unsigned int irq_nr) -{ - *R_VECT_MASK_SET = 1 << irq_nr; -} +/* Defined in arch specific irq.c */ +extern void arch_setup_irq(int irq); +extern void arch_free_irq(int irq); void disable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); mask_irq(irq_nr); - restore_flags(flags); + local_irq_restore(flags); } void enable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); unmask_irq(irq_nr); - restore_flags(flags); + local_irq_restore(flags); } unsigned long @@ -89,140 +76,11 @@ probe_irq_off(unsigned long x) return 0; } -irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ - -/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is - * global just so that the kernel gdb can use it. - */ - -void -set_int_vector(int n, irqvectptr addr, irqvectptr saddr) -{ - /* remember the shortcut entry point, after the prologue */ - - irq_shortcuts[n] = saddr; - - etrax_irv->v[n + 0x20] = (irqvectptr)addr; -} - -/* the breakpoint vector is obviously not made just like the normal irq handlers - * but needs to contain _code_ to jump to addr. - * - * the BREAK n instruction jumps to IBR + n * 8 - */ - -void -set_break_vector(int n, irqvectptr addr) -{ - unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; - unsigned long *jaddr = (unsigned long *)(jinstr + 1); - - /* if you don't know what this does, do not touch it! */ - - *jinstr = 0x0d3f; - *jaddr = (unsigned long)addr; - - /* 00000026 3f0d82000000 jump 0x82 */ -} - - -/* - * This builds up the IRQ handler stubs using some ugly macros in irq.h - * - * These macros create the low-level assembly IRQ routines that do all - * the operations that are needed. They are also written to be fast - and to - * disable interrupts as little as humanly possible. - * - */ - -/* IRQ0 and 1 are special traps */ -void hwbreakpoint(void); -void IRQ1_interrupt(void); -BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ -BUILD_IRQ(3, 0x08) -BUILD_IRQ(4, 0x10) -BUILD_IRQ(5, 0x20) -BUILD_IRQ(6, 0x40) -BUILD_IRQ(7, 0x80) -BUILD_IRQ(8, 0x100) -BUILD_IRQ(9, 0x200) -BUILD_IRQ(10, 0x400) -BUILD_IRQ(11, 0x800) -BUILD_IRQ(12, 0x1000) -BUILD_IRQ(13, 0x2000) -void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ -void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ -BUILD_IRQ(16, 0x10000) -BUILD_IRQ(17, 0x20000) -BUILD_IRQ(18, 0x40000) -BUILD_IRQ(19, 0x80000) -BUILD_IRQ(20, 0x100000) -BUILD_IRQ(21, 0x200000) -BUILD_IRQ(22, 0x400000) -BUILD_IRQ(23, 0x800000) -BUILD_IRQ(24, 0x1000000) -BUILD_IRQ(25, 0x2000000) -/* IRQ 26-30 are reserved */ -BUILD_IRQ(31, 0x80000000) - -/* - * Pointers to the low-level handlers - */ - -static void (*interrupt[NR_IRQS])(void) = { - NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, - IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, - IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, - IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, - IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, - IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, - IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, - IRQ31_interrupt -}; - -static void (*sinterrupt[NR_IRQS])(void) = { - NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt, - sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt, - sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt, - sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, - sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, - sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, - sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, - sIRQ31_interrupt -}; - -static void (*bad_interrupt[NR_IRQS])(void) = { - NULL, NULL, - NULL, bad_IRQ3_interrupt, - bad_IRQ4_interrupt, bad_IRQ5_interrupt, - bad_IRQ6_interrupt, bad_IRQ7_interrupt, - bad_IRQ8_interrupt, bad_IRQ9_interrupt, - bad_IRQ10_interrupt, bad_IRQ11_interrupt, - bad_IRQ12_interrupt, bad_IRQ13_interrupt, - NULL, NULL, - bad_IRQ16_interrupt, bad_IRQ17_interrupt, - bad_IRQ18_interrupt, bad_IRQ19_interrupt, - bad_IRQ20_interrupt, bad_IRQ21_interrupt, - bad_IRQ22_interrupt, bad_IRQ23_interrupt, - bad_IRQ24_interrupt, bad_IRQ25_interrupt, - NULL, NULL, NULL, NULL, NULL, - bad_IRQ31_interrupt -}; - /* * Initial irq handlers. */ -static struct irqaction *irq_action[NR_IRQS] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; +static struct irqaction *irq_action[NR_IRQS]; int show_interrupts(struct seq_file *p, void *v) { @@ -262,9 +120,10 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction *action; int do_random, cpu; + int retval = 0; cpu = smp_processor_id(); - irq_enter(cpu); + irq_enter(); kstat_cpu(cpu).irqs[irq]++; action = irq_action[irq]; @@ -275,14 +134,24 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) do_random = 0; do { do_random |= action->flags; - action->handler(irq, action->dev_id, regs); + retval |= action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + + if (retval != 1) { + if (retval) { + printk("irq event %d: bogus retval mask %x\n", + irq, retval); + } else { + printk("irq %d: nobody cared\n", irq); + } + } + if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - local_irq_disable(); + local_irq_disable(); } - irq_exit(cpu); + irq_exit(); if (softirq_pending(cpu)) do_softirq(); @@ -295,7 +164,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) handler is entered into the interrupt vector */ -int setup_etrax_irq(int irq, struct irqaction * new) +int setup_irq(int irq, struct irqaction * new) { int shared = 0; struct irqaction *old, **p; @@ -322,19 +191,19 @@ int setup_etrax_irq(int irq, struct irqaction * new) if (new->flags & SA_SAMPLE_RANDOM) rand_initialize_irq(irq); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); *p = new; if (!shared) { /* if the irq wasn't registred before, enter it into the vector table and unmask it physically */ - set_int_vector(irq, interrupt[irq], sinterrupt[irq]); + arch_setup_irq(irq); unmask_irq(irq); } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -348,7 +217,7 @@ int setup_etrax_irq(int irq, struct irqaction * new) */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -378,7 +247,7 @@ int request_irq(unsigned int irq, action->next = NULL; action->dev_id = dev_id; - retval = setup_etrax_irq(irq, action); + retval = setup_irq(irq, action); if (retval) kfree(action); @@ -399,14 +268,14 @@ void free_irq(unsigned int irq, void *dev_id) continue; /* Found it - now free it */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); *p = action->next; if (!irq_action[irq]) { mask_irq(irq); - set_int_vector(irq, bad_interrupt[irq], 0); + arch_free_irq(irq); } - restore_flags(flags); + local_irq_restore(flags); kfree(action); return; } @@ -415,84 +284,11 @@ void free_irq(unsigned int irq, void *dev_id) void weird_irq(void) { - __asm__("di"); + local_irq_disable(); printk("weird irq\n"); while(1); } -/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and - setting the irq vector table to point to bad_interrupt ptrs. -*/ - -void system_call(void); /* from entry.S */ -void do_sigtrap(void); /* from entry.S */ -void gdb_handle_breakpoint(void); /* from entry.S */ - -void __init -init_IRQ(void) -{ - int i; - - /* clear all interrupt masks */ - -#ifndef CONFIG_SVINTO_SIM - *R_IRQ_MASK0_CLR = 0xffffffff; - *R_IRQ_MASK1_CLR = 0xffffffff; - *R_IRQ_MASK2_CLR = 0xffffffff; -#endif - - *R_VECT_MASK_CLR = 0xffffffff; - - /* clear the shortcut entry points */ - - for(i = 0; i < NR_IRQS; i++) - irq_shortcuts[i] = NULL; - - for (i = 0; i < 256; i++) - etrax_irv->v[i] = weird_irq; - - /* the entries in the break vector contain actual code to be - executed by the associated break handler, rather than just a jump - address. therefore we need to setup a default breakpoint handler - for all breakpoints */ - - for (i = 0; i < 16; i++) - set_break_vector(i, do_sigtrap); - - /* set all etrax irq's to the bad handlers */ - for (i = 2; i < NR_IRQS; i++) - set_int_vector(i, bad_interrupt[i], 0); - - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ - - set_int_vector(15, multiple_interrupt, 0); - - /* 0 and 1 which are special breakpoint/NMI traps */ - - set_int_vector(0, hwbreakpoint, 0); - set_int_vector(1, IRQ1_interrupt, 0); - - /* and irq 14 which is the mmu bus fault handler */ - - set_int_vector(14, mmu_bus_fault, 0); - - /* setup the system-call trap, which is reached by BREAK 13 */ - - set_break_vector(13, system_call); - - /* setup a breakpoint handler for debugging used for both user and - kernel mode debugging (which is why it is not inside an ifdef - CONFIG_ETRAX_KGDB) */ - set_break_vector(8, gdb_handle_breakpoint); - -#ifdef CONFIG_ETRAX_KGDB - /* setup kgdb if its enabled, and break into the debugger */ - kgdb_init(); - breakpoint(); -#endif - -} - #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) /* Used by other archs to show/control IRQ steering during SMP */ void __init diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c index 4d2cbc18c6a..1161a252525 100644 --- a/arch/cris/kernel/ksyms.c +++ b/arch/cris/kernel/ksyms.c @@ -24,6 +24,9 @@ extern void dump_thread(struct pt_regs *, struct user *); extern unsigned long get_cmos_time(void); extern void __Udiv(void); +extern void __Umod(void); +extern void __Div(void); +extern void __Mod(void); extern void __ashrdi3(void); extern void iounmap(void *addr); @@ -44,11 +47,16 @@ EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); /* Math functions */ EXPORT_SYMBOL(__Udiv); +EXPORT_SYMBOL(__Umod); +EXPORT_SYMBOL(__Div); +EXPORT_SYMBOL(__Mod); EXPORT_SYMBOL(__ashrdi3); /* Memory functions */ @@ -58,6 +66,8 @@ EXPORT_SYMBOL(iounmap); /* Semaphore functions */ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); /* Export shadow registers for the CPU I/O pins */ EXPORT_SYMBOL(genconfig_shadow); @@ -69,14 +79,13 @@ EXPORT_SYMBOL(port_pb_config_shadow); EXPORT_SYMBOL(port_g_data_shadow); /* Userspace access functions */ -EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__generic_copy_from_user); -EXPORT_SYMBOL(__generic_copy_to_user); -EXPORT_SYMBOL(strnlen_user); EXPORT_SYMBOL(__copy_user_zeroing); EXPORT_SYMBOL(__copy_user); +/* Cache flush functions */ +EXPORT_SYMBOL(flush_etrax_cache); +EXPORT_SYMBOL(prepare_rx_descriptor); + #undef memcpy #undef memset extern void * memset(void *, int, __kernel_size_t); diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c new file mode 100644 index 00000000000..052c0031fa2 --- /dev/null +++ b/arch/cris/kernel/module.c @@ -0,0 +1,106 @@ +/* Kernel module help for i386. + Copyright (C) 2001 Rusty Russell. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + /* TODO: This is probably not correct */ + printk("Beware: untested code in module.c!\n"); + /* We add the value into the location given */ + *location += sym->st_value; + } + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index 60441877ef2..23a5d13c18e 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -1,13 +1,51 @@ -/* $Id: process.c,v 1.3 2002/01/21 15:22:49 bjornw Exp $ +/* $Id: process.c,v 1.14 2003/06/10 10:21:12 johana Exp $ * * linux/arch/cris/kernel/process.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000-2002 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: process.c,v $ + * Revision 1.14 2003/06/10 10:21:12 johana + * Moved thread_saved_pc() from arch/cris/kernel/process.c to + * subarch specific process.c. + * + * Revision 1.13 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.12 2002/12/11 15:41:11 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/kernel + * + * Revision 1.11 2002/12/10 09:00:10 starvik + * Merge of Linux 2.5.51 + * + * Revision 1.10 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.9 2002/11/26 09:44:21 starvik + * New threads exits through ret_from_fork (necessary for preemptive scheduling) + * + * Revision 1.8 2002/11/19 14:35:24 starvik + * Changes from linux 2.4 + * Changed struct initializer syntax to the currently prefered notation + * + * Revision 1.7 2002/11/18 07:39:42 starvik + * thread_saved_pc moved here from processor.h + * + * Revision 1.6 2002/11/14 06:51:27 starvik + * Made cpu_idle more similar with other archs + * init_task_union -> init_thread_union + * Updated for new interrupt macros + * sys_clone and do_fork have a new argument, user_tid + * + * Revision 1.5 2002/11/05 06:45:11 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.4 2002/02/05 15:37:44 bjornw + * Need init_task.h + * * Revision 1.3 2002/01/21 15:22:49 bjornw * current->counter is gone * @@ -54,29 +92,17 @@ */ #define __KERNEL_SYSCALLS__ -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include +#include #include -#include #include -#include -#include - -#include -#include -#include -#include -#include - -#include //#define DEBUG @@ -89,20 +115,29 @@ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS; +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); /* - * Initial task structure. + * Initial thread structure. * * We need to make sure that this is 8192-byte aligned due to the * way process stacks are handled. This is done by having a special * "init_task" linker map entry.. */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + -union task_union init_task_union - __attribute__((__section__(".data.init_task"))) = - { INIT_TASK(init_task_union.task) }; /* * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if @@ -125,44 +160,34 @@ void enable_hlt(void) hlt_counter--; } -int cpu_idle(void *unused) -{ - while(1) { - schedule(); - } -} - -/* if the watchdog is enabled, we can simply disable interrupts and go - * into an eternal loop, and the watchdog will reset the CPU after 0.1s - * if on the other hand the watchdog wasn't enabled, we just enable it and wait +/* + * The following aren't currently used. */ +void (*pm_idle)(void); -void hard_reset_now (void) -{ - /* - * Don't declare this variable elsewhere. We don't want any other - * code to know about it than the watchdog handler in entry.S and - * this code, implementing hard reset through the watchdog. - */ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - extern int cause_of_death; -#endif - - printk("*** HARD RESET ***\n"); - cli(); +extern void default_idle(void); -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - cause_of_death = 0xbedead; -#else - /* Since we don't plan to keep on reseting the watchdog, - the key can be arbitrary hence three */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | - IO_STATE(R_WATCHDOG, enable, start); -#endif - - while(1) /* waiting for RETRIBUTION! */ ; +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + while (1) { + void (*idle)(void) = pm_idle; + if (!idle) + idle = default_idle; + while (!need_resched()) + idle(); + schedule(); + } } +void hard_reset_now (void); + void machine_restart(void) { hard_reset_now(); @@ -194,60 +219,6 @@ void flush_thread(void) { } -asmlinkage void ret_from_sys_call(void); - -/* setup the child's kernel stack with a pt_regs and switch_stack on it. - * it will be un-nested during _resume and _ret_from_sys_call when the - * new thread is scheduled. - * - * also setup the thread switching structure which is used to keep - * thread-specific data during _resumes. - * - */ - -int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct *p, struct pt_regs *regs) -{ - struct pt_regs * childregs; - struct switch_stack *swstack; - - /* put the pt_regs structure at the end of the new kernel stack page and fix it up - * remember that the task_struct doubles as the kernel stack for the task - */ - - childregs = user_regs(p); - - *childregs = *regs; /* struct copy of pt_regs */ - - childregs->r10 = 0; /* child returns 0 after a fork/clone */ - - /* put the switch stack right below the pt_regs */ - - swstack = ((struct switch_stack *)childregs) - 1; - - swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == don't restart the syscall */ - - /* we want to return into ret_from_sys_call after the _resume */ - - swstack->return_ip = (unsigned long) ret_from_sys_call; - - /* fix the user-mode stackpointer */ - - p->thread.usp = usp; - - /* and the kernel-mode one */ - - p->thread.ksp = (unsigned long) swstack; - -#ifdef DEBUG - printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); - show_registers(childregs); -#endif - - return 0; -} - /* * fill in the user structure for a core dump.. */ @@ -281,110 +252,3 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { return 0; } - -/* - * Be aware of the "magic" 7th argument in the four system-calls below. - * They need the latest stackframe, which is put as the 7th argument by - * entry.S. The previous arguments are dummies or actually used, but need - * to be defined to reach the 7th argument. - * - * N.B.: Another method to get the stackframe is to use current_regs(). But - * it returns the latest stack-frame stacked when going from _user mode_ and - * some of these (at least sys_clone) are called from kernel-mode sometimes - * (for example during kernel_thread, above) and thus cannot use it. Thus, - * to be sure not to get any surprises, we use the method for the other calls - * as well. - */ - -asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - p = do_fork(SIGCHLD, rdusp(), regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* if newusp is 0, we just grab the old usp */ - -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, - long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - if (!newusp) - newusp = rdusp(); - p = do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* vfork is a system call in i386 because of register-pressure - maybe - * we can remove it and handle it in libc but we put it here until then. - */ - -asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp, - long r13, long mof, long srp, - struct pt_regs *regs) -{ - int error; - char *filename; - - filename = getname(fname); - error = PTR_ERR(filename); - - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); - out: - return error; -} - -/* - * These bracket the sleeping functions.. - */ - -extern void scheduling_functions_start_here(void); -extern void scheduling_functions_end_here(void); -#define first_sched ((unsigned long) scheduling_functions_start_here) -#define last_sched ((unsigned long) scheduling_functions_end_here) - -unsigned long get_wchan(struct task_struct *p) -{ -#if 0 - /* YURGH. TODO. */ - - unsigned long ebp, esp, eip; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - stack_page = (unsigned long)p; - esp = p->thread.esp; - if (!stack_page || esp < stack_page || esp > 8188+stack_page) - return 0; - /* include/asm-i386/system.h:switch_to() pushes ebp last. */ - ebp = *(unsigned long *) esp; - do { - if (ebp < stack_page || ebp > 8184+stack_page) - return 0; - eip = *(unsigned long *) (ebp+4); - if (eip < first_sched || eip >= last_sched) - return eip; - ebp = *(unsigned long *) ebp; - } while (count++ < 16); -#endif - return 0; -} -#undef last_sched -#undef first_sched diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c dissimilarity index 79% index c8a066c4ee4..e85a2fdd9ac 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -1,324 +1,119 @@ -/* - * linux/arch/cris/kernel/ptrace.c - * - * Parts taken from the m68k port. - * - * Copyright (c) 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen - * - * $Log: ptrace.c,v $ - * Revision 1.2 2001/12/18 13:35:20 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.8 2001/11/12 18:26:21 pkj - * Fixed compiler warnings. - * - * Revision 1.7 2001/09/26 11:53:49 bjornw - * PTRACE_DETACH works more simple in 2.4.10 - * - * Revision 1.6 2001/07/25 16:08:47 bjornw - * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7 - * - * Revision 1.5 2001/03/26 14:24:28 orjanf - * * Changed loop condition. - * * Added comment documenting non-standard ptrace behaviour. - * - * Revision 1.4 2001/03/20 19:44:41 bjornw - * Use the user_regs macro instead of thread.esp0 - * - * Revision 1.3 2000/12/18 23:45:25 bjornw - * Linux/CRIS first version - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in DCCR the user has access to. */ -/* 1 = access 0 = no access */ -#define DCCR_MASK 0x0000001f /* XNZVC */ - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, unsigned int regno) -{ - /* USP is a special case, it's not in the pt_regs struct but - * in the tasks thread struct - */ - - if (regno == PT_USP) - return task->thread.usp; - else if (regno < PT_MAX) - return ((unsigned long *)user_regs(task))[regno]; - else - return 0; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, unsigned int regno, - unsigned long data) -{ - if (regno == PT_USP) - task->thread.usp = data; - else if (regno < PT_MAX) - ((unsigned long *)user_regs(task))[regno] = data; - else - return -1; - return 0; -} - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) -{ - /* Todo - pending singlesteps? */ -} - -/* Note that this implementation of ptrace behaves differently from vanilla - * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, - * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not - * ignored. Instead, the data variable is expected to point at a location - * (in user space) where the result of the ptrace call is written (instead of - * being returned). - */ - -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - int ret; - - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) - goto out_tsk; - - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long *) data); - break; - } - - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - break; - - tmp = 0; /* Default return condition */ - ret = -EIO; - if (addr < sizeof(struct pt_regs)) { - tmp = get_reg(child, addr >> 2); - ret = put_user(tmp, (unsigned long *)data); - } - break; - } - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - break; - ret = -EIO; - break; - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - break; - - if (addr < sizeof(struct pt_regs)) { - addr >>= 2; - - if (addr == PT_DCCR) { - /* don't allow the tracing process to change stuff like - * interrupt enable, kernel/user bit, dma enables etc. - */ - data &= DCCR_MASK; - data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; - } - if (put_reg(child, addr, data)) - break; - ret = 0; - } - break; - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; - else - child->ptrace &= ~PT_TRACESYS; - child->exit_code = data; - /* TODO: make sure any pending breakpoint is killed */ - wake_up_process(child); - ret = 0; - break; - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: - ret = 0; - if (child->state == TASK_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* TODO: make sure any pending breakpoint is killed */ - wake_up_process(child); - break; - - case PTRACE_SINGLESTEP: /* set the trap flag. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - child->ptrace &= ~PT_TRACESYS; - - /* TODO: set some clever breakpoint mechanism... */ - - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - - case PTRACE_DETACH: - ret = ptrace_detach(child, data); - break; - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - int i; - unsigned long tmp; - for (i = 0; i <= PT_MAX; i++) { - tmp = get_reg(child, i); - if (put_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - data += sizeof(long); - } - ret = 0; - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - for (i = 0; i <= PT_MAX; i++) { - if (get_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - if (i == PT_DCCR) { - tmp &= DCCR_MASK; - tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; - } - put_reg(child, i, tmp); - data += sizeof(long); - } - ret = 0; - break; - } - - default: - ret = ptrace_request(child, request, addr, data); - break; - } -out_tsk: - free_task_struct(child); -out: - unlock_kernel(); - return ret; -} - -asmlinkage void syscall_trace(void) -{ - if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) != - (PT_PTRACED | PT_TRACESYS)) - return; - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; - notify_parent(current, SIGCHLD); - schedule(); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} +/* + * linux/arch/cris/kernel/ptrace.c + * + * Parts taken from the m68k port. + * + * Copyright (c) 2000, 2001, 2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * $Log: ptrace.c,v $ + * Revision 1.9 2003/07/04 12:56:11 tobiasa + * Moved arch-specific code to arch-specific files. + * + * Revision 1.8 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.7 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.6 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.5 2002/11/18 07:41:19 starvik + * Removed warning + * + * Revision 1.4 2002/11/11 12:47:28 starvik + * SYSCALL_TRACE has been moved to thread flags + * + * Revision 1.3 2002/02/05 15:37:18 bjornw + * * Add do_notify_resume (replaces do_signal in the callchain) + * * syscall_trace is now do_syscall_trace + * * current->ptrace flag PT_TRACESYS -> PT_SYSCALLTRACE + * * Keep track of the current->work.syscall_trace counter + * + * Revision 1.2 2001/12/18 13:35:20 bjornw + * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). + * + * Revision 1.8 2001/11/12 18:26:21 pkj + * Fixed compiler warnings. + * + * Revision 1.7 2001/09/26 11:53:49 bjornw + * PTRACE_DETACH works more simple in 2.4.10 + * + * Revision 1.6 2001/07/25 16:08:47 bjornw + * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7 + * + * Revision 1.5 2001/03/26 14:24:28 orjanf + * * Changed loop condition. + * * Added comment documenting non-standard ptrace behaviour. + * + * Revision 1.4 2001/03/20 19:44:41 bjornw + * Use the user_regs macro instead of thread.esp0 + * + * Revision 1.3 2000/12/18 23:45:25 bjornw + * Linux/CRIS first version + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Get contents of register REGNO in task TASK. + */ +inline long get_reg(struct task_struct *task, unsigned int regno) +{ + /* USP is a special case, it's not in the pt_regs struct but + * in the tasks thread struct + */ + + if (regno == PT_USP) + return task->thread.usp; + else if (regno < PT_MAX) + return ((unsigned long *)user_regs(task->thread_info))[regno]; + else + return 0; +} + +/* + * Write contents of register REGNO in task TASK. + */ +inline int put_reg(struct task_struct *task, unsigned int regno, + unsigned long data) +{ + if (regno == PT_USP) + task->thread.usp = data; + else if (regno < PT_MAX) + ((unsigned long *)user_regs(task->thread_info))[regno] = data; + else + return -1; + return 0; +} + +/* notification of userspace execution resumption + * - triggered by current->work.notify_resume + */ +extern int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); + + +void do_notify_resume(int canrestart, sigset_t *oldset, struct pt_regs *regs, + __u32 thread_info_flags ) +{ + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(canrestart,oldset,regs); +} diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 3232548a639..fc989d2c773 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: setup.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/setup.c * @@ -10,30 +10,12 @@ * This file handles the architecture-dependent parts of initialization */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include -#include - -#include -#include -#include #include -#include -#include +#include +#include /* * Setup options @@ -52,6 +34,7 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; extern const unsigned long text_start, edata; /* set by the linker script */ +extern unsigned long dram_start, dram_end; extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ @@ -169,14 +152,14 @@ setup_arch(char **cmdline_p) *cmdline_p = command_line; - if (romfs_in_flash) { - strlcpy(command_line, "root=", sizeof(command_line)); - strlcat(command_line, CONFIG_ETRAX_ROOT_DEVICE, - sizeof(command_line)); - - /* Save command line copy for /proc/cmdline */ - strlcpy(saved_command_line, command_line, sizeof(saved_command_line)); - } +#ifdef CONFIG_ETRAX_CMDLINE + strlcpy(command_line, CONFIG_ETRAX_CMDLINE, sizeof(command_line)); +#elif defined(CONFIG_ETRAX_ROOT_DEVICE) + strlcpy(command_line, "root=", sizeof(command_line)); + strlcat(command_line, CONFIG_ETRAX_ROOT_DEVICE, + sizeof(command_line)); +#endif + command_line[COMMAND_LINE_SIZE - 1] = '\0'; /* give credit for the CRIS port */ @@ -184,83 +167,6 @@ setup_arch(char **cmdline_p) } -#ifdef CONFIG_PROC_FS -#define HAS_FPU 0x0001 -#define HAS_MMU 0x0002 -#define HAS_ETHERNET100 0x0004 -#define HAS_TOKENRING 0x0008 -#define HAS_SCSI 0x0010 -#define HAS_ATA 0x0020 -#define HAS_USB 0x0040 -#define HAS_IRQ_BUG 0x0080 -#define HAS_MMU_BUG 0x0100 - -static struct cpu_info { - char *model; - unsigned short cache; - unsigned short flags; -} cpu_info[] = { - /* The first four models will never ever run this code and are - only here for display. */ - { "ETRAX 1", 0, 0 }, - { "ETRAX 2", 0, 0 }, - { "ETRAX 3", 0, HAS_TOKENRING }, - { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, - { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, - { "Unknown", 0, 0 } /* This entry MUST be the last */ -}; - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long revision; - struct cpu_info *info; - - /* read the version register in the CPU and print some stuff */ - - revision = rdvr(); - - if (revision >= sizeof cpu_info/sizeof *cpu_info) - info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; - else - info = &cpu_info[revision]; - - return seq_printf(m, - "cpu\t\t: CRIS\n" - "cpu revision\t: %lu\n" - "cpu model\t: %s\n" - "cache size\t: %d kB\n" - "fpu\t\t: %s\n" - "mmu\t\t: %s\n" - "mmu DMA bug\t: %s\n" - "ethernet\t: %s Mbps\n" - "token ring\t: %s\n" - "scsi\t\t: %s\n" - "ata\t\t: %s\n" - "usb\t\t: %s\n" - "bogomips\t: %lu.%02lu\n", - - revision, - info->model, - info->cache, - info->flags & HAS_FPU ? "yes" : "no", - info->flags & HAS_MMU ? "yes" : "no", - info->flags & HAS_MMU_BUG ? "yes" : "no", - info->flags & HAS_ETHERNET100 ? "10/100" : "10", - info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", - info->flags & HAS_SCSI ? "yes" : "no", - info->flags & HAS_ATA ? "yes" : "no", - info->flags & HAS_USB ? "yes" : "no", - (loops_per_jiffy * HZ + 500) / 500000, - ((loops_per_jiffy * HZ + 500) / 5000) % 100); -} - static void *c_start(struct seq_file *m, loff_t *pos) { /* We only got one CPU... */ @@ -277,11 +183,13 @@ static void c_stop(struct seq_file *m, void *v) { } +extern int show_cpuinfo(struct seq_file *m, void *v); + struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; -#endif /* CONFIG_PROC_FS */ + diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c index 31917ab1198..e7e5c04071e 100644 --- a/arch/cris/kernel/sys_cris.c +++ b/arch/cris/kernel/sys_cris.c @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: sys_cris.c,v 1.5 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/sys_cris.c * @@ -29,7 +29,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage int sys_pipe(unsigned long * fildes) +asmlinkage int sys_pipe(unsigned long __user * fildes) { int fd[2]; int error; @@ -69,7 +69,7 @@ out: return error; } -asmlinkage unsigned long old_mmap(unsigned long *args) +asmlinkage unsigned long old_mmap(unsigned long __user *args) { unsigned long buffer[6]; int err = -EFAULT; @@ -101,7 +101,7 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, */ asmlinkage int sys_ipc (uint call, int first, int second, - int third, void *ptr, long fifth) + int third, void __user *ptr, long fifth) { int version, ret; @@ -110,20 +110,24 @@ asmlinkage int sys_ipc (uint call, int first, int second, switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, second, + (const struct timespec __user *)fifth); + case SEMGET: return sys_semget (first, second, third); case SEMCTL: { union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) + if (get_user(fourth.__pad, (void * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third); case MSGRCV: switch (version) { @@ -133,7 +137,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, return -EINVAL; if (copy_from_user(&tmp, - (struct ipc_kludge *) ptr, + (struct ipc_kludge __user *) ptr, sizeof (tmp))) return -EFAULT; return sys_msgrcv (first, tmp.msgp, second, @@ -141,29 +145,29 @@ asmlinkage int sys_ipc (uint call, int first, int second, } default: return sys_msgrcv (first, - (struct msgbuf *) ptr, + (struct msgbuf __user *) ptr, second, fifth, third); } case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); case SHMAT: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char __user *) ptr, second, &raddr); if (ret) return ret; - return put_user (raddr, (ulong *) third); + return put_user (raddr, (ulong __user *) third); } case SHMDT: - return sys_shmdt ((char *)ptr); + return sys_shmdt ((char __user *)ptr); case SHMGET: return sys_shmget (first, second, third); case SHMCTL: return sys_shmctl (first, second, - (struct shmid_ds *) ptr); + (struct shmid_ds __user *) ptr); default: - return -EINVAL; + return -ENOSYS; } } diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c dissimilarity index 73% index 81f91df573a..caee8e4fd39 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -1,500 +1,196 @@ -/* $Id: time.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ - * - * linux/arch/cris/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Copyright (C) 1999, 2000, 2001 Axis Communications AB - * - * 1994-07-02 Alan Modra - * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime - * 1995-03-26 Markus Kuhn - * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 - * precision CMOS clock update - * 1996-05-03 Ingo Molnar - * fixed time warps in do_[slow|fast]_gettimeoffset() - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * - * Linux/CRIS specific code: - * - * Authors: Bjorn Wesen - * Johan Adolfsson - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -u64 jiffies_64 = INITIAL_JIFFIES; - -static int have_rtc; /* used to remember if we have an RTC or not */ - -/* define this if you need to use print_timestamp */ -/* it will make jiffies at 96 hz instead of 100 hz though */ -#undef USE_CASCADE_TIMERS - -extern int setup_etrax_irq(int, struct irqaction *); - -/* Lookup table to convert *R_TIMER0 to microseconds (us) - * Timer goes from TIMER0_DIV down to 1 meaning 0-10000us in step of approx 52us - */ -unsigned short cris_timer0_value_us[TIMER0_DIV+1]; - -#define TICK_SIZE tick - -static unsigned long do_slow_gettimeoffset(void) -{ - unsigned long count; - unsigned long usec_count = 0; - - static unsigned long count_p = LATCH; /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* The timer interrupt comes from Etrax timer 0. In order to get - * better precision, we check the current value. It might have - * underflowed already though. - */ - -#ifndef CONFIG_SVINTO_SIM - /* Not available in the xsim simulator. */ - count = *R_TIMER0_DATA; -#else - count = 0; -#endif - - jiffies_t = jiffies; - - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there are three kinds of problems that must be avoided here: - * 1. the timer counter underflows - * 2. we are after the timer interrupt, but the bottom half handler - * hasn't executed yet. - */ - if( jiffies_t == jiffies_p ) { - if( count > count_p ) { - /* Timer wrapped */ - count = count_p; - usec_count = 1000000/CLOCK_TICK_RATE/2; - } - } else - jiffies_p = jiffies_t; - count_p = count; - /* Convert timer value to usec using table lookup */ - usec_count += cris_timer0_value_us[count]; -#if 0 - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; -#endif - return usec_count; -} - -static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; - -/* - * This version of gettimeofday has near microsecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - - save_flags(flags); - cli(); - *tv = xtime; - tv->tv_usec += do_gettimeoffset(); - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } - restore_flags(flags); -} - -int do_settimeofday(struct timespec *tv) -{ - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - cli(); - /* This is revolting. We need to set the xtime.tv_usec - * correctly. However, the value in this location is - * is value at the last tick. - * Discover what correction gettimeofday - * would have done, and then undo it! - */ - tv->tv_nsec -= do_gettimeoffset() * 1000; - - if (tv->tv_nsec < 0) { - tv->tv_nsec += NSEC_PER_SEC; - tv->tv_sec--; - } - - xtime = *tv; - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - sti(); - return 0; -} - - -/* - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you'll only notice that after reboot! - */ - -static int set_rtc_mmss(unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - - printk("set_rtc_mmss(%lu)\n", nowtime); - - if(!have_rtc) - return 0; - - cmos_minutes = CMOS_READ(RTC_MINUTES); - BCD_TO_BIN(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - return retval; -} - -/* Excerpt from the Etrax100 HSDD about the built-in watchdog: - * - * 3.10.4 Watchdog timer - - * When the watchdog timer is started, it generates an NMI if the watchdog - * isn't restarted or stopped within 0.1 s. If it still isn't restarted or - * stopped after an additional 3.3 ms, the watchdog resets the chip. - * The watchdog timer is stopped after reset. The watchdog timer is controlled - * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit - * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is - * described in the table below: - * - * Watchdog Value written: - * state: To enable: To key: Operation: - * -------- ---------- ------- ---------- - * stopped 0 X No effect. - * stopped 1 key_val Start watchdog with key = key_val. - * started 0 ~key Stop watchdog - * started 1 ~key Restart watchdog with key = ~key. - * started X new_key_val Change key to new_key_val. - * - * Note: '~' is the bitwise NOT operator. - * - */ - -/* right now, starting the watchdog is the same as resetting it */ -#define start_watchdog reset_watchdog - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) -static int watchdog_key = 0; /* arbitrary number */ -#endif - -/* number of pages to consider "out of memory". it is normal that the memory - * is used though, so put this really low. - */ - -#define WATCHDOG_MIN_FREE_PAGES 8 - -void -reset_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - /* only keep watchdog happy as long as we have memory left! */ - if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { - /* reset the watchdog with the inverse of the old key */ - watchdog_key ^= 0x7; /* invert key, which is 3 bits */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | - IO_STATE(R_WATCHDOG, enable, start); - } -#endif -} - -/* stop the watchdog - we still need the correct key */ - -void -stop_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - watchdog_key ^= 0x7; /* invert key, which is 3 bits */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | - IO_STATE(R_WATCHDOG, enable, stop); -#endif -} - -/* last time the cmos clock got updated */ -static long last_rtc_update = 0; - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ - -//static unsigned short myjiff; /* used by our debug routine print_timestamp */ - -static inline void -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* acknowledge the timer irq */ - -#ifdef USE_CASCADE_TIMERS - *R_TIMER_CTRL = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, clr) | - IO_STATE( R_TIMER_CTRL, tm1, run) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, clr) | - IO_STATE( R_TIMER_CTRL, tm0, run) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); -#else - *R_TIMER_CTRL = r_timer_ctrl_shadow | - IO_STATE(R_TIMER_CTRL, i0, clr); -#endif - - /* reset watchdog otherwise it resets us! */ - - reset_watchdog(); - - /* call the real timer interrupt handler */ - - do_timer(regs); - - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; - } -} - -#if 0 -/* some old debug code for testing the microsecond timing of packets */ -static unsigned int lastjiff; - -void print_timestamp(const char *s) -{ - unsigned long flags; - unsigned int newjiff; - - save_flags(flags); - cli(); - newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); - printk("%s: %x (%x)\n", s, newjiff, newjiff - lastjiff); - lastjiff = newjiff; - restore_flags(flags); -} -#endif - -/* grab the time from the RTC chip */ - -unsigned long -get_cmos_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - - printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", - sec, min, hour, day, mon, year); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - - if ((year += 1900) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); -} - -/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. - * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. - */ - -void -update_xtime_from_cmos(void) -{ - if(have_rtc) { - xtime.tv_sec = get_cmos_time(); - xtime.tv_usec = 0; - } -} - -/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain - * it needs to be SA_INTERRUPT to make the jiffies update work properly - */ - -static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, - 0, "timer", NULL, NULL}; - -void __init -time_init(void) -{ - int i; - /* probe for the RTC and read it if it exists */ - - if(RTC_INIT() < 0) { - /* no RTC, start at 1980 */ - xtime.tv_sec = 0; - xtime.tv_usec = 0; - have_rtc = 0; - } else { - /* get the current time */ - have_rtc = 1; - update_xtime_from_cmos(); - } - - /* Setup the etrax timers - * Base frequency is 19200 hz, divider 192 -> 100 hz as Linux wants - * In normal mode, we use timer0, so timer1 is free. In cascade - * mode (which we sometimes use for debugging) both timers are used. - * Remember that linux/timex.h contains #defines that rely on the - * timer settings below (hz and divide factor) !!! - */ - -#ifdef USE_CASCADE_TIMERS - *R_TIMER_CTRL = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, nop) | - IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, nop) | - IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, nop) | - IO_STATE( R_TIMER_CTRL, tm1, run) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, nop) | - IO_STATE( R_TIMER_CTRL, tm0, run) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); -#else - *R_TIMER_CTRL = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | - IO_STATE(R_TIMER_CTRL, i1, nop) | - IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | - IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | - IO_STATE(R_TIMER_CTRL, i0, nop) | - IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | - IO_STATE(R_TIMER_CTRL, i1, nop) | - IO_STATE(R_TIMER_CTRL, tm1, run) | - IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | - IO_STATE(R_TIMER_CTRL, i0, nop) | - IO_STATE(R_TIMER_CTRL, tm0, run) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); -#endif - - for (i=0; i <= TIMER0_DIV; i++) { - /* We must be careful not to get overflow... */ - cris_timer0_value_us[TIMER0_DIV-i] = - (unsigned short)((unsigned long) - ((i*(1000000/HZ))/TIMER0_DIV)&0x0000FFFFL); - } - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ - - /* now actually register the timer irq handler that calls timer_interrupt() */ - - setup_etrax_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ - - /* enable watchdog if we should use one */ - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - printk("Enabling watchdog...\n"); - start_watchdog(); - - /* If we use the hardware watchdog, we want to trap it as an NMI - and dump registers before it resets us. For this to happen, we - must set the "m" NMI enable flag (which once set, is unset only - when an NMI is taken). - - The same goes for the external NMI, but that doesn't have any - driver or infrastructure support yet. */ - asm ("setf m"); - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); - *R_VECT_MASK_SET = - IO_STATE(R_VECT_MASK_SET, nmi, set); -#endif -} +/* $Id: time.c,v 1.9 2003/07/04 08:27:52 starvik Exp $ + * + * linux/arch/cris/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1999, 2000, 2001 Axis Communications AB + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1995-03-26 Markus Kuhn + * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 + * precision CMOS clock update + * 1996-05-03 Ingo Molnar + * fixed time warps in do_[slow|fast]_gettimeoffset() + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + * + * Linux/CRIS specific code: + * + * Authors: Bjorn Wesen + * Johan Adolfsson + * + */ + +#include +#include +#include +#include +#include +#include + +u64 jiffies_64 = INITIAL_JIFFIES; + +int have_rtc; /* used to remember if we have an RTC or not */; + +#define TICK_SIZE tick + +extern unsigned long wall_jiffies; + +extern unsigned long do_slow_gettimeoffset(void); +static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + * + * Note: Division is quite slow on CRIS and do_gettimeofday is called + * rather often. Maybe we should do some kind of approximation here + * (a naive approximation would be to divide by 1024). + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + signed long usec, sec; + local_irq_save(flags); + local_irq_disable(); + usec = do_gettimeoffset(); + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + local_irq_restore(flags); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +int do_settimeofday(struct timespec *tv) +{ + unsigned long flags; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + local_irq_save(flags); + local_irq_disable(); + + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_nsec -= do_gettimeoffset() * 1000; + tv->tv_nsec -= (jiffies - wall_jiffies) * TICK_NSEC; + + while (tv->tv_nsec < 0) { + tv->tv_nsec += NSEC_PER_SEC; + tv->tv_sec--; + } + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_nsec; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_state = TIME_ERROR; /* p. 24, (a) */ + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + local_irq_restore(flags); + return 0; +} + + +/* + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ + +int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + + printk("set_rtc_mmss(%lu)\n", nowtime); + + if(!have_rtc) + return 0; + + cmos_minutes = CMOS_READ(RTC_MINUTES); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + return retval; +} + +/* grab the time from the RTC chip */ + +unsigned long +get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", + sec, min, hour, day, mon, year); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. + * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. + */ + +void +update_xtime_from_cmos(void) +{ + if(have_rtc) { + xtime.tv_sec = get_cmos_time(); + xtime.tv_nsec = 0; + } +} diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index 9666d32af62..5273241e072 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: traps.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/traps.c * @@ -6,7 +6,7 @@ * mechanism, as well as some general stack/register dumping * things. * - * Copyright (C) 2000,2001 Axis Communications AB + * Copyright (C) 2000-2002 Axis Communications AB * * Authors: Bjorn Wesen * Hans-Peter Nilsson @@ -14,19 +14,8 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include #include +#include static int kstack_depth_to_print = 24; @@ -95,7 +84,7 @@ void show_trace_task(struct task_struct *tsk) */ void -show_stack(unsigned long *sp) +show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack, addr; int i; @@ -105,8 +94,12 @@ show_stack(unsigned long *sp) * back trace. */ - if(sp == NULL) - sp = (unsigned long*)rdsp(); + if(sp == NULL) { + if (task) + sp = (unsigned long*)task->thread.ksp; + else + sp = (unsigned long*)rdsp(); + } stack = sp; @@ -144,123 +137,9 @@ show_stack() } #endif -void -show_registers(struct pt_regs * regs) -{ - /* We either use rdusp() - the USP register, which might not - correspond to the current process for all cases we're called, - or we use the current->thread.usp, which is not up to date for - the current process. Experience shows we want the USP - register. */ - unsigned long usp = rdusp(); - - printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", - regs->irp, regs->srp, regs->dccr, usp, regs->mof ); - printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", - regs->r0, regs->r1, regs->r2, regs->r3); - printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", - regs->r4, regs->r5, regs->r6, regs->r7); - printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", - regs->r8, regs->r9, regs->r10, regs->r11); - printk("r12: %08lx r13: %08lx oR10: %08lx\n", - regs->r12, regs->r13, regs->orig_r10); - printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); - printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, (unsigned long)current); - - /* - * When in-kernel, we also print out the stack and code at the - * time of the fault.. - */ - if (! user_mode(regs)) { - int i; - - show_stack((unsigned long*)usp); - - /* Dump kernel stack if the previous dump wasn't one. */ - if (usp != 0) - show_stack (NULL); - - printk("\nCode: "); - if(regs->irp < PAGE_OFFSET) - goto bad; - - /* Often enough the value at regs->irp does not point to - the interesting instruction, which is most often the - _previous_ instruction. So we dump at an offset large - enough that instruction decoding should be in sync at - the interesting point, but small enough to fit on a row - (sort of). We point out the regs->irp location in a - ksymoops-friendly way by wrapping the byte for that - address in parentheses. */ - for(i = -12; i < 12; i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->irp)[i])) { -bad: - printk(" Bad IP value."); - break; - } - - if (i == 0) - printk("(%02x) ", c); - else - printk("%02x ", c); - } - printk("\n"); - } -} - -/* Called from entry.S when the watchdog has bitten - * We print out something resembling an oops dump, and if - * we have the nice doggy development flag set, we halt here - * instead of rebooting. - */ - -void -watchdog_bite_hook(struct pt_regs *regs) -{ -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - cli(); - stop_watchdog(); - show_registers(regs); - while(1) /* nothing */; -#else - show_registers(regs); -#endif -} - void dump_stack(void) { - show_stack(NULL); -} - -/* This is normally the 'Oops' routine */ -void -die_if_kernel(const char * str, struct pt_regs * regs, long err) -{ - extern void reset_watchdog(void); - extern void stop_watchdog(void); - - if(user_mode(regs)) - return; - -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - /* This printout might take too long and trigger the - * watchdog normally. If we're in the nice doggy - * development mode, stop the watchdog during printout. - */ - stop_watchdog(); -#endif - - printk("%s: %04lx\n", str, err & 0xffff); - - show_registers(regs); - -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - reset_watchdog(); -#endif - do_exit(SIGSEGV); + show_stack(NULL, NULL); } void __init diff --git a/arch/cris/mm/Makefile b/arch/cris/mm/Makefile index 5a92ec53ca3..f3790c7e41a 100644 --- a/arch/cris/mm/Makefile +++ b/arch/cris/mm/Makefile @@ -3,3 +3,4 @@ # obj-y := init.o fault.o tlb.o extable.o ioremap.o + diff --git a/arch/cris/mm/extable.c b/arch/cris/mm/extable.c dissimilarity index 62% index 7351f59f8bb..7992bdb4fea 100644 --- a/arch/cris/mm/extable.c +++ b/arch/cris/mm/extable.c @@ -1,63 +1,48 @@ -/* - * linux/arch/cris/mm/extable.c - * - * $Log: extable.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.3 2001/09/27 13:52:40 bjornw - * Harmonize underscore-ness with other parts - * - * - */ - -#include -#include -#include - -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; - -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - long diff; - - mid = (last - first) / 2 + first; - diff = mid->insn - value; - if (diff == 0) - return mid->fixup; - else if (diff < 0) - first = mid+1; - else - last = mid-1; - } - return 0; -} - -unsigned long -search_exception_table(unsigned long addr) -{ - unsigned long ret; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - return search_one_table(__start___ex_table, __stop___ex_table-1, addr); -#else - /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) - continue; - ret = search_one_table(mp->ex_table_start, - mp->ex_table_end - 1, addr); - if (ret) return ret; - } -#endif - - return 0; -} +/* + * linux/arch/cris/mm/extable.c + * + * $Log: extable.c,v $ + * Revision 1.4 2003/01/09 14:42:52 starvik + * Merge of Linux 2.5.55 + * + * Revision 1.3 2002/11/21 07:24:54 starvik + * Made search_exception_table similar to implementation for other archs + * (now compiles with CONFIG_MODULES) + * + * Revision 1.2 2002/11/18 07:36:55 starvik + * Removed warning + * + * Revision 1.1 2001/12/17 13:59:27 bjornw + * Initial revision + * + * Revision 1.3 2001/09/27 13:52:40 bjornw + * Harmonize underscore-ness with other parts + * + * + */ + +#include +#include +#include + +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return NULL; +} diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c index 2e4d91e40cf..1af6f3a49da 100644 --- a/arch/cris/mm/fault.c +++ b/arch/cris/mm/fault.c @@ -6,6 +6,25 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.8 2003/07/04 13:02:48 tobiasa + * Moved code snippet from arch/cris/mm/fault.c that searches for fixup code + * to seperate function in arch-specific files. + * + * Revision 1.7 2003/01/22 06:48:38 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.6 2003/01/09 14:42:52 starvik + * Merge of Linux 2.5.55 + * + * Revision 1.5 2002/12/11 14:44:48 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm + * + * Revision 1.4 2002/11/13 15:10:28 starvik + * pte_offset has been renamed to pte_offset_kernel + * + * Revision 1.3 2002/11/05 06:45:13 starvik + * Merge of Linux 2.5.45 + * * Revision 1.2 2001/12/18 13:35:22 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -68,24 +87,13 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include #include #include - -#include -#include -#include +#include #include -#include -extern void die_if_kernel(const char *,struct pt_regs *,long); +extern int find_fixup_code(struct pt_regs *); +extern void die_if_kernel(const char *, struct pt_regs *, long); asmlinkage void do_invalid_op (struct pt_regs *, unsigned long); asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, @@ -107,127 +115,6 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, volatile pgd_t *current_pgd; -/* fast TLB-fill fault handler - * this is called from entry.S with interrupts disabled - */ - -void -handle_mmu_bus_fault(struct pt_regs *regs) -{ - int cause, select; -#ifdef DEBUG - int index; - int page_id; - int acc, inv; -#endif - int miss, we, writeac; - pmd_t *pmd; - pte_t pte; - int errcode; - unsigned long address; - - cause = *R_MMU_CAUSE; - select = *R_TLB_SELECT; - - address = cause & PAGE_MASK; /* get faulting address */ - -#ifdef DEBUG - page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); - acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); - inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); - index = IO_EXTRACT(R_TLB_SELECT, index, select); -#endif - miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); - we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); - writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); - - /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned - * write causes a MMU-fault, it will not be restarted correctly. - * This could happen if a write crosses a page-boundary and the - * second page is not yet COW'ed or even loaded. The workaround - * is to clear the unaligned bit in the CPU status record, so - * that the CPU will rerun both the first and second halves of - * the instruction. This will not have any sideeffects unless - * the first half goes to any device or memory that can't be - * written twice, and which is mapped through the MMU. - * - * We only need to do this for writes. - */ - - if(writeac) - regs->csrinstr &= ~(1 << 5); - - /* Set errcode's R/W flag according to the mode which caused the - * fault - */ - - errcode = writeac << 1; - - D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", - regs->irp, address, miss, inv, we, acc, index, page_id)); - - /* for a miss, we need to reload the TLB entry */ - - if (miss) { - /* see if the pte exists at all - * refer through current_pgd, don't use mm->pgd - */ - - pmd = (pmd_t *)(current_pgd + pgd_index(address)); - if (pmd_none(*pmd)) - goto dofault; - if (pmd_bad(*pmd)) { - printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); - pmd_clear(pmd); - return; - } - pte = *pte_offset(pmd, address); - if (!pte_present(pte)) - goto dofault; - -#ifdef DEBUG - printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); - if (pte_val(pte) & _PAGE_SILENT_WRITE) - printk("Silent-W "); - if (pte_val(pte) & _PAGE_KERNEL) - printk("Kernel "); - if (pte_val(pte) & _PAGE_SILENT_READ) - printk("Silent-R "); - if (pte_val(pte) & _PAGE_GLOBAL) - printk("Global "); - if (pte_val(pte) & _PAGE_PRESENT) - printk("Present "); - if (pte_val(pte) & _PAGE_ACCESSED) - printk("Accessed "); - if (pte_val(pte) & _PAGE_MODIFIED) - printk("Modified "); - if (pte_val(pte) & _PAGE_READ) - printk("Readable "); - if (pte_val(pte) & _PAGE_WRITE) - printk("Writeable "); - printk("\n"); -#endif - - /* load up the chosen TLB entry - * this assumes the pte format is the same as the TLB_LO layout. - * - * the write to R_TLB_LO also writes the vpn and page_id fields from - * R_MMU_CAUSE, which we in this case obviously want to keep - */ - - *R_TLB_LO = pte_val(pte); - - return; - } - - errcode = 1 | (we << 1); - - dofault: - /* leave it to the MM system fault handler below */ - D(printk("do_page_fault %lx errcode %d\n", address, errcode)); - do_page_fault(address, regs, errcode); -} - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -253,7 +140,6 @@ do_page_fault(unsigned long address, struct pt_regs *regs, struct mm_struct *mm; struct vm_area_struct * vma; int writeaccess; - unsigned long fixup; siginfo_t info; tsk = current; @@ -391,20 +277,8 @@ do_page_fault(unsigned long address, struct pt_regs *regs, * code) */ - if ((fixup = search_exception_table(regs->irp)) != 0) { - /* Adjust the instruction pointer in the stackframe */ - - regs->irp = fixup; - - /* We do not want to return by restoring the CPU-state - * anymore, so switch frame-types (see ptrace.h) - */ - - regs->frametype = CRIS_FRAME_NORMAL; - - D(printk("doing fixup to 0x%lx\n", fixup)); + if (find_fixup_code(regs)) return; - } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -498,7 +372,7 @@ vmalloc_fault: * silently loop forever. */ - pte_k = pte_offset(pmd_k, address); + pte_k = pte_offset_kernel(pmd_k, address); if (!pte_present(*pte_k)) goto no_context; diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c dissimilarity index 61% index d9ab23bacb2..3ff9bfcb819 100644 --- a/arch/cris/mm/init.c +++ b/arch/cris/mm/init.c @@ -1,470 +1,230 @@ -/* - * linux/arch/cris/mm/init.c - * - * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000,2001 Axis Communications AB - * - * Authors: Bjorn Wesen (bjornw@axis.com) - * - * $Log: init.c,v $ - * Revision 1.2 2001/12/18 13:35:22 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.31 2001/11/13 16:22:00 bjornw - * Skip calculating totalram and sharedram in si_meminfo - * - * Revision 1.30 2001/11/12 19:02:10 pkj - * Fixed compiler warnings. - * - * Revision 1.29 2001/07/25 16:09:50 bjornw - * val->sharedram will stay 0 - * - * Revision 1.28 2001/06/28 16:30:17 bjornw - * Oops. This needs to wait until 2.4.6 is merged - * - * Revision 1.27 2001/06/28 14:04:07 bjornw - * Fill in sharedram - * - * Revision 1.26 2001/06/18 06:36:02 hp - * Enable free_initmem of __init-type pages - * - * Revision 1.25 2001/06/13 00:02:23 bjornw - * Use a separate variable to store the current pgd to avoid races in schedule - * - * Revision 1.24 2001/05/15 00:52:20 hp - * Only map segment 0xa as seg if CONFIG_JULIETTE - * - * Revision 1.23 2001/04/04 14:35:40 bjornw - * * Removed get_pte_slow and friends (2.4.3 change) - * * Removed bad_pmd handling (2.4.3 change) - * - * Revision 1.22 2001/04/04 13:38:04 matsfg - * Moved ioremap to a separate function instead - * - * Revision 1.21 2001/03/27 09:28:33 bjornw - * ioremap used too early - lets try it in mem_init instead - * - * Revision 1.20 2001/03/23 07:39:21 starvik - * Corrected according to review remarks - * - * Revision 1.19 2001/03/15 14:25:17 bjornw - * More general shadow registers and ioremaped addresses for external I/O - * - * Revision 1.18 2001/02/23 12:46:44 bjornw - * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached - * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O - * is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe) - * - * Revision 1.17 2001/02/22 15:05:21 bjornw - * Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs - * - * Revision 1.16 2001/02/22 15:02:35 bjornw - * Map 0xc straight over during LOW_MAP to allow for memory mapped I/O - * - * Revision 1.15 2001/01/10 21:12:10 bjornw - * loops_per_sec -> loops_per_jiffy - * - * Revision 1.14 2000/11/22 16:23:20 bjornw - * Initialize totalhigh counters to 0 to make /proc/meminfo look nice. - * - * Revision 1.13 2000/11/21 16:37:51 bjornw - * Temporarily disable initmem freeing - * - * Revision 1.12 2000/11/21 13:55:07 bjornw - * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type - * - * Revision 1.11 2000/10/06 12:38:22 bjornw - * Cast empty_bad_page correctly (should really be of * type from the start.. - * - * Revision 1.10 2000/10/04 16:53:57 bjornw - * Fix memory-map due to LX features - * - * Revision 1.9 2000/09/13 15:47:49 bjornw - * Wrong count in reserved-pages loop - * - * Revision 1.8 2000/09/13 14:35:10 bjornw - * 2.4.0-test8 added a new arg to free_area_init_node - * - * Revision 1.7 2000/08/17 15:35:55 bjornw - * 2.4.0-test6 removed MAP_NR and inserted virt_to_page - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -struct pgtable_cache_struct quicklists; /* see asm/pgalloc.h */ - -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; - -extern void die_if_kernel(char *,struct pt_regs *,long); -extern void show_net_buffers(void); -extern void tlb_init(void); - - -unsigned long empty_zero_page; - -/* trim the page-table cache if necessary */ - -int -do_check_pgt_cache(int low, int high) -{ - int freed = 0; - - if(pgtable_cache_size > high) { - do { - if(pgd_quicklist) { - free_pgd_slow(get_pgd_fast()); - freed++; - } - if(pmd_quicklist) { - pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); - freed++; - } - if(pte_quicklist) { - pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed++; - } - } while(pgtable_cache_size > low); - } - return freed; -} - -void -show_mem(void) -{ - int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; - int shared = 0; - - printk("\nMem-info:\n"); - show_free_areas(); - printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (!page_count(mem_map+i)) - free++; - else if (page_count(mem_map+i) == 1) - nonshared++; - else - shared += page_count(mem_map+i) - 1; - } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages nonshared\n",nonshared); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); - printk("%ld pages in page table cache\n",pgtable_cache_size); -} - -/* - * The kernel is already mapped with a kernel segment at kseg_c so - * we don't need to map it with a page table. However head.S also - * temporarily mapped it at kseg_4 so we should set up the ksegs again, - * clear the TLB and do some other paging setup stuff. - */ - -void __init -paging_init(void) -{ - int i; - unsigned long zones_size[MAX_NR_ZONES]; - - printk("Setting up paging and the MMU.\n"); - - /* clear out the init_mm.pgd that will contain the kernel's mappings */ - - for(i = 0; i < PTRS_PER_PGD; i++) - swapper_pg_dir[i] = __pgd(0); - - /* make sure the current pgd table points to something sane - * (even if it is most probably not used until the next - * switch_mm) - */ - - current_pgd = init_mm.pgd; - - /* initialise the TLB (tlb.c) */ - - tlb_init(); - - /* see README.mm for details on the KSEG setup */ - -#ifndef CONFIG_CRIS_LOW_MAP - /* This code is for the corrected Etrax-100 LX version 2... */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ - IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | - IO_STATE(R_MMU_KSEG, seg_7, page ) | - IO_STATE(R_MMU_KSEG, seg_6, page ) | - IO_STATE(R_MMU_KSEG, seg_5, page ) | - IO_STATE(R_MMU_KSEG, seg_4, page ) | - IO_STATE(R_MMU_KSEG, seg_3, page ) | - IO_STATE(R_MMU_KSEG, seg_2, page ) | - IO_STATE(R_MMU_KSEG, seg_1, page ) | - IO_STATE(R_MMU_KSEG, seg_0, page ) ); - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#else - /* Etrax-100 LX version 1 has a bug so that we cannot map anything - * across the 0x80000000 boundary, so we need to shrink the user-virtual - * area to 0x50000000 instead of 0xb0000000 and map things slightly - * different. The unused areas are marked as paged so that we can catch - * freak kernel accesses there. - * - * The ARTPEC chip is mapped at 0xa so we pass that segment straight - * through. We cannot vremap it because the vmalloc area is below 0x8 - * and Juliette needs an uncached area above 0x8. - * - * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. - * We map them straight over in LOW_MAP, but use vremap in LX version 2. - */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | - IO_STATE(R_MMU_KSEG, seg_e, page ) | - IO_STATE(R_MMU_KSEG, seg_d, page ) | - IO_STATE(R_MMU_KSEG, seg_c, page ) | - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ -#ifdef CONFIG_JULIETTE - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ -#else - IO_STATE(R_MMU_KSEG, seg_a, page ) | -#endif - IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ - IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ - IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ - IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | -#ifdef CONFIG_JULIETTE - IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | -#else - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | -#endif - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#endif - - *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); - - /* The MMU has been enabled ever since head.S but just to make - * it totally obvious we do it here as well. - */ - - *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | - IO_STATE(R_MMU_CTRL, acc_excp, enable ) | - IO_STATE(R_MMU_CTRL, we_excp, enable ) ); - - *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); - - /* - * initialize the bad page table and bad page to point - * to a couple of allocated pages - */ - - empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)empty_zero_page, 0, PAGE_SIZE); - - /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ - - zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; - - for (i = 1; i < MAX_NR_ZONES; i++) - zones_size[i] = 0; - - /* Use free_area_init_node instead of free_area_init, because the former - * is designed for systems where the DRAM starts at an address substantially - * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the - * mem_map page array. - */ - - free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); - mem_map = contig_page_data.node_mem_map; -} - -extern unsigned long loops_per_jiffy; /* init/main.c */ -unsigned long loops_per_usec; - -extern char _stext, _edata, _etext; -extern char __init_begin, __init_end; - -void __init -mem_init(void) -{ - int codesize, reservedpages, datasize, initsize; - unsigned long tmp; - - if(!mem_map) - BUG(); - - /* max/min_low_pfn was set by setup.c - * now we just copy it to some other necessary places... - * - * high_memory was also set in setup.c - */ - - max_mapnr = num_physpages = max_low_pfn - min_low_pfn; - - /* this will put all memory onto the freelists */ - totalram_pages = free_all_bootmem(); - - reservedpages = 0; - for (tmp = 0; tmp < max_mapnr; tmp++) { - /* - * Only count reserved RAM pages - */ - if (PageReserved(mem_map + tmp)) - reservedpages++; - } - - codesize = (unsigned long) &_etext - (unsigned long) &_stext; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; - initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; - - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, " - "%dk init)\n" , - (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), - codesize >> 10, - reservedpages << (PAGE_SHIFT-10), - datasize >> 10, - initsize >> 10 - ); - - /* HACK alert - calculate a loops_per_usec for asm/delay.h here - * since this is called just after calibrate_delay in init/main.c - * but before places which use udelay. cannot be in time.c since - * that is called _before_ calibrate_delay - */ - - loops_per_usec = (loops_per_jiffy * HZ) / 1000000; - - return; -} - -/* Initialize remaps of some I/O-ports. This is designed to be callable - * multiple times from the drivers init-sections, because we don't know - * beforehand which driver will get initialized first. - */ - -void -init_ioremap(void) -{ - - /* Give the external I/O-port addresses their values */ - - static int initialized = 0; - - if( !initialized ) { - initialized++; - -#ifdef CONFIG_CRIS_LOW_MAP - /* Simply a linear map (see the KSEG map above in paging_init) */ - port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | - MEM_NON_CACHEABLE); - port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | - MEM_NON_CACHEABLE); - port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | - MEM_NON_CACHEABLE); -#else - /* Note that nothing blows up just because we do this remapping - * it's ok even if the ports are not used or connected - * to anything (or connected to a non-I/O thing) */ - port_cse1_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSE1_START | - MEM_NON_CACHEABLE), 16); - port_csp0_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSP0_START | - MEM_NON_CACHEABLE), 16); - port_csp4_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSP4_START | - MEM_NON_CACHEABLE), 16); -#endif - } -} - - -/* free the pages occupied by initialization code */ - -void -free_initmem(void) -{ - unsigned long addr; - - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - set_page_count(virt_to_page(addr), 1); - free_page(addr); - totalram_pages++; - } - printk ("Freeing unused kernel memory: %luk freed\n", - (&__init_end - &__init_begin) >> 10); -} +/* + * linux/arch/cris/mm/init.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000,2001 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: init.c,v $ + * Revision 1.9 2003/07/04 08:27:54 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.8 2003/04/09 05:20:48 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.7 2003/01/22 06:48:38 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.6 2002/12/11 14:44:48 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm + * + * Revision 1.5 2002/11/18 07:37:37 starvik + * Added cache bug workaround (from Linux 2.4) + * + * Revision 1.4 2002/11/13 15:40:24 starvik + * Removed the page table cache stuff (as done in other archs) + * + * Revision 1.3 2002/11/05 06:45:13 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.2 2001/12/18 13:35:22 bjornw + * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). + * + * Revision 1.31 2001/11/13 16:22:00 bjornw + * Skip calculating totalram and sharedram in si_meminfo + * + * Revision 1.30 2001/11/12 19:02:10 pkj + * Fixed compiler warnings. + * + * Revision 1.29 2001/07/25 16:09:50 bjornw + * val->sharedram will stay 0 + * + * Revision 1.28 2001/06/28 16:30:17 bjornw + * Oops. This needs to wait until 2.4.6 is merged + * + * Revision 1.27 2001/06/28 14:04:07 bjornw + * Fill in sharedram + * + * Revision 1.26 2001/06/18 06:36:02 hp + * Enable free_initmem of __init-type pages + * + * Revision 1.25 2001/06/13 00:02:23 bjornw + * Use a separate variable to store the current pgd to avoid races in schedule + * + * Revision 1.24 2001/05/15 00:52:20 hp + * Only map segment 0xa as seg if CONFIG_JULIETTE + * + * Revision 1.23 2001/04/04 14:35:40 bjornw + * * Removed get_pte_slow and friends (2.4.3 change) + * * Removed bad_pmd handling (2.4.3 change) + * + * Revision 1.22 2001/04/04 13:38:04 matsfg + * Moved ioremap to a separate function instead + * + * Revision 1.21 2001/03/27 09:28:33 bjornw + * ioremap used too early - lets try it in mem_init instead + * + * Revision 1.20 2001/03/23 07:39:21 starvik + * Corrected according to review remarks + * + * Revision 1.19 2001/03/15 14:25:17 bjornw + * More general shadow registers and ioremaped addresses for external I/O + * + * Revision 1.18 2001/02/23 12:46:44 bjornw + * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached + * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O + * is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe) + * + * Revision 1.17 2001/02/22 15:05:21 bjornw + * Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs + * + * Revision 1.16 2001/02/22 15:02:35 bjornw + * Map 0xc straight over during LOW_MAP to allow for memory mapped I/O + * + * Revision 1.15 2001/01/10 21:12:10 bjornw + * loops_per_sec -> loops_per_jiffy + * + * Revision 1.14 2000/11/22 16:23:20 bjornw + * Initialize totalhigh counters to 0 to make /proc/meminfo look nice. + * + * Revision 1.13 2000/11/21 16:37:51 bjornw + * Temporarily disable initmem freeing + * + * Revision 1.12 2000/11/21 13:55:07 bjornw + * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type + * + * Revision 1.11 2000/10/06 12:38:22 bjornw + * Cast empty_bad_page correctly (should really be of * type from the start.. + * + * Revision 1.10 2000/10/04 16:53:57 bjornw + * Fix memory-map due to LX features + * + * Revision 1.9 2000/09/13 15:47:49 bjornw + * Wrong count in reserved-pages loop + * + * Revision 1.8 2000/09/13 14:35:10 bjornw + * 2.4.0-test8 added a new arg to free_area_init_node + * + * Revision 1.7 2000/08/17 15:35:55 bjornw + * 2.4.0-test6 removed MAP_NR and inserted virt_to_page + * + * + */ + +#include +#include +#include + +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + +unsigned long empty_zero_page; + +extern unsigned long loops_per_jiffy; /* init/main.c */ +unsigned long loops_per_usec; + +extern char _stext, _edata, _etext; /* From linkerscript */ +extern char __init_begin, __init_end; + +void +show_mem(void) +{ + int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; + int shared = 0; + + printk("\nMem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else if (page_count(mem_map+i) == 1) + nonshared++; + else + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages nonshared\n",nonshared); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); +} + +void __init +mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + unsigned long tmp; + + if(!mem_map) + BUG(); + + /* max/min_low_pfn was set by setup.c + * now we just copy it to some other necessary places... + * + * high_memory was also set in setup.c + */ + + max_mapnr = num_physpages = max_low_pfn - min_low_pfn; + + /* this will put all memory onto the freelists */ + totalram_pages = free_all_bootmem(); + + reservedpages = 0; + for (tmp = 0; tmp < max_mapnr; tmp++) { + /* + * Only count reserved RAM pages + */ + if (PageReserved(mem_map + tmp)) + reservedpages++; + } + + codesize = (unsigned long) &_etext - (unsigned long) &_stext; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, " + "%dk init)\n" , + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10 + ); + + /* HACK alert - calculate a loops_per_usec for asm/delay.h here + * since this is called just after calibrate_delay in init/main.c + * but before places which use udelay. cannot be in time.c since + * that is called _before_ calibrate_delay + */ + + loops_per_usec = (loops_per_jiffy * HZ) / 1000000; + + return; +} + +/* free the pages occupied by initialization code */ + +void +free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing unused kernel memory: %luk freed\n", + (unsigned long)((&__init_end - &__init_begin) >> 10)); +} diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c index 53656f9c5dc..14216d9668f 100644 --- a/arch/cris/mm/ioremap.c +++ b/arch/cris/mm/ioremap.c @@ -12,12 +12,13 @@ #include #include #include +#include +#include -static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, +extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, unsigned long flags) { unsigned long end; - unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -25,17 +26,16 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned l end = PMD_SIZE; if (address >= end) BUG(); - pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | __READABLE | - __WRITEABLE | _PAGE_GLOBAL | - _PAGE_KERNEL | flags))); + set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | + __WRITEABLE | _PAGE_GLOBAL | + _PAGE_KERNEL | flags))); address += PAGE_SIZE; - pfn++; + phys_addr += PAGE_SIZE; pte++; } while (address && (address < end)); } @@ -53,7 +53,7 @@ static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo if (address >= end) BUG(); do { - pte_t * pte = pte_alloc(&init_mm, pmd, address); + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -148,7 +148,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr) - phys_addr; + size = PAGE_ALIGN(last_addr+1) - phys_addr; /* * Ok, go for it.. diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c dissimilarity index 66% index f5a97c9799f..23eca5ad738 100644 --- a/arch/cris/mm/tlb.c +++ b/arch/cris/mm/tlb.c @@ -1,347 +1,126 @@ -/* - * linux/arch/cris/mm/tlb.c - * - * Copyright (C) 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen (bjornw@axis.com) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define D(x) - -/* CRIS in Etrax100LX TLB */ - -#define NUM_TLB_ENTRIES 64 -#define NUM_PAGEID 64 -#define INVALID_PAGEID 63 -#define NO_CONTEXT -1 - -/* The TLB can host up to 64 different mm contexts at the same time. - * The running context is R_MMU_CONTEXT, and each TLB entry contains a - * page_id that has to match to give a hit. In page_id_map, we keep track - * of which mm's we have assigned which page_id's, so that we know when - * to invalidate TLB entries. - * - * The last page_id is never running - it is used as an invalid page_id - * so we can make TLB entries that will never match. - * - * Notice that we need to make the flushes atomic, otherwise an interrupt - * handler that uses vmalloced memory might cause a TLB load in the middle - * of a flush causing. - */ - -struct mm_struct *page_id_map[NUM_PAGEID]; - -static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ - -/* invalidate all TLB entries */ - -void -flush_tlb_all(void) -{ - int i; - unsigned long flags; - - /* the vpn of i & 0xf is so we don't write similar TLB entries - * in the same 4-way entry group. details.. - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - restore_flags(flags); - D(printk("tlb: flushed all\n")); -} - -/* invalidate the selected mm context only */ - -void -flush_tlb_mm(struct mm_struct *mm) -{ - int i; - int page_id = mm->context; - unsigned long flags; - - D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - /* mark the TLB entries that match the page_id as invalid. - * here we could also check the _PAGE_GLOBAL bit and NOT flush - * global pages. is it worth the extra I/O ? - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* invalidate a single page */ - -void -flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) -{ - struct mm_struct *mm = vma->vm_mm; - int page_id = mm->context; - int i; - unsigned long flags; - - D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - addr &= PAGE_MASK; /* perhaps not necessary */ - - /* invalidate those TLB entries that match both the mm context - * and the virtual address requested - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - unsigned long tlb_hi; - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - tlb_hi = *R_TLB_HI; - if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && - (tlb_hi & PAGE_MASK) == addr) { - *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - addr; /* same addr as before works. */ - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* invalidate a page range */ - -void -flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, - unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - int page_id = mm->context; - int i; - unsigned long flags; - - D(printk("tlb: flush range %p<->%p in context %d (%p)\n", - start, end, page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - start &= PAGE_MASK; /* probably not necessary */ - end &= PAGE_MASK; /* dito */ - - /* invalidate those TLB entries that match both the mm context - * and the virtual address range - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - unsigned long tlb_hi, vpn; - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - tlb_hi = *R_TLB_HI; - vpn = tlb_hi & PAGE_MASK; - if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && - vpn >= start && vpn < end) { - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* dump the entire TLB for debug purposes */ - -#if 0 -void -dump_tlb_all(void) -{ - int i; - unsigned long flags; - - printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); - - save_and_cli(flags); - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); - printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", - i, *R_TLB_HI, *R_TLB_LO); - } - restore_flags(flags); -} -#endif - -/* - * Initialize the context related info for a new mm_struct - * instance. - */ - -int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - mm->context = NO_CONTEXT; - return 0; -} - -/* the following functions are similar to those used in the PPC port */ - -static inline void -alloc_context(struct mm_struct *mm) -{ - struct mm_struct *old_mm; - - D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); - - /* did we replace an mm ? */ - - old_mm = page_id_map[map_replace_ptr]; - - if(old_mm) { - /* throw out any TLB entries belonging to the mm we replace - * in the map - */ - flush_tlb_mm(old_mm); - - old_mm->context = NO_CONTEXT; - } - - /* insert it into the page_id_map */ - - mm->context = map_replace_ptr; - page_id_map[map_replace_ptr] = mm; - - map_replace_ptr++; - - if(map_replace_ptr == INVALID_PAGEID) - map_replace_ptr = 0; /* wrap around */ -} - -/* - * if needed, get a new MMU context for the mm. otherwise nothing is done. - */ - -void -get_mmu_context(struct mm_struct *mm) -{ - if(mm->context == NO_CONTEXT) - alloc_context(mm); -} - -/* called in schedule() just before actually doing the switch_to */ - -void -switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, int cpu) -{ - /* make sure we have a context */ - - get_mmu_context(next); - - /* remember the pgd for the fault handlers - * this is similar to the pgd register in some other CPU's. - * we need our own copy of it because current and active_mm - * might be invalid at points where we still need to derefer - * the pgd. - */ - - current_pgd = next->pgd; - - /* switch context in the MMU */ - - D(printk("switching mmu_context to %d (%p)\n", next->context, next)); - - *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); -} - - -/* called by __exit_mm to destroy the used MMU context if any before - * destroying the mm itself. this is only called when the last user of the mm - * drops it. - * - * the only thing we really need to do here is mark the used PID slot - * as empty. - */ - -void -destroy_context(struct mm_struct *mm) -{ - if(mm->context != NO_CONTEXT) { - D(printk("destroy_context %d (%p)\n", mm->context, mm)); - flush_tlb_mm(mm); /* TODO this might be redundant ? */ - page_id_map[mm->context] = NULL; - /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ - } -} - -/* called once during VM initialization, from init.c */ - -void __init -tlb_init(void) -{ - int i; - - /* clear the page_id map */ - - for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) - page_id_map[i] = NULL; - - /* invalidate the entire TLB */ - - flush_tlb_all(); - - /* the init_mm has context 0 from the boot */ - - page_id_map[0] = &init_mm; -} +/* + * linux/arch/cris/mm/tlb.c + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + */ + +#include +#include + +#define D(x) + +/* The TLB can host up to 64 different mm contexts at the same time. + * The running context is R_MMU_CONTEXT, and each TLB entry contains a + * page_id that has to match to give a hit. In page_id_map, we keep track + * of which mm's we have assigned which page_id's, so that we know when + * to invalidate TLB entries. + * + * The last page_id is never running - it is used as an invalid page_id + * so we can make TLB entries that will never match. + * + * Notice that we need to make the flushes atomic, otherwise an interrupt + * handler that uses vmalloced memory might cause a TLB load in the middle + * of a flush causing. + */ + +struct mm_struct *page_id_map[NUM_PAGEID]; +static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ + +int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + mm->context = NO_CONTEXT; + return 0; +} + +/* the following functions are similar to those used in the PPC port */ + +static inline void +alloc_context(struct mm_struct *mm) +{ + struct mm_struct *old_mm; + + D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); + + /* did we replace an mm ? */ + + old_mm = page_id_map[map_replace_ptr]; + + if(old_mm) { + /* throw out any TLB entries belonging to the mm we replace + * in the map + */ + flush_tlb_mm(old_mm); + + old_mm->context = NO_CONTEXT; + } + + /* insert it into the page_id_map */ + + mm->context = map_replace_ptr; + page_id_map[map_replace_ptr] = mm; + + map_replace_ptr++; + + if(map_replace_ptr == INVALID_PAGEID) + map_replace_ptr = 0; /* wrap around */ +} + +/* + * if needed, get a new MMU context for the mm. otherwise nothing is done. + */ + +void +get_mmu_context(struct mm_struct *mm) +{ + if(mm->context == NO_CONTEXT) + alloc_context(mm); +} + +/* called by __exit_mm to destroy the used MMU context if any before + * destroying the mm itself. this is only called when the last user of the mm + * drops it. + * + * the only thing we really need to do here is mark the used PID slot + * as empty. + */ + +void +destroy_context(struct mm_struct *mm) +{ + if(mm->context != NO_CONTEXT) { + D(printk("destroy_context %d (%p)\n", mm->context, mm)); + flush_tlb_mm(mm); /* TODO this might be redundant ? */ + page_id_map[mm->context] = NULL; + /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ + } +} + +/* called once during VM initialization, from init.c */ + +void __init +tlb_init(void) +{ + int i; + + /* clear the page_id map */ + + for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) + page_id_map[i] = NULL; + + /* invalidate the entire TLB */ + + flush_tlb_all(); + + /* the init_mm has context 0 from the boot */ + + page_id_map[0] = &init_mm; +} diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index ed5254e36ee..3d78369616c 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1339,6 +1339,14 @@ config DEBUG_SPINLOCK best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + config DEBUG_HIGHMEM bool "Highmem debugging" depends on DEBUG_KERNEL && HIGHMEM diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index a114c2ab7f8..99167880abb 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -430,6 +430,14 @@ void __init early_cpu_init(void) rise_init_cpu(); nexgen_init_cpu(); umc_init_cpu(); + +#ifdef CONFIG_DEBUG_PAGEALLOC + /* pse is not compatible with on-the-fly unmapping, + * disable it even if the cpus claim to support it. + */ + clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); + disable_pse = 1; +#endif } /* * cpu_init() initializes state that is per-CPU. Some data is already @@ -487,7 +495,7 @@ void __init cpu_init (void) current->active_mm = &init_mm; if (current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, cpu); + enter_lazy_tlb(&init_mm, current); load_esp0(t, thread->esp0); set_tss_desc(cpu,t); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 91a8a25f635..36181c7a0c6 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -268,8 +268,8 @@ static void change_speed (unsigned int index) change_VID(vid); } else { /* Going up, so change VID first */ - change_VID(fid); - change_FID(vid); + change_VID(vid); + change_FID(fid); } diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 5aef7a47a38..dafcae8663c 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -876,5 +876,6 @@ ENTRY(sys_call_table) .long sys_clock_nanosleep .long sys_statfs64 .long sys_fstatfs64 + .long sys_tgkill nr_syscalls=(.-sys_call_table)/4 diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 57159fe9fac..3e5ec5c69f8 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -2052,7 +2053,6 @@ static inline void unlock_ExtINT_logic(void) */ static inline void check_timer(void) { - extern int timer_ack; int pin1, pin2; int vector; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 6e0ff0a46b5..314d47e8ec1 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -416,7 +416,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) * handled by some other CPU. (or is disabled) */ int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ - int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; @@ -437,7 +436,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) } } #endif - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 72362882327..127452cfe39 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -189,7 +189,6 @@ void disable_timer_nmi_watchdog(void) if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0)) return; - disable_irq(0); unset_nmi_callback(); nmi_active = -1; nmi_watchdog = NMI_NONE; @@ -201,7 +200,6 @@ void enable_timer_nmi_watchdog(void) nmi_watchdog = NMI_IO_APIC; touch_nmi_watchdog(); nmi_active = 1; - enable_irq(0); } } diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index db98194645c..9309c404e7a 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -80,8 +80,7 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(i8253_lock); -extern struct timer_opts timer_none; -struct timer_opts* timer = &timer_none; +struct timer_opts *cur_timer = &timer_none; /* * This version of gettimeofday has microsecond resolution @@ -93,14 +92,14 @@ void do_gettimeofday(struct timeval *tv) unsigned long usec, sec; do { + unsigned long lost; + seq = read_seqbegin(&xtime_lock); - usec = timer->get_offset(); - { - unsigned long lost = jiffies - wall_jiffies; - if (lost) - usec += lost * (1000000 / HZ); - } + usec = cur_timer->get_offset(); + lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); sec = xtime.tv_sec; usec += (xtime.tv_nsec / 1000); } while (read_seqretry(&xtime_lock, seq)); @@ -126,7 +125,7 @@ int do_settimeofday(struct timespec *tv) * wall time. Discover what correction gettimeofday() would have * made, and then undo it! */ - tv->tv_nsec -= timer->get_offset() * NSEC_PER_USEC; + tv->tv_nsec -= cur_timer->get_offset() * NSEC_PER_USEC; tv->tv_nsec -= (jiffies - wall_jiffies) * TICK_NSEC; while (tv->tv_nsec < 0) { @@ -180,7 +179,7 @@ int timer_ack; */ unsigned long long monotonic_clock(void) { - return timer->monotonic_clock(); + return cur_timer->monotonic_clock(); } EXPORT_SYMBOL(monotonic_clock); @@ -189,7 +188,8 @@ EXPORT_SYMBOL(monotonic_clock); * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static inline void do_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { #ifdef CONFIG_X86_IO_APIC if (timer_ack) { @@ -259,7 +259,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ write_seqlock(&xtime_lock); - timer->mark_offset(); + cur_timer->mark_offset(); do_timer_interrupt(irq, NULL, regs); @@ -301,16 +301,13 @@ static int time_init_device(void) device_initcall(time_init_device); - void __init time_init(void) { - xtime.tv_sec = get_cmos_time(); wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); wall_to_monotonic.tv_nsec = -xtime.tv_nsec; - - timer = select_timer(); + cur_timer = select_timer(); time_init_hook(); } diff --git a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c index 538c2c33f4e..cf8f641d38f 100644 --- a/arch/i386/kernel/timers/timer.c +++ b/arch/i386/kernel/timers/timer.c @@ -3,12 +3,6 @@ #include #include -/* list of externed timers */ -extern struct timer_opts timer_pit; -extern struct timer_opts timer_tsc; -#ifdef CONFIG_X86_CYCLONE_TIMER -extern struct timer_opts timer_cyclone; -#endif /* list of timers, ordered by preference, NULL terminated */ static struct timer_opts* timers[] = { #ifdef CONFIG_X86_CYCLONE_TIMER @@ -29,6 +23,15 @@ static int __init clock_setup(char* str) } __setup("clock=", clock_setup); + +/* The chosen timesource has been found to be bad. + * Fall back to a known good timesource (the PIT) + */ +void clock_fallback(void) +{ + cur_timer = &timer_pit; +} + /* iterates through the list of timers, returning the first * one that initializes successfully. */ diff --git a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c index 0d2c2baf2a6..f88c490e0a2 100644 --- a/arch/i386/kernel/timers/timer_cyclone.c +++ b/arch/i386/kernel/timers/timer_cyclone.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,7 +19,6 @@ #include extern spinlock_t i8253_lock; -extern unsigned long jiffies; extern unsigned long calibrate_tsc(void); /* Number of usecs that the last interrupt was delayed */ @@ -88,7 +88,7 @@ static void mark_offset_cyclone(void) * between cyclone and pit reads (as noted when * usec delta is > 90% # of usecs/tick) */ - if (abs(delay - delay_at_last_interrupt) > (900000/HZ)) + if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ)) jiffies++; } diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index 02de71f68d9..9988b67dd83 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -21,7 +22,6 @@ int tsc_disable __initdata = 0; extern spinlock_t i8253_lock; -extern unsigned long jiffies; static int use_tsc; /* Number of usecs that the last interrupt was delayed */ @@ -124,6 +124,7 @@ static void mark_offset_tsc(void) int countmp; static int count1 = 0; unsigned long long this_offset, last_offset; + static int lost_count = 0; write_lock(&monotonic_lock); last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; @@ -178,9 +179,19 @@ static void mark_offset_tsc(void) delta += delay_at_last_interrupt; lost = delta/(1000000/HZ); delay = delta%(1000000/HZ); - if (lost >= 2) + if (lost >= 2) { jiffies += lost-1; + /* sanity check to ensure we're not always loosing ticks */ + if (lost_count++ > 100) { + printk(KERN_WARNING "Loosing too many ticks!\n"); + printk(KERN_WARNING "TSC cannot be used as a timesource." + " (Are you running with SpeedStep?)\n"); + printk(KERN_WARNING "Falling back to a sane timesource.\n"); + clock_fallback(); + } + } else + lost_count = 0; /* update the monotonic base value */ this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low; monotonic_base += cycles_2_ns(this_offset - last_offset); @@ -194,7 +205,7 @@ static void mark_offset_tsc(void) * between tsc and pit reads (as noted when * usec delta is > 90% # of usecs/tick) */ - if (abs(delay - delay_at_last_interrupt) > (900000/HZ)) + if (lost && abs(delay - delay_at_last_interrupt) > (900000/HZ)) jiffies++; } diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c index a678560d383..028dd9bbd22 100644 --- a/arch/i386/lib/delay.c +++ b/arch/i386/lib/delay.c @@ -25,7 +25,7 @@ extern struct timer_opts* timer; void __delay(unsigned long loops) { - timer->delay(loops); + cur_timer->delay(loops); } inline void __const_udelay(unsigned long xloops) diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c index 7bb9f7ebe46..51b777c42d5 100644 --- a/arch/i386/mm/pageattr.c +++ b/arch/i386/mm/pageattr.c @@ -13,6 +13,10 @@ #include #include +static spinlock_t cpa_lock = SPIN_LOCK_UNLOCKED; +static struct list_head df_list = LIST_HEAD_INIT(df_list); + + static inline pte_t *lookup_address(unsigned long address) { pgd_t *pgd = pgd_offset_k(address); @@ -31,10 +35,15 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot) { int i; unsigned long addr; - struct page *base = alloc_pages(GFP_KERNEL, 0); + struct page *base; pte_t *pbase; + + spin_unlock_irq(&cpa_lock); + base = alloc_pages(GFP_KERNEL, 0); + spin_lock_irq(&cpa_lock); if (!base) return NULL; + address = __pa(address); addr = address & LARGE_PAGE_MASK; pbase = (pte_t *)page_address(base); @@ -87,7 +96,7 @@ static inline void revert_page(struct page *kpte_page, unsigned long address) } static int -__change_page_attr(struct page *page, pgprot_t prot, struct page **oldpage) +__change_page_attr(struct page *page, pgprot_t prot) { pte_t *kpte; unsigned long address; @@ -123,7 +132,7 @@ __change_page_attr(struct page *page, pgprot_t prot, struct page **oldpage) } if (cpu_has_pse && (atomic_read(&kpte_page->count) == 1)) { - *oldpage = kpte_page; + list_add(&kpte_page->list, &df_list); revert_page(kpte_page, address); } return 0; @@ -134,12 +143,6 @@ static inline void flush_map(void) on_each_cpu(flush_kernel_map, NULL, 1, 1); } -struct deferred_page { - struct deferred_page *next; - struct page *fpage; -}; -static struct deferred_page *df_list; /* protected by init_mm.mmap_sem */ - /* * Change the page attributes of an page in the linear mapping. * @@ -156,47 +159,54 @@ static struct deferred_page *df_list; /* protected by init_mm.mmap_sem */ int change_page_attr(struct page *page, int numpages, pgprot_t prot) { int err = 0; - struct page *fpage; int i; + unsigned long flags; - down_write(&init_mm.mmap_sem); + spin_lock_irqsave(&cpa_lock, flags); for (i = 0; i < numpages; i++, page++) { - fpage = NULL; - err = __change_page_attr(page, prot, &fpage); + err = __change_page_attr(page, prot); if (err) break; - if (fpage) { - struct deferred_page *df; - df = kmalloc(sizeof(struct deferred_page), GFP_KERNEL); - if (!df) { - flush_map(); - __free_page(fpage); - } else { - df->next = df_list; - df->fpage = fpage; - df_list = df; - } - } } - up_write(&init_mm.mmap_sem); + spin_unlock_irqrestore(&cpa_lock, flags); return err; } void global_flush_tlb(void) { - struct deferred_page *df, *next_df; + LIST_HEAD(l); + struct list_head* n; - down_read(&init_mm.mmap_sem); - df = xchg(&df_list, NULL); - up_read(&init_mm.mmap_sem); + BUG_ON(irqs_disabled()); + + spin_lock_irq(&cpa_lock); + list_splice_init(&df_list, &l); + spin_unlock_irq(&cpa_lock); flush_map(); - for (; df; df = next_df) { - next_df = df->next; - if (df->fpage) - __free_page(df->fpage); - kfree(df); - } + n = l.next; + while (n != &l) { + struct page *pg = list_entry(n, struct page, list); + n = n->next; + __free_page(pg); + } } +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages(struct page *page, int numpages, int enable) +{ + if (PageHighMem(page)) + return; + /* the return value is ignored - the calls cannot fail, + * large pages are disabled at boot time. + */ + change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0)); + /* we should perform an IPI and flush all tlbs, + * but that can deadlock->flush only current cpu. + */ + __flush_tlb_all(); +} +EXPORT_SYMBOL(kernel_map_pages); +#endif + EXPORT_SYMBOL(change_page_attr); EXPORT_SYMBOL(global_flush_tlb); diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c index 7ab983c90c5..941c2aa5236 100644 --- a/arch/i386/mm/pgtable.c +++ b/arch/i386/mm/pgtable.c @@ -34,7 +34,7 @@ void show_mem(void) show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_size; ++i) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pgdat->node_mem_map + i; total++; if (PageHighMem(page)) diff --git a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c index 7cb2029ca85..1b7747ca726 100644 --- a/arch/i386/oprofile/init.c +++ b/arch/i386/oprofile/init.c @@ -34,7 +34,7 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { #ifdef CONFIG_X86_LOCAL_APIC nmi_exit(); diff --git a/arch/i386/oprofile/op_model_p4.c b/arch/i386/oprofile/op_model_p4.c index 0c3de1990aa..188900c1d71 100644 --- a/arch/i386/oprofile/op_model_p4.c +++ b/arch/i386/oprofile/op_model_p4.c @@ -278,7 +278,7 @@ static struct p4_event_binding p4_events[NUM_EVENTS] = { }, { /* GLOBAL_POWER_EVENTS */ - 0x06, 0x13 /* manual says 0x05 */, + 0x06, 0x13 /* older manual says 0x05, newer 0x13 */, { { CTR_BPU_0, MSR_P4_FSB_ESCR0}, { CTR_BPU_2, MSR_P4_FSB_ESCR1} } }, diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 3a8be667ddf..b99be74dc91 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -177,7 +177,7 @@ static struct pci_raw_ops pci_direct_conf2 = { * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -static int __devinit pci_sanity_check(struct pci_raw_ops *o) +static int __init pci_sanity_check(struct pci_raw_ops *o) { u32 x = 0; int devfn; diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 53db10c42fe..4f9feba2fc9 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -102,13 +102,12 @@ static void __init pirq_peer_trick(void) #endif busmap[e->bus] = 1; } - for(i=1; i<256; i++) - /* - * It might be a secondary bus, but in this case its parent is already - * known (ascending bus order) and therefore pci_scan_bus returns immediately. - */ - if (busmap[i] && pci_scan_bus(i, &pci_root_ops, NULL)) + for(i = 1; i < 256; i++) { + if (!busmap[i] || pci_find_bus(0, i)) + continue; + if (pci_scan_bus(i, &pci_root_ops, NULL)) printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); + } pcibios_last_bus = -1; } @@ -196,15 +195,16 @@ static int pirq_piix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, /* * The VIA pirq rules are nibble-based, like ALI, * but without the ugly irq number munging. + * However, PIRQD is in the upper instead of lower 4 bits. */ static int pirq_via_get(struct pci_dev *router, struct pci_dev *dev, int pirq) { - return read_config_nybble(router, 0x55, pirq); + return read_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq); } static int pirq_via_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq) { - write_config_nybble(router, 0x55, pirq, irq); + write_config_nybble(router, 0x55, pirq == 4 ? 5 : pirq, irq); return 1; } diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c index 29fea7d6ad6..c72bf1a59b7 100644 --- a/arch/i386/pci/legacy.c +++ b/arch/i386/pci/legacy.c @@ -11,40 +11,26 @@ */ static void __devinit pcibios_fixup_peer_bridges(void) { - int n; - struct pci_bus *bus; - struct pci_dev *dev; - u16 l; + int n, devfn; if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) return; DBG("PCI: Peer bridge fixup\n"); - bus = kmalloc(sizeof(*bus), GFP_ATOMIC); - dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if (!bus || !dev) { - printk(KERN_ERR "Out of memory in %s\n", __FUNCTION__); - goto exit; - } - for (n=0; n <= pcibios_last_bus; n++) { - if (pci_bus_exists(&pci_root_buses, n)) + u32 l; + if (pci_find_bus(0, n)) continue; - bus->number = n; - bus->ops = &pci_root_ops; - dev->bus = bus; - for (dev->devfn=0; dev->devfn<256; dev->devfn += 8) - if (!pci_read_config_word(dev, PCI_VENDOR_ID, &l) && + for (devfn = 0; devfn < 256; devfn += 8) { + if (!raw_pci_ops->read(0, n, devfn, PCI_VENDOR_ID, 2, &l) && l != 0x0000 && l != 0xffff) { DBG("Found device at %02x:%02x [%04x]\n", n, dev->devfn, l); printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); pci_scan_bus(n, &pci_root_ops, NULL); break; } + } } -exit: - kfree(dev); - kfree(bus); } static int __init pci_legacy_init(void) diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 9bfae790059..9c4f04e6363 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -708,33 +708,6 @@ config MAGIC_SYSRQ keys are documented in . Don't say Y unless you really know what this hack does. -config IA64_EARLY_PRINTK - bool "Early printk support" - depends on DEBUG_KERNEL && !IA64_GENERIC - help - Selecting this option uses the VGA screen or serial console for - printk() output before the consoles are initialised. It is useful - for debugging problems early in the boot process, but only if you - have a suitable VGA/serial console attached. If you're unsure, - select N. - -config IA64_EARLY_PRINTK_UART - bool "Early printk on MMIO serial port" - depends on IA64_EARLY_PRINTK - -config IA64_EARLY_PRINTK_UART_BASE - hex "UART MMIO base address" - depends on IA64_EARLY_PRINTK_UART - default "ff5e0000" - -config IA64_EARLY_PRINTK_VGA - bool "Early printk on VGA" - depends on IA64_EARLY_PRINTK - -config IA64_EARLY_PRINTK_SGI_SN - bool "Early printk on SGI SN serial console" - depends on IA64_EARLY_PRINTK && (IA64_GENERIC || IA64_SGI_SN2) - config DEBUG_SLAB bool "Debug memory allocations" depends on DEBUG_KERNEL diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 77f7c35cf0c..85db8f8eb1b 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -47,8 +47,10 @@ /* ** This option allows cards capable of 64bit DMA to bypass the IOMMU. If ** not defined, all DMA will be 32bit and go through the TLB. +** There's potentially a conflict in the bio merge code with us +** advertising an iommu, but then bypassing it. Disabled for now. */ -#define ALLOW_IOV_BYPASS +#undef ALLOW_IOV_BYPASS /* ** If a device prefetches beyond the end of a valid pdir entry, it will cause diff --git a/arch/ia64/hp/sim/hpsim_irq.c b/arch/ia64/hp/sim/hpsim_irq.c index ad60a4cce38..77dd1302f21 100644 --- a/arch/ia64/hp/sim/hpsim_irq.c +++ b/arch/ia64/hp/sim/hpsim_irq.c @@ -39,7 +39,7 @@ hpsim_irq_init (void) int i; for (i = 0; i < NR_IRQS; ++i) { - idesc = irq_desc(i); + idesc = irq_descp(i); if (idesc->handler == &no_irq_type) idesc->handler = &irq_type_hp_sim; } diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index 730382f8f48..2982f536bf4 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -350,6 +350,7 @@ simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *)) break; case MODE_SENSE: + case MODE_SENSE_10: /* sd.c uses this to determine whether disk does write-caching. */ memset(sc->request_buffer, 0, 128); sc->result = GOOD; diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index dcc4982c2c6..8b2a4159274 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -177,7 +178,7 @@ ia32_setup_arg_pages (struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; - if (!vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index fd033607bf6..d778e4d6cc7 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -420,7 +420,12 @@ ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot return addr; if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len) + { + if (flags & MAP_FIXED) + return -ENOMEM; + else return -EINVAL; + } if (OFFSET4K(offset)) return -EINVAL; @@ -519,7 +524,7 @@ sys32_munmap (unsigned int start, unsigned int len) #if PAGE_SHIFT <= IA32_PAGE_SHIFT ret = sys_munmap(start, end - start); #else - if (start > end) + if (start >= end) return -EINVAL; start = PAGE_ALIGN(start); @@ -1275,7 +1280,7 @@ semctl32 (int first, int second, int third, void *uptr) static int do_sys32_msgsnd (int first, int second, int third, void *uptr) { - struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); + struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); struct msgbuf32 *up = (struct msgbuf32 *)uptr; mm_segment_t old_fs; int err; @@ -1317,12 +1322,12 @@ do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void msgtyp = ipck.msgtyp; } err = -ENOMEM; - p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); + p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); if (!p) goto out; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_msgrcv(first, p, second + 4, msgtyp, third); + err = sys_msgrcv(first, p, second, msgtyp, third); set_fs(old_fs); if (err < 0) goto free_then_out; @@ -2542,13 +2547,31 @@ asmlinkage long sys32_sysinfo (struct sysinfo32 *info) { extern asmlinkage long sys_sysinfo (struct sysinfo *); - mm_segment_t old_fs = get_fs(); struct sysinfo s; long ret, err; + int bitcount = 0; + mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_sysinfo(&s); set_fs(old_fs); + /* Check to see if any memory value is too large for 32-bit and + * scale down if needed. + */ + if ((s.totalram >> 32) || (s.totalswap >> 32)) { + while (s.mem_unit < PAGE_SIZE) { + s.mem_unit <<= 1; + bitcount++; + } + s.totalram >>= bitcount; + s.freeram >>= bitcount; + s.sharedram >>= bitcount; + s.bufferram >>= bitcount; + s.totalswap >>= bitcount; + s.freeswap >>= bitcount; + s.totalhigh >>= bitcount; + s.freehigh >>= bitcount; + } if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) return -EFAULT; diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index ba2bcfc717b..8fe8f08641b 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1408,7 +1408,7 @@ sys_call_table: data8 sys_sched_getaffinity data8 sys_set_tid_address data8 sys_fadvise64 - data8 ia64_ni_syscall // 1235 + data8 sys_tgkill // 1235 data8 sys_exit_group data8 sys_lookup_dcookie data8 sys_io_setup diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index 32ecc497b47..f3ea890b90e 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h @@ -15,7 +15,6 @@ #define PT_REGS_SAVES(off) \ .unwabi 3, 'i'; \ - .unwabi @svr4, 'i'; \ .fframe IA64_PT_REGS_SIZE+16+(off); \ .spillsp rp, PT(CR_IIP)+16+(off); \ .spillsp ar.pfs, PT(CR_IFS)+16+(off); \ diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index ff4f2b38f97..771ef25ab49 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -655,8 +655,8 @@ fsyscall_table: data8 0 // sched_setaffinity data8 0 // sched_getaffinity data8 fsys_set_tid_address // set_tid_address - data8 0 // unused - data8 0 // unused // 1235 + data8 0 // fadvise64 + data8 0 // tgkill // 1235 data8 0 // exit_group data8 0 // lookup_dcookie data8 0 // io_setup diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index b78a08624cd..9ae14758639 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -199,13 +199,15 @@ ia64_decrement_ip (struct pt_regs *regs) * rnat0/rnat1 gets its value from sw->ar_rnat. */ static unsigned long -get_rnat (struct pt_regs *pt, struct switch_stack *sw, +get_rnat (struct task_struct *task, struct switch_stack *sw, unsigned long *krbs, unsigned long *urnat_addr, unsigned long *urbs_end) { unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0, mask, m; unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; long num_regs, nbits; + struct pt_regs *pt; + pt = ia64_task_regs(task); kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; @@ -254,21 +256,41 @@ get_rnat (struct pt_regs *pt, struct switch_stack *sw, * The reverse of get_rnat. */ static void -put_rnat (struct pt_regs *pt, struct switch_stack *sw, +put_rnat (struct task_struct *task, struct switch_stack *sw, unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat, unsigned long *urbs_end) { unsigned long rnat0 = 0, rnat1 = 0, *slot0_kaddr, umask = 0, mask, m; unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; long num_regs, nbits; + struct pt_regs *pt; + unsigned long cfm, *urbs_kargs; + struct unw_frame_info info; + pt = ia64_task_regs(task); kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; - if (urbs_end < urnat_addr) - nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_end); - else + urbs_kargs = urbs_end; + if ((long)pt->cr_ifs >= 0) { + /* + * If entered via syscall, don't allow user to set rnat bits + * for syscall args. + */ + unw_init_from_blocked_task(&info,task); + if (unw_unwind_to_user(&info) == 0) { + unw_get_cfm(&info,&cfm); + urbs_kargs = ia64_rse_skip_regs(urbs_end,-(cfm & 0x7f)); + } + } + + if (urbs_kargs >= urnat_addr) nbits = 63; + else { + if ((urnat_addr - 63) >= urbs_kargs) + return; + nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_kargs); + } mask = (1UL << nbits) - 1; /* @@ -339,7 +361,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack, unsigned * read the corresponding bits in the kernel RBS. */ rnat_addr = ia64_rse_rnat_addr(laddr); - ret = get_rnat(child_regs, child_stack, krbs, rnat_addr, urbs_end); + ret = get_rnat(child, child_stack, krbs, rnat_addr, urbs_end); if (laddr == rnat_addr) { /* return NaT collection word itself */ @@ -390,7 +412,7 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack, unsigned * => write the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) - put_rnat(child_regs, child_stack, krbs, laddr, val, urbs_end); + put_rnat(child, child_stack, krbs, laddr, val, urbs_end); else { if (laddr < urbs_end) { regnum = ia64_rse_num_regs(bspstore, laddr); diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 6de52294bd8..50f606b2e5f 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -26,8 +26,9 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len unsigned long pgoff, unsigned long flags) { long map_shared = (flags & MAP_SHARED); - unsigned long align_mask = PAGE_SIZE - 1; - struct vm_area_struct * vmm; + unsigned long start_addr, align_mask = PAGE_SIZE - 1; + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; if (len > RGN_MAP_LIMIT) return -ENOMEM; @@ -37,7 +38,7 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len addr = 0; #endif if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = mm->free_area_cache; if (map_shared && (TASK_SIZE > 0xfffffffful)) /* @@ -48,17 +49,25 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len */ align_mask = SHMLBA - 1; - addr = (addr + align_mask) & ~align_mask; - - for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (TASK_SIZE - len < addr) - return -ENOMEM; - if (REGION_OFFSET(addr) + len > RGN_MAP_LIMIT) /* no risk of overflow here... */ + full_search: + start_addr = addr = (addr + align_mask) & ~align_mask; + + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) { + if (start_addr != TASK_UNMAPPED_BASE) { + /* Start a new search --- just in case we missed some holes. */ + addr = TASK_UNMAPPED_BASE; + goto full_search; + } return -ENOMEM; - if (!vmm || addr + len <= vmm->vm_start) + } + if (!vma || addr + len <= vma->vm_start) { + /* Remember the address where we stopped this search: */ + mm->free_area_cache = addr + len; return addr; - addr = (vmm->vm_end + align_mask) & ~align_mask; + } + addr = (vma->vm_end + align_mask) & ~align_mask; } } @@ -100,7 +109,6 @@ ia64_shmat (int shmid, void *shmaddr, int shmflg) asmlinkage unsigned long ia64_brk (unsigned long brk) { - extern int vm_enough_memory (long pages); unsigned long rlim, retval, newbrk, oldbrk; struct mm_struct *mm = current->mm; diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 428c481f2c9..0a14f97334a 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -58,15 +58,9 @@ #ifdef UNW_DEBUG static unsigned int unw_debug_level = UNW_DEBUG; -# ifdef CONFIG_KDB -# include -# define UNW_DEBUG_ON(n) (unw_debug_level >= n && !KDB_IS_RUNNING()) -# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) kdb_printf(__VA_ARGS__) -# else /* !CONFIG_KDB */ -# define UNW_DEBUG_ON(n) unw_debug_level >= n - /* Do not code a printk level, not all debug lines end in newline */ -# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) -# endif /* CONFIG_KDB */ +# define UNW_DEBUG_ON(n) unw_debug_level >= n + /* Do not code a printk level, not all debug lines end in newline */ +# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) # define inline #else /* !UNW_DEBUG */ # define UNW_DEBUG_ON(n) 0 @@ -2124,7 +2118,7 @@ unw_remove_unwind_table (void *handle) kfree(table); } -static void __init +static int __init create_gate_table (void) { const struct unw_table_entry *entry, *start, *end; @@ -2142,7 +2136,7 @@ create_gate_table (void) if (!punw) { printk("%s: failed to find gate DSO's unwind table!\n", __FUNCTION__); - return; + return 0; } start = (const struct unw_table_entry *) punw->p_vaddr; @@ -2159,7 +2153,7 @@ create_gate_table (void) if (!unw.gate_table) { unw.gate_table_size = 0; printk(KERN_ERR "%s: unable to create unwind data for gate page!\n", __FUNCTION__); - return; + return 0; } unw.gate_table_size = size; @@ -2176,6 +2170,7 @@ create_gate_table (void) lp[2] = info - (char *) unw.gate_table; /* info */ } *lp = 0; /* end-of-table marker */ + return 0; } __initcall(create_gate_table); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 8fc22262ce0..14ae18c1af0 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -121,7 +121,7 @@ ia64_init_addr_space (void) vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma) { vma->vm_mm = current->mm; - vma->vm_start = current->thread.rbs_bot; + vma->vm_start = current->thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; @@ -232,7 +232,7 @@ show_mem(void) printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { printk("Node ID: %d\n", pgdat->node_id); - for(i = 0; i < pgdat->node_size; i++) { + for(i = 0; i < pgdat->node_spanned_pages; i++) { if (PageReserved(pgdat->node_mem_map+i)) reserved++; else if (PageSwapCache(pgdat->node_mem_map+i)) @@ -240,7 +240,7 @@ show_mem(void) else if (page_count(pgdat->node_mem_map + i)) shared += page_count(pgdat->node_mem_map + i) - 1; } - printk("\t%d pages of RAM\n", pgdat->node_size); + printk("\t%d pages of RAM\n", pgdat->node_spanned_pages); printk("\t%d reserved pages\n", reserved); printk("\t%d pages shared\n", shared); printk("\t%d pages swap cached\n", cached); diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 2bbf9c01f14..bbd4b795c1f 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -138,37 +138,6 @@ alloc_pci_controller (int seg) return controller; } -static struct pci_bus * -scan_root_bus (int bus, struct pci_ops *ops, void *sysdata) -{ - struct pci_bus *b; - - /* - * We know this is a new root bus we haven't seen before, so - * scan it, even if we've seen the same bus number in a different - * segment. - */ - b = kmalloc(sizeof(*b), GFP_KERNEL); - if (!b) - return NULL; - - memset(b, 0, sizeof(*b)); - INIT_LIST_HEAD(&b->children); - INIT_LIST_HEAD(&b->devices); - - list_add_tail(&b->node, &pci_root_buses); - - b->number = b->secondary = bus; - b->resource[0] = &ioport_resource; - b->resource[1] = &iomem_resource; - - b->sysdata = sysdata; - b->ops = ops; - b->subordinate = pci_do_scan_bus(b); - - return b; -} - static int alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags) { @@ -312,7 +281,7 @@ pci_acpi_scan_root (struct acpi_device *device, int domain, int bus) info.name = name; acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, &info); - return scan_root_bus(bus, &pci_root_ops, controller); + return pci_scan_bus(bus, &pci_root_ops, controller); out3: kfree(controller->window); diff --git a/arch/ia64/sn/io/Makefile b/arch/ia64/sn/io/Makefile index b2080573dc8..10970306a6f 100644 --- a/arch/ia64/sn/io/Makefile +++ b/arch/ia64/sn/io/Makefile @@ -11,5 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += sgi_if.o xswitch.o sgi_io_sim.o cdl.o ate_utils.o \ +obj-y += sgi_if.o xswitch.o sgi_io_sim.o cdl.o \ io.o machvec/ drivers/ platform_init/ sn2/ hwgfs/ diff --git a/arch/ia64/sn/io/ate_utils.c b/arch/ia64/sn/io/ate_utils.c deleted file mode 100644 index a5b11ae21b5..00000000000 --- a/arch/ia64/sn/io/ate_utils.c +++ /dev/null @@ -1,204 +0,0 @@ -/* $Id: ate_utils.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Allocate the map needed to allocate the ATE entries. - */ -struct map * -atemapalloc(ulong_t mapsiz) -{ - struct map *mp; - ulong_t size; - struct a { - spinlock_t lock; - sv_t sema; - } *sync; - - if (mapsiz == 0) - return(NULL); - size = sizeof(struct map) * (mapsiz + 2); - if ((mp = (struct map *) kmalloc(size, GFP_KERNEL)) == NULL) - return(NULL); - memset(mp, 0x0, size); - - sync = kmalloc(sizeof(struct a), GFP_KERNEL); - if (sync == NULL) { - kfree(mp); - return(NULL); - } - memset(sync, 0x0, sizeof(struct a)); - - mutex_spinlock_init(&sync->lock); - sv_init( &(sync->sema), &(sync->lock), SV_MON_SPIN | SV_ORDER_FIFO /*| SV_INTS*/); - mp[1].m_size = (unsigned long) &sync->lock; - mp[1].m_addr = (unsigned long) &sync->sema; - mapsize(mp) = mapsiz - 1; - return(mp); -} - -/* - * free a map structure previously allocated via rmallocmap(). - */ -void -atemapfree(struct map *mp) -{ - struct a { - spinlock_t lock; - sv_t sema; - }; - /* ASSERT(sv_waitq(mapout(mp)) == 0); */ - /* sv_destroy(mapout(mp)); */ - spin_lock_destroy(maplock(mp)); - kfree((void *)mp[1].m_size); - kfree(mp); -} - -/* - * Allocate 'size' units from the given map. - * Return the base of the allocated space. - * In a map, the addresses are increasing and the - * list is terminated by a 0 size. - * Algorithm is first-fit. - */ - -ulong_t -atealloc( - struct map *mp, - size_t size) -{ - register unsigned int a; - register struct map *bp; - register unsigned long s; - - ASSERT(size >= 0); - - if (size == 0) - return((ulong_t) NULL); - - s = mutex_spinlock(maplock(mp)); - - for (bp = mapstart(mp); bp->m_size; bp++) { - if (bp->m_size >= size) { - a = bp->m_addr; - bp->m_addr += size; - if ((bp->m_size -= size) == 0) { - do { - bp++; - (bp-1)->m_addr = bp->m_addr; - } while ((((bp-1)->m_size) = (bp->m_size))); - mapsize(mp)++; - } - - ASSERT(bp->m_size < 0x80000000); - mutex_spinunlock(maplock(mp), s); - return(a); - } - } - - /* - * We did not get what we need .. we cannot sleep .. - */ - mutex_spinunlock(maplock(mp), s); - return(0); -} - -/* - * Free the previously allocated space a of size units into the specified map. - * Sort ``a'' into map and combine on one or both ends if possible. - * Returns 0 on success, 1 on failure. - */ -void -atefree(struct map *mp, size_t size, ulong_t a) -{ - register struct map *bp; - register unsigned int t; - register unsigned long s; - - ASSERT(size >= 0); - - if (size == 0) - return; - - bp = mapstart(mp); - s = mutex_spinlock(maplock(mp)); - - for ( ; bp->m_addr<=a && bp->m_size!=0; bp++) - ; - if (bp>mapstart(mp) && (bp-1)->m_addr+(bp-1)->m_size == a) { - (bp-1)->m_size += size; - if (bp->m_addr) { - /* m_addr==0 end of map table */ - ASSERT(a+size <= bp->m_addr); - if (a+size == bp->m_addr) { - - /* compress adjacent map addr entries */ - (bp-1)->m_size += bp->m_size; - while (bp->m_size) { - bp++; - (bp-1)->m_addr = bp->m_addr; - (bp-1)->m_size = bp->m_size; - } - mapsize(mp)++; - } - } - } else { - if (a+size == bp->m_addr && bp->m_size) { - bp->m_addr -= size; - bp->m_size += size; - } else { - ASSERT(size); - if (mapsize(mp) == 0) { - mutex_spinunlock(maplock(mp), s); - printk("atefree : map overflow 0x%p Lost 0x%lx items at 0x%lx", - (void *)mp, size, a) ; - return ; - } - do { - t = bp->m_addr; - bp->m_addr = a; - a = t; - t = bp->m_size; - bp->m_size = size; - bp++; - } while ((size = t)); - mapsize(mp)--; - } - } - mutex_spinunlock(maplock(mp), s); - /* - * wake up everyone waiting for space - */ - if (mapout(mp)) - ; - /* sv_broadcast(mapout(mp)); */ -} diff --git a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c index 0bad4c76da9..0ec5807cc73 100644 --- a/arch/ia64/sn/io/hwgfs/ramfs.c +++ b/arch/ia64/sn/io/hwgfs/ramfs.c @@ -190,7 +190,7 @@ static int hwgfs_fill_super(struct super_block * sb, void * data, int silent) } static struct super_block *hwgfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) + int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, hwgfs_fill_super); } diff --git a/arch/ia64/sn/io/machvec/iomv.c b/arch/ia64/sn/io/machvec/iomv.c index e69d0b81d95..5efa61deed6 100644 --- a/arch/ia64/sn/io/machvec/iomv.c +++ b/arch/ia64/sn/io/machvec/iomv.c @@ -26,8 +26,12 @@ void * sn_io_addr(unsigned long port) { if (!IS_RUNNING_ON_SIMULATOR()) { + /* On sn2, legacy I/O ports don't point at anything */ + if (port < 64*1024) + return 0; return( (void *) (port | __IA64_UNCACHED_OFFSET)); } else { + /* but the simulator uses them... */ unsigned long io_base; unsigned long addr; diff --git a/arch/ia64/sn/io/machvec/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c index 2e1ce4d34ab..5a26e7efb80 100644 --- a/arch/ia64/sn/io/machvec/pci_dma.c +++ b/arch/ia64/sn/io/machvec/pci_dma.c @@ -153,8 +153,7 @@ sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_hand *dma_handle = 0; - /* We can't easily support < 32 bit devices */ - if (IS_PCI32L(hwdev)) + if (hwdev->dma_mask < 0xffffffffUL) return NULL; /* @@ -173,8 +172,6 @@ sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_hand if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) return NULL; - memset(cpuaddr, 0, size); /* have to zero it out */ - /* physical addr. of the memory we just got */ phys_addr = __pa(cpuaddr); @@ -188,6 +185,16 @@ sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_hand ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_CMD); + /* + * If this device is in PCI-X mode, the system would have + * automatically allocated a 64Bits DMA Address. Error out if the + * device cannot support DAC. + */ + if (*dma_handle > hwdev->consistent_dma_mask) { + free_pages((unsigned long) cpuaddr, get_order(size)); + return NULL; + } + /* * It is a 32 bit card and we cannot do direct mapping, * so we try to use an ATE. diff --git a/arch/ia64/sn/io/sgi_if.c b/arch/ia64/sn/io/sgi_if.c index a4d65390113..11f2db1f6ae 100644 --- a/arch/ia64/sn/io/sgi_if.c +++ b/arch/ia64/sn/io/sgi_if.c @@ -55,46 +55,6 @@ snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node) } -#define xtod(c) ((c) <= '9' ? '0' - (c) : 'a' - (c) - 10) -long -atoi(register char *p) -{ - register long n; - register int c, neg = 0; - - if (p == NULL) - return 0; - - if (!isdigit(c = *p)) { - while (isspace(c)) - c = *++p; - switch (c) { - case '-': - neg++; - case '+': /* fall-through */ - c = *++p; - } - if (!isdigit(c)) - return (0); - } - if (c == '0' && *(p + 1) == 'x') { - p += 2; - c = *p; - n = xtod(c); - while ((c = *++p) && isxdigit(c)) { - n *= 16; /* two steps to avoid unnecessary overflow */ - n += xtod(c); /* accum neg to avoid surprises at MAX */ - } - } else { - n = '0' - c; - while ((c = *++p) && isdigit(c)) { - n *= 10; /* two steps to avoid unnecessary overflow */ - n += '0' - c; /* accum neg to avoid surprises at MAX */ - } - } - return (neg ? n : -n); -} - /* * print_register() allows formatted printing of bit fields. individual * bit fields are described by a struct reg_desc, multiple bit fields within diff --git a/arch/ia64/sn/io/sn2/Makefile b/arch/ia64/sn/io/sn2/Makefile index f8521c8bcea..3263e3c184f 100644 --- a/arch/ia64/sn/io/sn2/Makefile +++ b/arch/ia64/sn/io/sn2/Makefile @@ -12,7 +12,7 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN obj-y += pcibr/ ml_SN_intr.o shub_intr.o shuberror.o shub.o bte_error.o \ - pic.o geo_op.o l1.o l1_command.o klconflib.o klgraph.o ml_SN_init.o \ + pic.o geo_op.o l1_command.o klconflib.o klgraph.o ml_SN_init.o \ ml_iograph.o module.o pciio.o xbow.o xtalk.o shubio.o obj-$(CONFIG_KDB) += kdba_io.o diff --git a/arch/ia64/sn/io/sn2/l1.c b/arch/ia64/sn/io/sn2/l1.c deleted file mode 100644 index ac37d3ce6c9..00000000000 --- a/arch/ia64/sn/io/sn2/l1.c +++ /dev/null @@ -1,293 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -/* In general, this file is organized in a hierarchy from lower-level - * to higher-level layers, as follows: - * - * UART routines - * Bedrock/L1 "PPP-like" protocol implementation - * System controller "message" interface (allows multiplexing - * of various kinds of requests and responses with - * console I/O) - * Console interface: - * "l1_cons", the glue that allows the L1 to act - * as the system console for the stdio libraries - * - * Routines making use of the system controller "message"-style interface - * can be found in l1_command.c. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define UART_BAUD_RATE 57600 - -static int L1_connected; /* non-zero when interrupts are enabled */ - - -int -get_L1_baud(void) -{ - return UART_BAUD_RATE; -} - - - -/* Return the current interrupt level */ -int -l1_get_intr_value( void ) -{ - cpuid_t intr_cpuid; - nasid_t console_nasid; - int major, minor; - extern nasid_t get_console_nasid(void); - - /* if it is an old prom, run in poll mode */ - - major = sn_sal_rev_major(); - minor = sn_sal_rev_minor(); - if ( (major < 1) || ((major == 1) && (minor < 10)) ) { - /* before version 1.10 doesn't work */ - return (0); - } - - console_nasid = get_console_nasid(); - intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; - return CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); -} - -/* Disconnect the callup functions - throw away interrupts */ - -void -l1_unconnect_intr(void) -{ -} - -/* Set up uart interrupt handling for this node's uart */ - -int -l1_connect_intr(void *intr_func, void *arg, struct pt_regs *ep) -{ - cpuid_t intr_cpuid; - nasid_t console_nasid; - unsigned int console_irq; - int result; - extern int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); - extern nasid_t get_console_nasid(void); - - - /* don't call to connect multiple times - we DON'T support changing the handler */ - - if ( !L1_connected ) { - L1_connected++; - console_nasid = get_console_nasid(); - intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; - console_irq = CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); - result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR, - 0 /*not used*/, 0 /*not used*/); - if (result != SGI_UART_VECTOR) { - if (result < 0) - printk(KERN_WARNING "L1 console driver : intr_connect_level failed %d\n", result); - else - printk(KERN_WARNING "L1 console driver : intr_connect_level returns wrong bit %d\n", result); - return (-1); - } - - result = request_irq(console_irq, intr_func, SA_INTERRUPT, - "SGI L1 console driver", (void *)arg); - if (result < 0) { - printk(KERN_WARNING "L1 console driver : request_irq failed %d\n", result); - return (-1); - } - - /* ask SAL to turn on interrupts in the UART itself */ - ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); - } - return (0); -} - - -/* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. These are external - * interfaces into the protocol driver. - */ - -void -l1_control_out(int offset, int value) -{ - /* quietly ignore unless simulator */ - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - if ( master_node_bedrock_address != (u64)0 ) { - writeb(value, (unsigned long)master_node_bedrock_address + - (offset<< 3)); - } - return; - } -} - -/* Console input exported interface. Return a register value. */ - -int -l1_control_in_polled(int offset) -{ - static int l1_control_in_local(int); - - return(l1_control_in_local(offset)); -} - -int -l1_control_in(int offset) -{ - static int l1_control_in_local(int); - - return(l1_control_in_local(offset)); -} - -static int -l1_control_in_local(int offset) -{ - int sal_call_status = 0, input; - int ret = 0; - - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - ret = readb((unsigned long)master_node_bedrock_address + - (offset<< 3)); - return(ret); - } - if ( offset == REG_LSR ) { - ret = (LSR_XHRE | LSR_XSRE); /* can send anytime */ - sal_call_status = ia64_sn_console_check(&input); - if ( !sal_call_status && input ) { - /* input pending */ - ret |= LSR_RCA; - } - } - return(ret); -} - -/* - * Console input exported interface. Return a character (if one is available) - */ - -int -l1_serial_in_polled(void) -{ - static int l1_serial_in_local(void); - - return(l1_serial_in_local()); -} - -int -l1_serial_in(void) -{ - static int l1_serial_in_local(void); - - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); - } - return(l1_serial_in_local()); -} - -static int -l1_serial_in_local(void) -{ - int ch; - - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3))); - } - - if ( !(ia64_sn_console_getc(&ch)) ) - return(ch); - else - return(0); -} - -/* Console output exported interface. Write message to the console. */ - -int -l1_serial_out( char *str, int len ) -{ - int tmp; - - /* Ignore empty messages */ - if ( len == 0 ) - return(len); - -#if defined(CONFIG_IA64_EARLY_PRINTK) - /* Need to setup SAL calls so the PROM calls will work */ - { - static int inited; - void early_sn_setup(void); - if(!inited) { - inited=1; - early_sn_setup(); - } - } -#endif - - if ( IS_RUNNING_ON_SIMULATOR() ) { - extern u64 master_node_bedrock_address; - void early_sn_setup(void); - int counter = len; - - if (!master_node_bedrock_address) - early_sn_setup(); - if ( master_node_bedrock_address != (u64)0 ) { -#ifdef FLAG_DIRECT_CONSOLE_WRITES - /* This is an easy way to pre-pend the output to know whether the output - * was done via sal or directly */ - writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); -#endif /* FLAG_DIRECT_CONSOLE_WRITES */ - while ( counter > 0 ) { - writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3)); - counter--; - str++; - } - } - return(len); - } - - /* Attempt to write things out thru the sal */ - if ( L1_connected ) - tmp = ia64_sn_console_xmit_chars(str, len); - else - tmp = ia64_sn_console_putb(str, len); - return ((tmp < 0) ? 0 : tmp); -} diff --git a/arch/ia64/sn/io/sn2/module.c b/arch/ia64/sn/io/sn2/module.c index 4679cf22e69..e7a32c49b4a 100644 --- a/arch/ia64/sn/io/sn2/module.c +++ b/arch/ia64/sn/io/sn2/module.c @@ -262,18 +262,3 @@ io_module_init(void) if (nserial == 0) DPRINTF(KERN_WARNING "io_module_init: No serial number found.\n"); } - -int -get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) -{ - if (cmod < 0 || cmod >= nummodules) - return -EINVAL; - - mod_info->mod_num = modules[cmod]->id; - - ia64_sn_sys_serial_get(mod_info->serial_str); - - mod_info->serial_num = ia64_sn_partition_serial_get(); - - return 0; -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c index ed31eedfab9..ce602a24797 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c @@ -30,19 +30,6 @@ #include #include -#ifdef __ia64 -uint64_t atealloc(struct map *mp, size_t size); -void atefree(struct map *mp, size_t size, uint64_t a); -void atemapfree(struct map *mp); -struct map *atemapalloc(uint64_t mapsiz); - -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - - #ifndef LOCAL #define LOCAL static #endif @@ -165,32 +152,55 @@ pcibr_init_ext_ate_ram(bridge_t *bridge) int pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) { - int index = 0; + int status = 0; + struct resource *new_res; + struct resource **allocated_res; + + new_res = (struct resource *) kmalloc( sizeof(struct resource), GFP_ATOMIC); + memset(new_res, 0, sizeof(*new_res)); + status = allocate_resource( &pcibr_soft->bs_int_ate_resource, new_res, + count, pcibr_soft->bs_int_ate_resource.start, + pcibr_soft->bs_int_ate_resource.end, 1, + NULL, NULL); + + if ( status && (pcibr_soft->bs_ext_ate_resource.end != 0) ) { + status = allocate_resource( &pcibr_soft->bs_ext_ate_resource, new_res, + count, pcibr_soft->bs_ext_ate_resource.start, + pcibr_soft->bs_ext_ate_resource.end, 1, + NULL, NULL); + if (status) { + new_res->start = -1; + } + } - index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); + if (status) { + /* Failed to allocate */ + kfree(new_res); + return -1; + } - if (!index && pcibr_soft->bs_ext_ate_map) - index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); + /* Save the resource for freeing */ + allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + new_res->start * sizeof( unsigned long)); + *allocated_res = new_res; - /* rmalloc manages resources in the 1..n - * range, with 0 being failure. - * pcibr_ate_alloc manages resources - * in the 0..n-1 range, with -1 being failure. - */ - return index - 1; + return new_res->start; } void pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) /* Who says there's no such thing as a free meal? :-) */ { - /* note the "+1" since rmalloc handles 1..n but - * we start counting ATEs at zero. - */ - rmfree((index < pcibr_soft->bs_int_ate_size) - ? pcibr_soft->bs_int_ate_map - : pcibr_soft->bs_ext_ate_map, - count, index + 1); + + struct resource **allocated_res; + int status = 0; + + allocated_res = (struct resource **)(((unsigned long)pcibr_soft->bs_allocated_ate_res) + index * sizeof(unsigned long)); + + status = release_resource(*allocated_res); + if (status) + BUG(); /* Ouch .. */ + kfree(*allocated_res); + } /* diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c index 2d1d193d07b..1e80244c0a2 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -34,13 +35,6 @@ #include #include -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - /* * global variables to toggle the different levels of pcibr debugging. * -pcibr_debug_mask is the mask of the different types of debugging @@ -933,7 +927,7 @@ pcibr_bus_cnvlink(vertex_hdl_t f_c) xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); if (xp == NULL) return 0; - widgetnum = atoi(xp+7); + widgetnum = simple_strtoul(xp+7, NULL, 0); if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) return 0; @@ -1494,18 +1488,21 @@ pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, /* we always have 128 ATEs (512 for Xbridge) inside the chip * even if disabled for debugging. */ - pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); - pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); + pcibr_soft->bs_int_ate_resource.start = 0; + pcibr_soft->bs_int_ate_resource.end = pcibr_soft->bs_int_ate_size - 1; if (num_entries > pcibr_soft->bs_int_ate_size) { #if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ printk("pcibr_attach: disabling internal ATEs.\n"); pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); #endif - pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); - pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, - num_entries - pcibr_soft->bs_int_ate_size); + pcibr_soft->bs_ext_ate_resource.start = pcibr_soft->bs_int_ate_size; + pcibr_soft->bs_ext_ate_resource.end = num_entries; } + + pcibr_soft->bs_allocated_ate_res = (void *) kmalloc(pcibr_soft->bs_int_ate_size * sizeof(unsigned long), GFP_KERNEL); + memset(pcibr_soft->bs_allocated_ate_res, 0x0, pcibr_soft->bs_int_ate_size * sizeof(unsigned long)); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl, "pcibr_attach2: %d ATEs, %d internal & %d external\n", num_entries ? num_entries : pcibr_soft->bs_int_ate_size, @@ -1716,10 +1713,10 @@ pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, { - pciio_win_map_t win_map_p; iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; int prom_base_size = 0x1000000; - iopaddr_t prom_base_limit = prom_base_addr + prom_base_size; + int status; + struct resource *res; /* Allocate resource maps based on bus page size; for I/O and memory * space, free all pages except those in the base area and in the @@ -1729,35 +1726,38 @@ pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, * the widget number and s is the device register offset for the slot. */ - win_map_p = &pcibr_soft->bs_io_win_map; - pciio_device_win_map_new(win_map_p, - PCIBR_BUS_IO_MAX + 1, - PCIBR_BUS_IO_PAGE); - pciio_device_win_populate(win_map_p, - PCIBR_BUS_IO_BASE, - prom_base_addr - PCIBR_BUS_IO_BASE); - pciio_device_win_populate(win_map_p, - prom_base_limit, - (PCIBR_BUS_IO_MAX + 1) - prom_base_limit); - - win_map_p = &pcibr_soft->bs_swin_map; - pciio_device_win_map_new(win_map_p, - PCIBR_BUS_SWIN_MAX + 1, - PCIBR_BUS_SWIN_PAGE); - pciio_device_win_populate(win_map_p, - PCIBR_BUS_SWIN_BASE, - (PCIBR_BUS_SWIN_MAX + 1) - PCIBR_BUS_SWIN_PAGE); - - win_map_p = &pcibr_soft->bs_mem_win_map; - pciio_device_win_map_new(win_map_p, - PCIBR_BUS_MEM_MAX + 1, - PCIBR_BUS_MEM_PAGE); - pciio_device_win_populate(win_map_p, - PCIBR_BUS_MEM_BASE, - prom_base_addr - PCIBR_BUS_MEM_BASE); - pciio_device_win_populate(win_map_p, - prom_base_limit, - (PCIBR_BUS_MEM_MAX + 1) - prom_base_limit); + /* Setup the Bus's PCI IO Root Resource. */ + pcibr_soft->bs_io_win_root_resource.start = PCIBR_BUS_IO_BASE; + pcibr_soft->bs_io_win_root_resource.end = 0xffffffff; + res = (struct resource *) kmalloc( sizeof(struct resource), KM_NOSLEEP); + if (!res) + panic("PCIBR:Unable to allocate resource structure\n"); + + /* Block off the range used by PROM. */ + res->start = prom_base_addr; + res->end = prom_base_addr + (prom_base_size - 1); + status = request_resource(&pcibr_soft->bs_io_win_root_resource, res); + if (status) + panic("PCIBR:Unable to request_resource()\n"); + + /* Setup the Small Window Root Resource */ + pcibr_soft->bs_swin_root_resource.start = _PAGESZ; + pcibr_soft->bs_swin_root_resource.end = 0x000FFFFF; + + /* Setup the Bus's PCI Memory Root Resource */ + pcibr_soft->bs_mem_win_root_resource.start = 0x200000; + pcibr_soft->bs_mem_win_root_resource.end = 0xffffffff; + res = (struct resource *) kmalloc( sizeof(struct resource), KM_NOSLEEP); + if (!res) + panic("PCIBR:Unable to allocate resource structure\n"); + + /* Block off the range used by PROM. */ + res->start = prom_base_addr; + res->end = prom_base_addr + (prom_base_size - 1);; + status = request_resource(&pcibr_soft->bs_mem_win_root_resource, res); + if (status) + panic("PCIBR:Unable to request_resource()\n"); + } /* build "no-slot" connection point @@ -1940,15 +1940,6 @@ pcibr_detach(vertex_hdl_t xconn) spin_lock_destroy(&pcibr_soft->bs_lock); kfree(pcibr_soft->bs_name); - /* Error handler gets unregistered when the widget info is - * cleaned - */ - /* Free the soft ATE maps */ - if (pcibr_soft->bs_int_ate_map) - rmfreemap(pcibr_soft->bs_int_ate_map); - if (pcibr_soft->bs_ext_ate_map) - rmfreemap(pcibr_soft->bs_ext_ate_map); - /* Disconnect the error interrupt and free the xtalk resources * associated with it. */ @@ -4188,14 +4179,14 @@ pcibr_debug(uint32_t type, vertex_hdl_t vhdl, char *format, ...) cp = strstr(hwpath, "/xtalk/"); if (cp) { cp += strlen("/xtalk/"); - widget = atoi(cp); + widget = simple_strtoul(cp, NULL, 0); } } if (pcibr_debug_slot != -1) { cp = strstr(hwpath, "/pci/"); if (cp) { cp += strlen("/pci/"); - slot = atoi(cp); + slot = simple_strtoul(cp, NULL, 0); } } } @@ -4214,9 +4205,15 @@ pcibr_debug(uint32_t type, vertex_hdl_t vhdl, char *format, ...) * Since we have a variable length argument list, we * need to call printk this way rather than directly */ - va_start(ap, format); - printk(format, ap); - va_end(ap); + { + char buffer[500]; + + va_start(ap, format); + vsnprintf(buffer, 500, format, ap); + va_end(ap); + buffer[499] = (char)0; /* just to be safe */ + printk("%s", buffer); + } } } } diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c index 211aec200f4..dd633b33cec 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c @@ -31,11 +31,6 @@ #include #ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc - inline int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) { diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c index bafa7d7d303..9063c1f1d8b 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c @@ -700,10 +700,10 @@ pcibr_slot_initial_rrb_alloc(vertex_hdl_t pcibr_vhdl, pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft) - return(EINVAL); + return(-EINVAL); if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); + return(-EINVAL); bridge = pcibr_soft->bs_base; @@ -741,7 +741,13 @@ pcibr_slot_initial_rrb_alloc(vertex_hdl_t pcibr_vhdl, pcibr_soft->bs_rrb_valid[slot][3] = chan[3]; - return(ENODEV); + return(-ENODEV); + } + + /* Give back any assigned to empty slots */ + if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && !pcibr_soft->bs_slot[slot].has_host) { + do_pcibr_rrb_free_all(pcibr_soft, bridge, slot); + return(-ENODEV); } for (vchan = 0; vchan < vchan_total; vchan++) diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c index c469c78454a..2c9c7129daa 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c @@ -30,15 +30,6 @@ #include #include #include -#include - -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - extern pcibr_info_t pcibr_info_get(vertex_hdl_t); extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); @@ -142,7 +133,7 @@ pcibr_slot_startup(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) error = pcibr_slot_attach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_ATTACH, l1_msg, &tmp_up_resp.resp_sub_errno); - strlcpy(tmp_up_resp.resp_l1_msg, l1_msg, L1_QSIZE); + strncpy(tmp_up_resp.resp_l1_msg, l1_msg, L1_QSIZE); tmp_up_resp.resp_l1_msg[L1_QSIZE] = '\0'; if (COPYOUT(&tmp_up_resp, reqp->req_respp.up, reqp->req_size)) { @@ -228,8 +219,8 @@ pcibr_slot_shutdown(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) error = pcibr_slot_detach(pcibr_vhdl, slot, D_PCI_HOT_PLUG_DETACH, l1_msg, &tmp_down_resp.resp_sub_errno); - strlcpy(tmp_down_resp.resp_l1_msg, l1_msg, - sizeof(tmp_down_resp.resp_l1_msg)); + strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE); + tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0'; shutdown_copyout: @@ -1877,30 +1868,36 @@ pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p, pciio_space_t space, int start, int size, int align) { pciio_win_map_t win_map_p; + struct resource *root_resource = NULL; + iopaddr_t iopaddr = 0; switch (space) { case PCIIO_SPACE_IO: win_map_p = &pcibr_soft->bs_io_win_map; + root_resource = &pcibr_soft->bs_io_win_root_resource; break; case PCIIO_SPACE_MEM: win_map_p = &pcibr_soft->bs_swin_map; + root_resource = &pcibr_soft->bs_swin_root_resource; break; case PCIIO_SPACE_MEM32: win_map_p = &pcibr_soft->bs_mem_win_map; + root_resource = &pcibr_soft->bs_mem_win_root_resource; break; default: return 0; } - return pciio_device_win_alloc(win_map_p, + iopaddr = pciio_device_win_alloc(root_resource, win_info_p ? &win_info_p->w_win_alloc : NULL, start, size, align); + return(iopaddr); } diff --git a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c index e0a147a57dc..0c51f37f539 100644 --- a/arch/ia64/sn/io/sn2/pciio.c +++ b/arch/ia64/sn/io/sn2/pciio.c @@ -28,16 +28,8 @@ #include #include #include -#include #include -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - #define DEBUG_PCIIO #undef DEBUG_PCIIO /* turn this on for yet more console output */ @@ -1313,61 +1305,6 @@ pciio_device_detach(vertex_hdl_t pconn, return(0); } -/* SN2 */ -/* - * Allocate (if necessary) and initialize a PCI window mapping structure. - */ -pciio_win_map_t -pciio_device_win_map_new(pciio_win_map_t win_map, - size_t region_size, - size_t page_size) -{ - ASSERT((page_size & (page_size - 1)) == 0); - ASSERT((region_size & (page_size - 1)) == 0); - - if (win_map == NULL) - NEW(win_map); - - /* - * The map array tracks the free ``pages'' in the region. The worst - * case scenario is when every other page in the region is free -- - * e.i. maximum fragmentation. This leads to (max pages + 1) / 2 + 1 - * map entries. The first "+1" handles the divide by 2 rounding; the - * second handles the need for an end marker sentinel. - */ - win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1); - win_map->wm_page_size = page_size; - ASSERT(win_map->wm_map != NULL); - - return win_map; -} - -/* - * Free resources associated with a PCI window mapping structure. - */ -extern void -pciio_device_win_map_free(pciio_win_map_t win_map) -{ - rmfreemap(win_map->wm_map); - bzero(win_map, sizeof *win_map); -} - -/* - * Populate window map with specified free range. - */ -void -pciio_device_win_populate(pciio_win_map_t win_map, - iopaddr_t ioaddr, - size_t size) -{ - ASSERT((size & (win_map->wm_page_size - 1)) == 0); - ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0); - - rmfree(win_map->wm_map, - size / win_map->wm_page_size, - (unsigned long)ioaddr / win_map->wm_page_size); - -} /* * Allocate space from the specified PCI window mapping resource. On * success record information about the allocation in the supplied window @@ -1385,94 +1322,36 @@ pciio_device_win_populate(pciio_win_map_t win_map, * and alignment. */ iopaddr_t -pciio_device_win_alloc(pciio_win_map_t win_map, +pciio_device_win_alloc(struct resource *root_resource, pciio_win_alloc_t win_alloc, size_t start, size_t size, size_t align) { - unsigned long base; - -#ifdef PIC_LATER - ASSERT((size & (size - 1)) == 0); - ASSERT((align & (align - 1)) == 0); - /* - * Convert size and alignment to pages. If size is greated than the - * requested alignment, we bump the alignment up to size; otherwise - * convert the size into a multiple of the alignment request. - */ - size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size; - align = align / win_map->wm_page_size; - if (size > align) - align = size; - else - size = (size + align - 1) & ~(align - 1); - - /* XXXX */ - base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP); - if (base == RMALLOC_FAIL) - return((iopaddr_t)NULL); -#else - int index_page, index_page_align; - int align_pages, size_pages; - int alloc_pages, free_pages; - int addr_align; - - /* Convert PCI bus alignment from bytes to pages */ - align_pages = align / win_map->wm_page_size; - - /* Convert PCI request from bytes to pages */ - size_pages = (size / win_map->wm_page_size) + - ((size % win_map->wm_page_size) ? 1 : 0); - - /* Align address with the larger of the size or the requested slot align */ - if (size_pages > align_pages) - align_pages = size_pages; - - /* - * Avoid wasting space by aligning - 1; this will prevent crossing - * another alignment boundary. - */ - alloc_pages = size_pages + (align_pages - 1); + struct resource *new_res; + int status = 0; - /* Allocate PCI bus space in pages */ - index_page = (int) rmalloc(win_map->wm_map, - (size_t) alloc_pages); + new_res = (struct resource *) kmalloc( sizeof(struct resource), KM_NOSLEEP); - /* Error if no PCI bus address space available */ - if (!index_page) - return 0; - - /* PCI bus address index starts at 0 */ - index_page--; - - /* Align the page offset as requested */ - index_page_align = (index_page + (align_pages - 1)) - - ((index_page + (align_pages - 1)) % align_pages); - - free_pages = (align_pages - 1) - (index_page_align - index_page); - - /* Free unused PCI bus pages adjusting the index to start at 1 */ - rmfree(win_map->wm_map, - free_pages, - (index_page_align + 1) + size_pages); - - /* Return aligned PCI bus space in bytes */ - addr_align = (index_page_align * win_map->wm_page_size); - base = index_page; - size = alloc_pages - free_pages; -#endif /* PIC_LATER */ + status = allocate_resource( root_resource, new_res, + size, align /* Min start addr. */, + root_resource->end, align, + NULL, NULL); + if (status) { + kfree(new_res); + return((iopaddr_t) NULL); + } /* * If a window allocation cookie has been supplied, use it to keep * track of all the allocated space assigned to this window. */ if (win_alloc) { - win_alloc->wa_map = win_map; - win_alloc->wa_base = base; + win_alloc->wa_resource = new_res; + win_alloc->wa_base = new_res->start; win_alloc->wa_pages = size; } - return base * win_map->wm_page_size; + return new_res->start;; } /* @@ -1482,10 +1361,16 @@ pciio_device_win_alloc(pciio_win_map_t win_map, void pciio_device_win_free(pciio_win_alloc_t win_alloc) { - if (win_alloc->wa_pages) - rmfree(win_alloc->wa_map->wm_map, - win_alloc->wa_pages, - win_alloc->wa_base); + + int status = 0; + + if (win_alloc->wa_resource) { + status = release_resource(win_alloc->wa_resource); + if (!status) + kfree(win_alloc->wa_resource); + else + BUG(); + } } /* diff --git a/arch/ia64/sn/io/sn2/shub.c b/arch/ia64/sn/io/sn2/shub.c index 9709c01cc27..f35230a4572 100644 --- a/arch/ia64/sn/io/sn2/shub.c +++ b/arch/ia64/sn/io/sn2/shub.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -485,10 +486,13 @@ sn_linkstats_get(char *page) static int __init linkstatd_init(void) { + if (!ia64_platform_is("sn2")) + return -ENODEV; + spin_lock_init(&sn_linkstats_lock); sn_linkstats = kmalloc(numnodes * sizeof(struct s_linkstats), GFP_KERNEL); sn_linkstats_reset(60000UL); /* default 60 second update interval */ - kernel_thread(linkstatd_thread, NULL, CLONE_FS | CLONE_FILES); + kernel_thread(linkstatd_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); return 0; } diff --git a/arch/ia64/sn/io/sn2/shuberror.c b/arch/ia64/sn/io/sn2/shuberror.c index 2469c553261..8f77e493eb9 100644 --- a/arch/ia64/sn/io/sn2/shuberror.c +++ b/arch/ia64/sn/io/sn2/shuberror.c @@ -155,7 +155,7 @@ hubii_eint_init(cnodeid_t cnode) rv = intr_connect_level(intr_cpu, SGI_II_ERROR, 0, NULL); request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); - irq_desc(bit)->status |= SN2_IRQ_PER_HUB; + irq_descp(bit)->status |= SN2_IRQ_PER_HUB; ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 8d58bfbc7bf..09cbbb65ab1 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -218,6 +219,8 @@ register_pcibr_intr(int irq, pcibr_intr_t intr) { if (pcibr_intr_list == NULL) { pcibr_intr_list = kmalloc(sizeof(struct pcibr_intr_list_t *) * NR_IRQS, GFP_KERNEL); + if (pcibr_intr_list == NULL) + pcibr_intr_list = vmalloc(sizeof(struct pcibr_intr_list_t *) * NR_IRQS); if (pcibr_intr_list == NULL) panic("Could not allocate memory for pcibr_intr_list\n"); memset( (void *)pcibr_intr_list, 0, sizeof(struct pcibr_intr_list_t *) * NR_IRQS); } diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 2238608d21c..8264a5e0902 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ DEFINE_PER_CPU(struct pda_s, pda_percpu); extern void bte_init_node (nodepda_t *, cnodeid_t); extern void bte_init_cpu (void); extern void sn_timer_init(void); +extern unsigned long last_time_offset; extern void (*ia64_mark_idle)(int); extern void snidle(int); @@ -145,7 +147,7 @@ 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) || defined(CONFIG_IA64_SGI_SN_SIM) +#if defined(CONFIG_IA64_EARLY_PRINTK_SGI_SN) || defined(CONFIG_IA64_SGI_SN_SIM) void __init early_sn_setup(void) @@ -187,7 +189,7 @@ 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 */ +#endif /* CONFIG_IA64_EARLY_PRINTK_SGI_SN */ #ifdef CONFIG_IA64_MCA extern int platform_intr_list[]; @@ -289,6 +291,12 @@ sn_setup(char **cmdline_p) } /* + * we set the default root device to /dev/hda + * to make simulation easy + */ + ROOT_DEV = Root_HDA1; + + /* * Create the PDAs and NODEPDAs for all the cpus. */ sn_init_pdas(cmdline_p); diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c index f860679d5b1..dafa74a914d 100644 --- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -312,6 +313,9 @@ prominfo_init(void) nasid_t nasid; char name[NODE_NAME_LEN]; + if (!ia64_platform_is("sn2")) + return 0; + TRACE(); DPRINTK("running on cpu %d\n", smp_processor_id()); diff --git a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S index d28370bd122..305d239a7de 100644 --- a/arch/ia64/vmlinux.lds.S +++ b/arch/ia64/vmlinux.lds.S @@ -5,7 +5,7 @@ #include #include -#define LOAD_OFFSET KERNEL_START + KERNEL_TR_PAGE_SIZE +#define LOAD_OFFSET (KERNEL_START - KERNEL_TR_PAGE_SIZE) #include OUTPUT_FORMAT("elf64-ia64-little") diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 75852545987..2c08a7d8b27 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -222,21 +222,17 @@ config UCDIMM Support for the Arcturus Networks uDsimm module. config DRAGEN2 - bool "Dragen Engine II board support" + bool "DragenEngine II board support" depends on M68VZ328 help - Support for the Dragen Engine II board. + Support for the DragenEngine II board. -config HWADDR_FROMEEPROM - bool " Read ETH address from EEPROM" - depends on DRAGEN2 +config DIRECT_IO_ACCESS + bool " Allow user to access IO directly" + depends on (UCSIMM || UCDIMM || DRAGEN2) help - Use MAC address from EEPROM. - -config HWADDR_OFFSET - int " Offset from start of EEPROM" - default "2" - depends on HWADDR_FROMEEPROM + Disable the CPU internal registers protection in user mode, + to allow a user application to read/write them. config INIT_LCD bool " Initialize LCD" @@ -246,7 +242,7 @@ config INIT_LCD config MEMORY_RESERVE int " Memory reservation (MiB)" - depends on (UCSIMM || UCDIMM || DRAGEN2) + depends on (UCSIMM || UCDIMM) help Reserve certain memory regions on 68x328 based boards. diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index 4b009076f9c..ed7676394f2 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -60,7 +60,7 @@ static inline void do_profile (unsigned long pc) * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick */ -static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) +static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) { /* last time the cmos clock got updated */ static long last_rtc_update=0; @@ -115,6 +115,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) #endif /* CONFIG_HEARTBEAT */ write_sequnlock(&xtime_lock); + return(IRQ_HANDLED); } void time_init(void) diff --git a/arch/m68knommu/platform/5282/config.c b/arch/m68knommu/platform/5282/config.c index 9548cf3a426..c3fc68c8af6 100644 --- a/arch/m68knommu/platform/5282/config.c +++ b/arch/m68knommu/platform/5282/config.c @@ -62,7 +62,7 @@ void config_BSP(char *commandp, int size) { mcf_disableall(); -#if defined(CONFIG_BOOTPARAM) +#ifdef CONFIG_BOOTPARAM strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); commandp[size-1] = 0; #else diff --git a/arch/m68knommu/platform/5282/pit.c b/arch/m68knommu/platform/5282/pit.c index ae03f5291cd..0ee25bf8db9 100644 --- a/arch/m68knommu/platform/5282/pit.c +++ b/arch/m68knommu/platform/5282/pit.c @@ -36,7 +36,7 @@ void coldfire_pit_tick(void) /***************************************************************************/ -void coldfire_pit_init(void (*handler)(int, void *, struct pt_regs *)) +void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) { volatile unsigned char *icrp; volatile unsigned long *imrp; diff --git a/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S index a87ee519a60..809b9ca2bdf 100644 --- a/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S +++ b/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S @@ -127,6 +127,7 @@ _start: movc %d0,%CACR +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -148,6 +149,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S index 070c0e8002d..1fff8b293b7 100644 --- a/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S +++ b/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S @@ -110,6 +110,8 @@ _start: movc %d0,%CACR nop + +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -131,6 +133,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5307/MP3/crt0_ram.S b/arch/m68knommu/platform/5307/MP3/crt0_ram.S index 822e1a49bac..d99883ac3bd 100644 --- a/arch/m68knommu/platform/5307/MP3/crt0_ram.S +++ b/arch/m68knommu/platform/5307/MP3/crt0_ram.S @@ -124,6 +124,8 @@ _start: movec %d0,%CACR nop + +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -145,6 +147,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5307/NETtel/crt0_ram.S b/arch/m68knommu/platform/5307/NETtel/crt0_ram.S index 70eaf4cf757..009a40506c0 100644 --- a/arch/m68knommu/platform/5307/NETtel/crt0_ram.S +++ b/arch/m68knommu/platform/5307/NETtel/crt0_ram.S @@ -147,6 +147,8 @@ _start: movec %d0,%CACR nop + +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -168,6 +170,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c index 7eab68bebbe..f3cbebab431 100644 --- a/arch/m68knommu/platform/5307/ints.c +++ b/arch/m68knommu/platform/5307/ints.c @@ -43,12 +43,13 @@ volatile unsigned int num_spurious; unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs) +static irqreturn_t default_irq_handler(int irq, void *ptr, struct pt_regs *regs) { #if 1 printk("%s(%d): default irq handler vec=%d [0x%x]\n", __FILE__, __LINE__, irq, irq); #endif + return(IRQ_HANDLED); } /* @@ -96,8 +97,12 @@ irq_node_t *new_irq_node(void) return NULL; } -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) +int request_irq( + unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long flags, + const char *devname, + void *dev_id) { if (irq < 0 || irq >= NR_IRQS) { printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, @@ -159,7 +164,7 @@ void free_irq(unsigned int irq, void *dev_id) int sys_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { if (irq > IRQ7) { diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c index 2d864431dd4..290fdd07b7b 100644 --- a/arch/m68knommu/platform/68328/ints.c +++ b/arch/m68knommu/platform/68328/ints.c @@ -81,6 +81,7 @@ unsigned int local_irq_count[NR_CPUS]; /* irq node variables for the 32 (potential) on chip sources */ static irq_node_t int_irq_list[NR_IRQS]; +#if !defined(CONFIG_DRAGEN2) asm (" .global _start, __ramend .section .romvec @@ -102,6 +103,7 @@ e_vectors: ignore: rte "); +#endif /* * This function should be called during kernel startup to initialize @@ -204,7 +206,7 @@ int show_interrupts(struct seq_file *p, void *v) seq_printf(p, " "); seq_printf(p, "%s\n", int_irq_list[i].devname); } - seq_printf(p, " : %10u spurious", num_spurious); + seq_printf(p, " : %10u spurious\n", num_spurious); return 0; } diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c index 6172044d034..70130387410 100644 --- a/arch/m68knommu/platform/68360/config.c +++ b/arch/m68knommu/platform/68360/config.c @@ -205,9 +205,4 @@ void config_BSP(char *command, int len) mach_hwclk = NULL; mach_set_clock_mmss = NULL; mach_reset = BSP_reset; - - //Kendrick's Change - mach_trap_init = M68360_init_IRQ; - - config_M68360_irq(); } diff --git a/arch/m68knommu/platform/68VZ328/de2/config.c b/arch/m68knommu/platform/68VZ328/de2/config.c index bbba58b90de..6673fe79aa1 100644 --- a/arch/m68knommu/platform/68VZ328/de2/config.c +++ b/arch/m68knommu/platform/68VZ328/de2/config.c @@ -36,7 +36,7 @@ #define TICKS_PER_JIFFY 41450 static void -dragen2_sched_init(void (*timer_routine) (int, void *, struct pt_regs *)) +dragen2_sched_init(irqreturn_t (*timer_routine) (int, void *, struct pt_regs *)) { /* disable timer 1 */ TCTL = 0; @@ -183,14 +183,20 @@ static void init_hardware(void) #endif } -void config_BSP(char *command, int len) +void config_BSP(char *command, int size) { printk("68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n"); - command[0] = '\0'; /* no specific boot option */ + +#if defined(CONFIG_BOOTPARAM) + strncpy(command, CONFIG_BOOTPARAM_STRING, size); + command[size-1] = 0; +#else + memset(command, 0, size); +#endif init_hardware(); - mach_sched_init = dragen2_sched_init; + mach_sched_init = (void *)dragen2_sched_init; mach_tick = dragen2_tick; mach_gettimeoffset = dragen2_gettimeoffset; mach_reset = dragen2_reset; diff --git a/arch/m68knommu/vmlinux.lds.S b/arch/m68knommu/vmlinux.lds.S index fa2004ada4b..1ab8a31ef96 100644 --- a/arch/m68knommu/vmlinux.lds.S +++ b/arch/m68knommu/vmlinux.lds.S @@ -277,7 +277,9 @@ SECTIONS { __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; - SECURITY_INIT + __security_initcall_start = .; + *(.security_initcall.init) + __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 714e358bb85..3b1074386cf 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -39,7 +39,6 @@ #include extern void startup_match20_interrupt(void); -extern void do_softirq(void); extern volatile unsigned long wall_jiffies; unsigned long missed_heart_beats = 0; @@ -76,7 +75,7 @@ void mips_timer_interrupt(struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; #ifdef CONFIG_PM printk(KERN_ERR "Unexpected CP0 interrupt\n"); @@ -92,7 +91,7 @@ void mips_timer_interrupt(struct pt_regs *regs) timerhi += (count < timerlo); /* Wrap around */ timerlo = count; - kstat_cpu(0).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; do_timer(regs); r4k_cur += r4k_offset; ack_r4ktimer(r4k_cur); @@ -102,8 +101,6 @@ void mips_timer_interrupt(struct pt_regs *regs) irq_exit(); - if (softirq_pending(cpu)) - do_softirq(); return; null: @@ -117,7 +114,7 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) int time_elapsed; static int jiffie_drift = 0; - kstat_cpu(0).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { /* should never happen! */ printk(KERN_WARNING "counter 0 w status eror\n"); diff --git a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c index 2580fa94787..124459426a2 100644 --- a/arch/mips/baget/irq.c +++ b/arch/mips/baget/irq.c @@ -153,7 +153,7 @@ int get_irq_list(char *buf) if (!action) gotos skip; len += sprintf(buf+len, "%2d: %8d %c %s", - i, kstat_cpu(0).irqs[i], + i, kstat_this_cpu.irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -183,7 +183,7 @@ static void do_IRQ(int irq, struct pt_regs * regs) cpu = smp_processor_id(); irq_enter(); - kstat_cpus(cpu)[irq]++; + kstat_cpus(cpu).irqs[irq]++; mask_irq(irq); action = *(irq + irq_action); diff --git a/arch/mips/defconfig-lasat200 b/arch/mips/defconfig-lasat200 index f627176a7b8..36497365d10 100644 --- a/arch/mips/defconfig-lasat200 +++ b/arch/mips/defconfig-lasat200 @@ -45,7 +45,7 @@ CONFIG_KMOD=y # CONFIG_MIPS_IVR is not set CONFIG_LASAT=y # CONFIG_LASAT_100 is not set -CONFIG_LASAT_200=y +# CONFIG_LASAT_200 is not set CONFIG_PICVUE=y CONFIG_PICVUE_PROC=y CONFIG_DS1603=y diff --git a/arch/mips/galileo-boards/ev96100/time.c b/arch/mips/galileo-boards/ev96100/time.c index 827b70a399c..2ed5b2755a8 100644 --- a/arch/mips/galileo-boards/ev96100/time.c +++ b/arch/mips/galileo-boards/ev96100/time.c @@ -262,7 +262,7 @@ void mips_timer_interrupt(struct pt_regs *regs) } do { - kstat_cpu(0).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; do_timer(regs); r4k_cur += r4k_offset; ack_r4ktimer(r4k_cur); diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 45fef230974..34d0f692a91 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -350,7 +350,7 @@ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) unsigned int status; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff --git a/arch/mips/kernel/offset.c b/arch/mips/kernel/offset.c index fca62677596..4635a7e322b 100644 --- a/arch/mips/kernel/offset.c +++ b/arch/mips/kernel/offset.c @@ -200,8 +200,6 @@ void output_irq_cpustat_t_defines(void) { text("/* Linux irq_cpustat_t offsets. */"); offset("#define IC_SOFTIRQ_PENDING ", irq_cpustat_t, __softirq_pending); - offset("#define IC_SYSCALL_COUNT ", irq_cpustat_t, __syscall_count); - offset("#define IC_KSOFTIRQD_TASK ", irq_cpustat_t, __ksoftirqd_task); size("#define IC_IRQ_CPUSTAT_T ", irq_cpustat_t); linefeed; } diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h index 4034364bc3a..cf9fd7d5527 100644 --- a/arch/mips/kernel/syscalls.h +++ b/arch/mips/kernel/syscalls.h @@ -280,3 +280,4 @@ SYS(sys_clock_settime, 2) SYS(sys_clock_gettime, 2) SYS(sys_clock_getres, 2) SYS(sys_clock_nanosleep, 4) /* 4265 */ +SYS(sys_tgkill, 3) diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 5722c28c1e9..fdcc9d5bd05 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -527,8 +528,6 @@ asmlinkage int irix_gtime(struct pt_regs *regs) return get_seconds(); } -int vm_enough_memory(long pages); - /* * IRIX is completely broken... it returns 0 on success, otherwise * ENOMEM. @@ -585,7 +584,7 @@ asmlinkage int irix_brk(unsigned long brk) /* * Check if we have enough memory.. */ - if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) { + if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) { ret = -ENOMEM; goto out; } diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 36c91fdcda3..5b0aa50ea96 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -434,15 +434,12 @@ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ timer_interrupt(irq, NULL, regs); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) @@ -450,15 +447,12 @@ asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ local_timer_interrupt(irq, NULL, regs); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } /* diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 6a0951553dc..ac749271ce4 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c @@ -149,7 +149,7 @@ void lasat_hw0_irqdispatch(struct pt_regs *regs) } irq_enter(); - kstat_cpu(0).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; action->handler(irq, action->dev_id, regs); irq_exit(); diff --git a/arch/mips/mips-boards/sead/sead_time.c b/arch/mips/mips-boards/sead/sead_time.c index 239506b2211..8d1e2fc3388 100644 --- a/arch/mips/mips-boards/sead/sead_time.c +++ b/arch/mips/mips-boards/sead/sead_time.c @@ -68,7 +68,7 @@ void mips_timer_interrupt(struct pt_regs *regs) irq_enter(); do { - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; do_timer(regs); if ((timer_tick_count++ % HZ) == 0) { @@ -84,8 +84,6 @@ void mips_timer_interrupt(struct pt_regs *regs) - r4k_cur) < 0x7fffffff); irq_exit(); - if (softirq_pending(cpu)) - do_softirq(); } /* diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 46c2d1d2eab..7955e2d4b4d 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -268,7 +268,7 @@ void indy_buserror_irq(struct pt_regs *regs) int irq = SGI_BUSERR_IRQ; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; ip22_be_interrupt(irq, regs); irq_exit(); } diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 74d369ba837..ba592902f6d 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -176,7 +176,7 @@ void indy_8254timer_irq(struct pt_regs *regs) char c; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; printk(KERN_ALERT "Oops, got 8254 interrupt.\n"); ArcRead(0, &c, 1, &cnt); ArcEnterInteractiveMode(); @@ -189,12 +189,9 @@ void indy_r4k_timer_interrupt(struct pt_regs *regs) int irq = SGI_TIMER_IRQ; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; timer_interrupt(irq, NULL, regs); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } extern int setup_irq(unsigned int irq, struct irqaction *irqaction); diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 33dbe59cdc7..dd856c97931 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -107,7 +107,7 @@ again: if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; - kstat_cpu(cpu).irqs[irq]++; /* kstat only for bootcpu? */ + kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(regs); @@ -135,9 +135,6 @@ again: write_sequnlock(&xtime_lock); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } unsigned long ip27_do_gettimeoffset(void) diff --git a/arch/mips/sgi-ip32/ip32-timer.c b/arch/mips/sgi-ip32/ip32-timer.c index d37207a912b..62b06b0fd00 100644 --- a/arch/mips/sgi-ip32/ip32-timer.c +++ b/arch/mips/sgi-ip32/ip32-timer.c @@ -96,7 +96,7 @@ static irqreturn_t cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * re timerlo = count; write_c0_compare((u32) (count + cc_interval)); - kstat_cpu(0).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; do_timer(regs); if (!jiffies) { diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index c0be34ef38a..58aa364d6f4 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -430,7 +430,7 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs) * host to stop the break, since we would see another * interrupt on the end-of-break too) */ - kstat_cpu(smp_processor_id()).irqs[K_INT_UART_1]++; + kstat_this_cpu.irqs[K_INT_UART_1]++; mdelay(500); duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT | M_DUART_RX_EN | M_DUART_TX_EN); diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c index aa121a99330..056b0f7519d 100644 --- a/arch/mips/sibyte/sb1250/smp.c +++ b/arch/mips/sibyte/sb1250/smp.c @@ -76,7 +76,7 @@ void sb1250_mailbox_interrupt(struct pt_regs *regs) int cpu = smp_processor_id(); unsigned int action; - kstat_cpu(cpu).irqs[K_INT_MBOX_0]++; + kstat_this_cpu.irqs[K_INT_MBOX_0]++; /* Load the mailbox register to figure out what we're supposed to do */ action = (__raw_readq(mailbox_regs[cpu]) >> 48) & 0xffff; diff --git a/arch/mips64/kernel/irq.c b/arch/mips64/kernel/irq.c index 45fef230974..34d0f692a91 100644 --- a/arch/mips64/kernel/irq.c +++ b/arch/mips64/kernel/irq.c @@ -350,7 +350,7 @@ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs) unsigned int status; irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff --git a/arch/mips64/kernel/offset.c b/arch/mips64/kernel/offset.c index fca62677596..4635a7e322b 100644 --- a/arch/mips64/kernel/offset.c +++ b/arch/mips64/kernel/offset.c @@ -200,8 +200,6 @@ void output_irq_cpustat_t_defines(void) { text("/* Linux irq_cpustat_t offsets. */"); offset("#define IC_SOFTIRQ_PENDING ", irq_cpustat_t, __softirq_pending); - offset("#define IC_SYSCALL_COUNT ", irq_cpustat_t, __syscall_count); - offset("#define IC_KSOFTIRQD_TASK ", irq_cpustat_t, __ksoftirqd_task); size("#define IC_IRQ_CPUSTAT_T ", irq_cpustat_t); linefeed; } diff --git a/arch/mips64/kernel/scall_64.S b/arch/mips64/kernel/scall_64.S index e1a8ad2bba2..27ef5fb4196 100644 --- a/arch/mips64/kernel/scall_64.S +++ b/arch/mips64/kernel/scall_64.S @@ -368,12 +368,13 @@ sys_call_table: PTR sys_restart_syscall PTR sys_semtimedop PTR sys_fadvise64 /* 5215 */ - sys sys_timer_create - sys sys_timer_settime - sys sys_timer_gettime - sys sys_timer_getoverrun - sys sys_timer_delete /* 5220 */ - sys sys_clock_settime - sys sys_clock_gettime - sys sys_clock_getres - sys sys_clock_nanosleep + PTR sys_timer_create + PTR sys_timer_settime + PTR sys_timer_gettime + PTR sys_timer_getoverrun + PTR sys_timer_delete /* 5220 */ + PTR sys_clock_settime + PTR sys_clock_gettime + PTR sys_clock_getres + PTR sys_clock_nanosleep + PTR sys_tgkill /* 5225 */ diff --git a/arch/mips64/kernel/scall_n32.S b/arch/mips64/kernel/scall_n32.S index e28746d3eb3..47092c0521d 100644 --- a/arch/mips64/kernel/scall_n32.S +++ b/arch/mips64/kernel/scall_n32.S @@ -333,12 +333,13 @@ EXPORT(sysn32_call_table) PTR sys_statfs64 PTR sys_fstatfs64 PTR sys_sendfile64 - sys sys_timer_create /* 6220 */ - sys sys_timer_settime - sys sys_timer_gettime - sys sys_timer_getoverrun - sys sys_timer_delete - sys sys_clock_settime /* 6225 */ - sys sys_clock_gettime - sys sys_clock_getres - sys sys_clock_nanosleep + PTR sys_timer_create /* 6220 */ + PTR sys_timer_settime + PTR sys_timer_gettime + PTR sys_timer_getoverrun + PTR sys_timer_delete + PTR sys_clock_settime /* 6225 */ + PTR sys_clock_gettime + PTR sys_clock_getres + PTR sys_clock_nanosleep + PTR sys_tgkill diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S index e2b78e8e0a5..beb28bb9dc6 100644 --- a/arch/mips64/kernel/scall_o32.S +++ b/arch/mips64/kernel/scall_o32.S @@ -569,6 +569,7 @@ out: jr ra sys sys_clock_gettime 2 sys sys_clock_getres 2 sys sys_clock_nanosleep 4 /* 4265 */ + sys sys_tgkill 3 .endm diff --git a/arch/mips64/kernel/time.c b/arch/mips64/kernel/time.c index 36c91fdcda3..5b0aa50ea96 100644 --- a/arch/mips64/kernel/time.c +++ b/arch/mips64/kernel/time.c @@ -434,15 +434,12 @@ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ timer_interrupt(irq, NULL, regs); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) @@ -450,15 +447,12 @@ asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ local_timer_interrupt(irq, NULL, regs); irq_exit(); - - if (softirq_pending(cpu)) - do_softirq(); } /* diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index edf4e669ecf..ce1094414de 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -456,7 +456,7 @@ smp_cpu_init(int cpunum) current->active_mm = &init_mm; if(current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, cpunum); + enter_lazy_tlb(&init_mm, current); init_IRQ(); /* make sure no IRQ's are enabled or pending */ } diff --git a/arch/parisc/oprofile/init.c b/arch/parisc/oprofile/init.c index 21ad9bec43c..a97b6ba482d 100644 --- a/arch/parisc/oprofile/init.c +++ b/arch/parisc/oprofile/init.c @@ -20,6 +20,6 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) } -void __exit oprofile_arch_exit() +void oprofile_arch_exit() { } diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 9ade9f30eab..66f1c0c6cb1 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -450,9 +450,6 @@ config EV64260 config SPRUCE bool "IBM-Spruce" -config MENF1 - bool "MEN-F1" - config LOPEC bool "Motorola-LoPEC" @@ -473,6 +470,10 @@ config PRPMC800 config SANDPOINT bool "Motorola-Sandpoint" + help + Select SANDPOINT if configuring for a Motorola Sandpoint X3 + or X3(b). + X3 (any flavor). config ADIR bool "SBS-Adirondack" @@ -490,9 +491,6 @@ config GEMINI series Single Board Computer. More information is available at: . -config ZX4500 - bool "Zynx-ZX4500" - endchoice config PPC_CHRP @@ -500,6 +498,11 @@ config PPC_CHRP depends on PPC_MULTIPLATFORM default y +config PPC_GEN550 + bool + depends on SANDPOINT + default y + config PPC_PMAC bool depends on PPC_MULTIPLATFORM @@ -515,10 +518,6 @@ config PPC_OF depends on PPC_PMAC || PPC_CHRP default y -config SANDPOINT_X3 - bool "Sandpoint X3" - depends on SANDPOINT - config FORCE bool depends on 6xx && !8260 && (PCORE || POWERPMC250) @@ -526,7 +525,7 @@ config FORCE config EPIC_SERIAL_MODE bool - depends on 6xx && !8260 && (LOPEC || SANDPOINT_X3) + depends on 6xx && !8260 && (LOPEC || SANDPOINT) default y config WILLOW @@ -536,7 +535,7 @@ config WILLOW config MPC10X_STORE_GATHERING bool "Enable MPC10x store gathering" - depends on FORCE || MENF1 || SANDPOINT || ZX4500 + depends on FORCE || SANDPOINT config GT64260 bool @@ -1528,7 +1527,7 @@ config BOOTX_TEXT config SERIAL_TEXT_DEBUG bool "Support for early boot texts over serial port" - depends on 4xx || GT64260 || LOPEC || MCPN765 || PPLUS || PRPMC800 || SANDPOINT || ZX4500 + depends on 4xx || GT64260 || LOPEC || MCPN765 || PPLUS || PRPMC800 || SANDPOINT config OCP bool diff --git a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile index aefa82fcd7b..6435b3722a1 100644 --- a/arch/ppc/boot/common/Makefile +++ b/arch/ppc/boot/common/Makefile @@ -8,7 +8,8 @@ # Tom Rini January 2001 # -lib-y := string.o util.o misc-common.o +lib-y := string.o util.o misc-common.o \ + serial_stub.o lib-$(CONFIG_PPC_PREP) += mpc10x_memory.o lib-$(CONFIG_LOPEC) += mpc10x_memory.o lib-$(CONFIG_PAL4) += cpc700_memory.o diff --git a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c index 21cbfba8904..8c8db8d382d 100644 --- a/arch/ppc/boot/common/ns16550.c +++ b/arch/ppc/boot/common/ns16550.c @@ -95,8 +95,3 @@ serial_tstc(unsigned long com_port) { return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0); } - -void -serial_close(unsigned long com_port) -{ -} diff --git a/arch/ppc/boot/common/serial_stub.c b/arch/ppc/boot/common/serial_stub.c new file mode 100644 index 00000000000..2dc176ed058 --- /dev/null +++ b/arch/ppc/boot/common/serial_stub.c @@ -0,0 +1,28 @@ +/* + * arch/ppc/boot/common/serial_stub.c + * + * This is a few stub routines to make the boot code cleaner looking when + * there is no serial port support doesn't need to be closed, for example. + * + * Author: Tom Rini + * + * 2003 (c) MontaVista, Software, Inc. This file is licensed under the terms + * of the GNU General Public License version 2. This program is licensed "as + * is" without any warranty of any kind, whether express or implied. + */ + +void __attribute__ ((weak)) +serial_fixups(void) +{ +} + +unsigned long __attribute__ ((weak)) +serial_init(int chan, void *ignored) +{ + return 0; +} + +void __attribute__ ((weak)) +serial_close(unsigned long com_port) +{ +} diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index 94217ae4584..3c45f8bda05 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -47,28 +47,20 @@ endif ifeq ($(CONFIG_EBONY),y) ZIMAGE := zImage-TREE ZIMAGEINITRD := zImage.initrd-TREE -EXTRA := direct.o END := ebony ENTRYPOINT := 0x01000000 TFTPIMAGE := /tftpboot/zImage.$(END) endif ifeq ($(CONFIG_EV64260),y) -EXTRA := direct.o misc-ev64260.o +EXTRA := misc-ev64260.o TFTPIMAGE := /tftpboot/zImage.ev64260 endif ifeq ($(CONFIG_GEMINI),y) ZIMAGE := zImage-STRIPELF ZIMAGEINITRD := zImage.initrd-STRIPELF -EXTRA := direct.o END := gemini TFTPIMAGE := /tftpboot/zImage.$(END) endif -ifeq ($(CONFIG_MENF1),y) -ZIMAGE := zImage-MENF1 -ZIMAGEINITRD := zImage.initrd-MENF1 -EXTRA := chrpmap.o -TFTPIMAGE := /tftpboot/zImage.menf1 -endif ifeq ($(CONFIG_K2),y) EXTRA := legacy.o TFTPIMAGE := /tftpboot/zImage.k2 @@ -78,7 +70,6 @@ endif ifeq ($(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750)$(CONFIG_PRPMC800)$(CONFIG_LOPEC)$(CONFIG_PPLUS),y) ZIMAGE := zImage-PPLUS ZIMAGEINITRD := zImage.initrd-PPLUS -EXTRA := direct.o TFTPIMAGE := /tftpboot/zImage.pplus ZNETBOOT := zImage.pplus ZNETBOOTRD := zImage.initrd.pplus @@ -86,9 +77,6 @@ endif ifeq ($(CONFIG_PPLUS),y) EXTRA := legacy.o endif -ifeq ($(CONFIG_PAL4),y) -EXTRA := direct.o -endif ifeq ($(CONFIG_PCORE)$(CONFIG_POWERPMC250),y) ZIMAGE := zImage-STRIPELF ZIMAGEINITRD := zImage.initrd-STRIPELF @@ -96,30 +84,17 @@ EXTRA := chrpmap.o END := pcore TFTPIMAGE := /tftpboot/zImage.$(END) endif -# The PowerPMC 250 needs the dummy serial_fixups() -ifeq ($(CONFIG_POWERPMC250),y) -EXTRA := direct.o -endif ifeq ($(CONFIG_SANDPOINT),y) -EXTRA := direct.o TFTPIMAGE := /tftpboot/zImage.sandpoint endif ifeq ($(CONFIG_SPRUCE),y) ZIMAGE := zImage-TREE ZIMAGEINITRD := zImage.initrd-TREE -EXTRA := direct.o END := spruce ENTRYPOINT := 0x00800000 MISC := misc-spruce.o TFTPIMAGE := /tftpboot/zImage.$(END) endif -ifeq ($(CONFIG_ZX4500),y) -ZIMAGE := zImage-STRIPELF -ZIMAGEINITRD := zImage.initrd-STRIPELF -EXTRA := direct.o -END := zx4500 -TFTPIMAGE := /tftpboot/zImage.$(END) -endif ifeq ($(CONFIG_SMP),y) TFTPIMAGE += .smp endif @@ -221,12 +196,6 @@ $(images)/zImage.initrd-TREE: $(obj)/zvmlinux.initrd $(MKTREE) $(MKTREE) $(obj)/zvmlinux.initrd $(images)/zImage.initrd.$(END) \ $(ENTRYPOINT) -$(images)/zImage-MENF1: $(obj)/zvmlinux $(MKPREP) - $(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.menf1 - -$(images)/zImage.initrd-MENF1: $(obj)/zvmlinux.initrd $(MKPREP) - $(MKPREP) -pbp $(obj)/zvmlinux.initrd $(images)/zImage.initrd.menf1 - $(images)/zImage-PPLUS: $(obj)/zvmlinux $(MKPREP) $(MKBUGBOOT) $(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.pplus $(MKBUGBOOT) $(obj)/zvmlinux $(images)/zImage.bugboot diff --git a/arch/ppc/boot/simple/direct.S b/arch/ppc/boot/simple/direct.S deleted file mode 100644 index b5ced833e37..00000000000 --- a/arch/ppc/boot/simple/direct.S +++ /dev/null @@ -1,15 +0,0 @@ -/* - * arch/ppc/boot/simple/direct.S - * - * Author: Tom Rini - * - * This is an empty function for machines which use SERIAL_IO_MEM - * and don't need ISA_io set to anything but 0, or perform any other - * serial fixups. - */ - - .text - - .globl serial_fixups -serial_fixups: - blr diff --git a/arch/ppc/boot/simple/m8260_tty.c b/arch/ppc/boot/simple/m8260_tty.c index 120df32fe9c..9d1d54a5e8f 100644 --- a/arch/ppc/boot/simple/m8260_tty.c +++ b/arch/ppc/boot/simple/m8260_tty.c @@ -311,8 +311,3 @@ serial_tstc(void *ignored) return(!(rbdf->cbd_sc & BD_SC_EMPTY)); } - -void -serial_close(unsigned long com_port) -{ -} diff --git a/arch/ppc/boot/simple/m8xx_tty.c b/arch/ppc/boot/simple/m8xx_tty.c index 93b59a3bc1c..1d2778e248c 100644 --- a/arch/ppc/boot/simple/m8xx_tty.c +++ b/arch/ppc/boot/simple/m8xx_tty.c @@ -288,8 +288,3 @@ serial_tstc(void *ignored) return(!(rbdf->cbd_sc & BD_SC_EMPTY)); } - -void -serial_close(unsigned long com_port) -{ -} diff --git a/arch/ppc/configs/adir_defconfig b/arch/ppc/configs/adir_defconfig index aef58609eb8..90ddd552a9d 100644 --- a/arch/ppc/configs/adir_defconfig +++ b/arch/ppc/configs/adir_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_ADIR=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_ALTIVEC is not set diff --git a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig index 2ccbd93d1e8..71836487085 100644 --- a/arch/ppc/configs/apus_defconfig +++ b/arch/ppc/configs/apus_defconfig @@ -56,7 +56,6 @@ CONFIG_APUS=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -68,7 +67,6 @@ CONFIG_APUS=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_ALTIVEC is not set diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig index 5e50731b4db..23d13c9aa6e 100644 --- a/arch/ppc/configs/common_defconfig +++ b/arch/ppc/configs/common_defconfig @@ -56,7 +56,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -68,7 +67,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y CONFIG_PPC_PREP=y diff --git a/arch/ppc/configs/ev64260_defconfig b/arch/ppc/configs/ev64260_defconfig index d6204290b3a..c5bfc64d783 100644 --- a/arch/ppc/configs/ev64260_defconfig +++ b/arch/ppc/configs/ev64260_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set CONFIG_EV64260=y # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_EV64260=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_GT64260=y CONFIG_SERIAL_CONSOLE_BAUD=115200 # CONFIG_SMP is not set diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig index 98d499db74c..324f8a7ae15 100644 --- a/arch/ppc/configs/gemini_defconfig +++ b/arch/ppc/configs/gemini_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set CONFIG_GEMINI=y -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set CONFIG_ALTIVEC=y diff --git a/arch/ppc/configs/ibmchrp_defconfig b/arch/ppc/configs/ibmchrp_defconfig index 66017e5bbfe..ef4bd5c260d 100644 --- a/arch/ppc/configs/ibmchrp_defconfig +++ b/arch/ppc/configs/ibmchrp_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y CONFIG_PPC_PREP=y diff --git a/arch/ppc/configs/k2_defconfig b/arch/ppc/configs/k2_defconfig index c345891ae74..a7bca0e729e 100644 --- a/arch/ppc/configs/k2_defconfig +++ b/arch/ppc/configs/k2_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PPC_STD_MMU=y CONFIG_K2=y # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_CPC710_DATA_GATHERING is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set diff --git a/arch/ppc/configs/lopec_defconfig b/arch/ppc/configs/lopec_defconfig index 70962e27db3..f4d189fc3fe 100644 --- a/arch/ppc/configs/lopec_defconfig +++ b/arch/ppc/configs/lopec_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set CONFIG_LOPEC=y # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_LOPEC=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_EPIC_SERIAL_MODE=y # CONFIG_SMP is not set # CONFIG_PREEMPT is not set diff --git a/arch/ppc/configs/mcpn765_defconfig b/arch/ppc/configs/mcpn765_defconfig index 851a94f7ed5..23b969014ad 100644 --- a/arch/ppc/configs/mcpn765_defconfig +++ b/arch/ppc/configs/mcpn765_defconfig @@ -50,7 +50,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set CONFIG_MCPN765=y # CONFIG_MVME5100 is not set @@ -62,7 +61,6 @@ CONFIG_MCPN765=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set CONFIG_ALTIVEC=y diff --git a/arch/ppc/configs/menf1_defconfig b/arch/ppc/configs/menf1_defconfig index b9d61c21ff3..64eece52ad3 100644 --- a/arch/ppc/configs/menf1_defconfig +++ b/arch/ppc/configs/menf1_defconfig @@ -67,7 +67,6 @@ CONFIG_MENF1=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_MPC10X_STORE_GATHERING=y # CONFIG_SMP is not set # CONFIG_PREEMPT is not set diff --git a/arch/ppc/configs/mvme5100_defconfig b/arch/ppc/configs/mvme5100_defconfig index 69e9c155f48..67a31c66cea 100644 --- a/arch/ppc/configs/mvme5100_defconfig +++ b/arch/ppc/configs/mvme5100_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set CONFIG_MVME5100=y @@ -67,7 +66,6 @@ CONFIG_MVME5100=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_MVME5100_IPMC761_PRESENT is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set diff --git a/arch/ppc/configs/pcore_defconfig b/arch/ppc/configs/pcore_defconfig index b5568f2c374..13db3dcada7 100644 --- a/arch/ppc/configs/pcore_defconfig +++ b/arch/ppc/configs/pcore_defconfig @@ -55,7 +55,6 @@ CONFIG_PCORE=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PCORE=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_FORCE=y # CONFIG_MPC10X_STORE_GATHERING is not set # CONFIG_SMP is not set diff --git a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig index 411322433e7..86cddf4e9b5 100644 --- a/arch/ppc/configs/pmac_defconfig +++ b/arch/ppc/configs/pmac_defconfig @@ -57,7 +57,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -69,7 +68,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y CONFIG_PPC_PREP=y diff --git a/arch/ppc/configs/power3_defconfig b/arch/ppc/configs/power3_defconfig index a986e394dbf..360f281bd1e 100644 --- a/arch/ppc/configs/power3_defconfig +++ b/arch/ppc/configs/power3_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y CONFIG_PPC_PREP=y diff --git a/arch/ppc/configs/pplus_defconfig b/arch/ppc/configs/pplus_defconfig index 8dfa789c993..ff29c2bae2b 100644 --- a/arch/ppc/configs/pplus_defconfig +++ b/arch/ppc/configs/pplus_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PPLUS=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_ALTIVEC is not set diff --git a/arch/ppc/configs/prpmc750_defconfig b/arch/ppc/configs/prpmc750_defconfig index 24c99367511..6500b795e2b 100644 --- a/arch/ppc/configs/prpmc750_defconfig +++ b/arch/ppc/configs/prpmc750_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PRPMC750=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_ALTIVEC is not set diff --git a/arch/ppc/configs/prpmc800_defconfig b/arch/ppc/configs/prpmc800_defconfig index ee07a3c5ebb..7aa5e0cf3ac 100644 --- a/arch/ppc/configs/prpmc800_defconfig +++ b/arch/ppc/configs/prpmc800_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_PRPMC800=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_ALTIVEC is not set diff --git a/arch/ppc/configs/sandpoint_defconfig b/arch/ppc/configs/sandpoint_defconfig index a7b1f4bbbf0..74cf67dfe48 100644 --- a/arch/ppc/configs/sandpoint_defconfig +++ b/arch/ppc/configs/sandpoint_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,8 +66,7 @@ CONFIG_SANDPOINT=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set -CONFIG_SANDPOINT_X3=y +CONFIG_PPC_GEN550=y CONFIG_EPIC_SERIAL_MODE=y # CONFIG_MPC10X_STORE_GATHERING is not set # CONFIG_SMP is not set @@ -84,8 +82,8 @@ CONFIG_ALTIVEC=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_KCORE_ELF=y -CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y +CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_PCI_LEGACY_PROC is not set # CONFIG_PCI_NAMES is not set @@ -118,6 +116,11 @@ CONFIG_TASK_SIZE=0x80000000 CONFIG_BOOT_LOAD=0x00800000 # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Memory Technology Devices (MTD) # # CONFIG_MTD is not set @@ -147,7 +150,7 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_MD is not set # -# ATA/IDE/MFM/RLL support +# ATA/ATAPI/MFM/RLL support # CONFIG_IDE=y @@ -166,6 +169,7 @@ CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_TASKFILE_IO=y # # IDE chipset support/bugfixes @@ -173,7 +177,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDEPCI is not set # -# SCSI support +# SCSI device support # # CONFIG_SCSI is not set @@ -292,6 +296,7 @@ CONFIG_NET_PCI=y # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set +# CONFIG_TC35815 is not set # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set CONFIG_E100=y @@ -413,11 +418,6 @@ CONFIG_FONT_8x16=y # CONFIG_LOGO is not set # -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# # Input device support # CONFIG_INPUT=y @@ -443,6 +443,7 @@ CONFIG_SERIO=y CONFIG_SERIO_I8042=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set # # Input Device Drivers @@ -731,6 +732,7 @@ CONFIG_USB_SE401=m # # USB Network adaptors # +# CONFIG_USB_AX8817X is not set # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_PEGASUS is not set diff --git a/arch/ppc/configs/spruce_defconfig b/arch/ppc/configs/spruce_defconfig index 4a5a09f9506..7b0c4e56030 100644 --- a/arch/ppc/configs/spruce_defconfig +++ b/arch/ppc/configs/spruce_defconfig @@ -55,7 +55,6 @@ CONFIG_PPC_STD_MMU=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set CONFIG_SPRUCE=y -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -67,7 +66,6 @@ CONFIG_SPRUCE=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set # CONFIG_SPRUCE_BAUD_33M is not set # CONFIG_SMP is not set # CONFIG_PREEMPT is not set diff --git a/arch/ppc/configs/zx4500_defconfig b/arch/ppc/configs/zx4500_defconfig deleted file mode 100644 index 8b1bf65a1a5..00000000000 --- a/arch/ppc/configs/zx4500_defconfig +++ /dev/null @@ -1,560 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_MMU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_HAVE_DEC_LOCK=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General setup -# -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=14 -CONFIG_EMBEDDED=y -CONFIG_FUTEX=y -# CONFIG_EPOLL is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y - -# -# Platform support -# -CONFIG_PPC=y -CONFIG_PPC32=y -CONFIG_6xx=y -# CONFIG_40x is not set -# CONFIG_POWER3 is not set -# CONFIG_8xx is not set - -# -# IBM 4xx options -# -# CONFIG_8260 is not set -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PPC_STD_MMU=y -# CONFIG_PPC_MULTIPLATFORM is not set -# CONFIG_APUS is not set -# CONFIG_WILLOW_2 is not set -# CONFIG_PCORE is not set -# CONFIG_POWERPMC250 is not set -# CONFIG_EV64260 is not set -# CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set -# CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set -# CONFIG_MVME5100 is not set -# CONFIG_PPLUS is not set -# CONFIG_PRPMC750 is not set -# CONFIG_PRPMC800 is not set -# CONFIG_SANDPOINT is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set -# CONFIG_PAL4 is not set -# CONFIG_GEMINI is not set -CONFIG_ZX4500=y -# CONFIG_MPC10X_STORE_GATHERING is not set -# CONFIG_SMP is not set -# CONFIG_PREEMPT is not set -# CONFIG_ALTIVEC is not set -# CONFIG_TAU is not set -# CONFIG_CPU_FREQ is not set - -# -# General setup -# -# CONFIG_HIGHMEM is not set -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_KCORE_ELF=y -CONFIG_BINFMT_ELF=y -CONFIG_KERNEL_ELF=y -CONFIG_BINFMT_MISC=y -# CONFIG_PCI_LEGACY_PROC is not set -CONFIG_PCI_NAMES=y -# CONFIG_HOTPLUG is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set -CONFIG_PPC601_SYNC_FIX=y -# CONFIG_CMDLINE_BOOL is not set - -# -# Advanced setup -# -# CONFIG_ADVANCED_OPTIONS is not set - -# -# Default settings for advanced configuration options are used -# -CONFIG_HIGHMEM_START=0xfe000000 -CONFIG_LOWMEM_SIZE=0x30000000 -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE=0x80000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_BLK_DEV_INITRD=y - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# ATA/IDE/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# -# Fusion MPT device support -# - -# -# IEEE 1394 (FireWire) support (EXPERIMENTAL) -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -# CONFIG_IP_PNP_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_IPV6 is not set -# CONFIG_XFRM_USER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -CONFIG_IPV6_SCTP__=y -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_LLC is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_FASTROUTE is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -# CONFIG_MII is not set -# CONFIG_OAKNET is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_HP100 is not set -CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_B44 is not set -# CONFIG_DGRS is not set -CONFIG_EEPRO100=y -# CONFIG_EEPRO100_PIO is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_IXGB is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices (depends on LLC=y) -# -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN_BOOL is not set - -# -# Graphics support -# -# CONFIG_FB is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Input device support -# -# CONFIG_INPUT is not set - -# -# Userland interfaces -# - -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -# CONFIG_SERIO is not set - -# -# Input Device Drivers -# - -# -# Macintosh device drivers -# - -# -# Character devices -# -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Hardware Sensors Mainboard support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_QIC02_TAPE is not set - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set -# CONFIG_HANGCHECK_TIMER is not set - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -# CONFIG_FAT_FS is not set -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -CONFIG_NFSD=y -# CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set -CONFIG_ROOT_NFS=y -CONFIG_LOCKD=y -CONFIG_EXPORTFS=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set -# CONFIG_USB_GADGET is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set - -# -# Library routines -# -# CONFIG_CRC32 is not set - -# -# Kernel hacking -# -# CONFIG_DEBUG_KERNEL is not set -# CONFIG_KALLSYMS is not set -CONFIG_SERIAL_TEXT_DEBUG=y - -# -# Security options -# -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 119106ad7e8..b404c4872d8 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -56,7 +56,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_POWERPMC250 is not set # CONFIG_EV64260 is not set # CONFIG_SPRUCE is not set -# CONFIG_MENF1 is not set # CONFIG_LOPEC is not set # CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set @@ -68,7 +67,6 @@ CONFIG_PPC_MULTIPLATFORM=y # CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set -# CONFIG_ZX4500 is not set CONFIG_PPC_CHRP=y CONFIG_PPC_PMAC=y CONFIG_PPC_PREP=y diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c index acc76c5f264..0e8be4cb370 100644 --- a/arch/ppc/kernel/ppc-stub.c +++ b/arch/ppc/kernel/ppc-stub.c @@ -851,14 +851,4 @@ kgdb_output_string (const char* s, unsigned int count) putpacket(buffer); return 1; - } - -#if defined(CONFIG_6xx) || defined(CONFIG_POWER3) - -/* This is used on arches which don't have a serial driver that maps - * the ports for us */ -void -kgdb_map_scc(void) -{ } -#endif diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 2832d5580c1..8ef2791d112 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -272,8 +272,10 @@ EXPORT_SYMBOL(kd_mksound); #ifdef CONFIG_NVRAM EXPORT_SYMBOL(nvram_read_byte); EXPORT_SYMBOL(nvram_write_byte); +#ifdef CONFIG_PPC_PMAC EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); +#endif #endif /* CONFIG_NVRAM */ EXPORT_SYMBOL(to_tm); diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index a0f733b81d0..27be4e41310 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -619,6 +619,8 @@ void __init setup_arch(char **cmdline_p) if (strstr(cmd_line, "nokgdb")) printk("kgdb default breakpoint deactivated on command line\n"); else { + if (ppc_md.progress) + ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); printk("kgdb default breakpoint activated\n"); breakpoint(); } diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index 263a40b0563..9eb9829f310 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -43,9 +43,8 @@ obj-$(CONFIG_POWERPMC250) += powerpmc250.o obj-$(CONFIG_PPLUS) += pplus_pci.o pplus_setup.o obj-$(CONFIG_PRPMC750) += prpmc750_setup.o prpmc750_pci.o obj-$(CONFIG_PRPMC800) += prpmc800_setup.o prpmc800_pci.o -obj-$(CONFIG_SANDPOINT) += sandpoint_setup.o sandpoint_pci.o +obj-$(CONFIG_SANDPOINT) += sandpoint.o obj-$(CONFIG_SPRUCE) += spruce_setup.o spruce_pci.o -obj-$(CONFIG_ZX4500) += zx4500_setup.o zx4500_pci.o ifeq ($(CONFIG_SMP),y) obj-$(CONFIG_PPC_PMAC) += pmac_smp.o diff --git a/arch/ppc/platforms/menf1.h b/arch/ppc/platforms/menf1.h deleted file mode 100644 index ecb9f094ce9..00000000000 --- a/arch/ppc/platforms/menf1.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * arch/ppc/platforms/menf1.h - * - * Definitions for MEN F1 board support - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __PPC_PLATFORMS_MENF1_H -#define __PPC_PLATFORMS_MENF1_H - -#define MENF1_NVRAM_AS0 0x70 -#define MENF1_NVRAM_AS1 0x72 -#define MENF1_NVRAM_DATA 0x71 - -#define MENF1_IDE0_BASE_ADDR 0x1f0 -#define MENF1_IDE1_BASE_ADDR 0x170 - -#endif /* __PPC_PLATFORMS_MENF1_H */ diff --git a/arch/ppc/platforms/menf1_pci.c b/arch/ppc/platforms/menf1_pci.c deleted file mode 100644 index 303d8756ffd..00000000000 --- a/arch/ppc/platforms/menf1_pci.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * arch/ppc/platforms/menf1_pci.c - * - * PCI support for MEN F1 - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "menf1.h" - -#undef DEBUG -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG */ - -static inline int __init -menf1_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) -{ - static char pci_irq_table[][4] = - /* - * PCI IDSEL/INTPIN->INTLINE - * A B C D - */ - { - {10, 11, 7, 9}, /* IDSEL 26 - PCMIP 0 */ - {0, 0, 0, 0}, /* IDSEL 27 - M5229 IDE */ - {0, 0, 0, 0}, /* IDSEL 28 - M7101 PMU */ - {9, 10, 11, 7}, /* IDSEL 29 - PCMIP 1 */ - {10, 11, 7, 9}, /* IDSEL 30 - P2P Bridge */ - }; - const long min_idsel = 26, max_idsel = 30, irqs_per_slot = 4; - return PCI_IRQ_TABLE_LOOKUP; -}; - -static int -menf1_exclude_device(u_char bus, u_char devfn) -{ - if ((bus == 0) && (devfn == 0xe0)) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - else { - return PCIBIOS_SUCCESSFUL; - } -} - -void __init -menf1_find_bridges(void) -{ - struct pci_controller* hose; - - hose = pcibios_alloc_controller(); - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - - ppc_md.pci_exclude_device = menf1_exclude_device; - - mpc10x_bridge_init(hose, - MPC10X_MEM_MAP_B, - MPC10X_MEM_MAP_B, - MPC10X_MAPB_EUMB_BASE); - - hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); - - { - /* Add ISA bus wait states */ - unsigned char isa_control; - - early_read_config_byte(hose, 0, 0x90, 0x43, &isa_control); - isa_control |= 0x33; - early_write_config_byte(hose, 0, 0x90, 0x43, isa_control); - } - - ppc_md.pci_swizzle = common_swizzle; - ppc_md.pci_map_irq = menf1_map_irq; -} diff --git a/arch/ppc/platforms/menf1_setup.c b/arch/ppc/platforms/menf1_setup.c deleted file mode 100644 index b202350a765..00000000000 --- a/arch/ppc/platforms/menf1_setup.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * arch/ppc/platforms/menf1_setup.c - * - * Board setup routines for MEN F1 - * - * Author: Matt Porter - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "menf1.h" - -extern void menf1_find_bridges(void); -extern unsigned long loops_per_jiffy; - -/* Dummy variable to satisfy mpc10x_common.o */ -void *OpenPIC_Addr; - -static int -menf1_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "machine\t\t: MEN F1\n"); - - return 0; -} - -static void __init -menf1_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000/HZ; - - /* Lookup PCI host bridges */ - menf1_find_bridges(); - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA2; -#endif - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - printk("MEN F1 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); -} - -static void -menf1_restart(char *cmd) -{ - - int picr1; - struct pci_dev *pdev; - - local_irq_disable(); - - /* - * Firmware doesn't like re-entry using Map B (CHRP), so make sure the - * PCI bridge is using MAP A (PReP). - */ - - pdev = pci_find_slot(0, PCI_DEVFN(0,0)); - - while(pdev == NULL); /* paranoia */ - - pci_read_config_dword(pdev, MPC10X_CFG_PICR1_REG, &picr1); - - picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) | - MPC10X_CFG_PICR1_ADDR_MAP_A; - - pci_write_config_dword(pdev, MPC10X_CFG_PICR1_REG, picr1); - - asm volatile("sync"); - - /* SRR0 has system reset vector, SRR1 has default MSR value */ - /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ - __asm__ __volatile__ - ("\n\ - lis 3,0xfff0 - ori 3,3,0x0100 - mtspr 26,3 - li 3,0 - mtspr 27,3 - rfi - "); - while(1); -} - -static void -menf1_halt(void) -{ - local_irq_disable(); - while (1); -} - -static void -menf1_power_off(void) -{ - menf1_halt(); -} - -static void __init -menf1_init_IRQ(void) -{ - int i; - - for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ ) - irq_desc[i].handler = &i8259_pic; - i8259_init(NULL); -} - -/* - * Set BAT 3 to map 0xF0000000. - */ -static __inline__ void -menf1_set_bat(void) -{ - static int mapping_set = 0; - - if (!mapping_set) - { - - /* wait for all outstanding memory accesses to complete */ - mb(); - - /* setup DBATs */ - mtspr(DBAT3U, 0xf0001ffe); - mtspr(DBAT3L, 0xf000002a); - - /* wait for updates */ - mb(); - - mapping_set = 1; - } - return; -} - -static unsigned long __init -menf1_find_end_of_memory(void) -{ - /* Cover the I/O with a BAT */ - menf1_set_bat(); - - /* Read the memory size from the MPC107 SMC */ - return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); -} - -static void __init -menf1_map_io(void) -{ - io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* IDE functions */ - -static void __init -menf1_ide_init_hwif_ports (hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - int i = 8; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += 1; - } - if (ctrl_port) - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - else - hw->io_ports[IDE_CONTROL_OFFSET] = - hw->io_ports[IDE_DATA_OFFSET] + 0x206; - - if (irq != NULL) - *irq = 0; -} - -static int -menf1_ide_default_irq(unsigned long base) -{ - if (base == MENF1_IDE0_BASE_ADDR) - return 14; - else if (base == MENF1_IDE1_BASE_ADDR) - return 15; - else - return 0; -} - -static unsigned long -menf1_ide_default_io_base(int index) -{ - if (index == 0) - return MENF1_IDE0_BASE_ADDR; - else if (index == 1) - return MENF1_IDE1_BASE_ADDR; - else - return 0; -} -#endif - -TODC_ALLOC(); - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - parse_bootinfo(find_bootinfo()); - - isa_io_base = MPC10X_MAPB_ISA_IO_BASE; - isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; - pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; - - ppc_md.setup_arch = menf1_setup_arch; - ppc_md.show_cpuinfo = menf1_show_cpuinfo; - ppc_md.init_IRQ = menf1_init_IRQ; - ppc_md.get_irq = i8259_irq; - - ppc_md.find_end_of_memory = menf1_find_end_of_memory; - ppc_md.setup_io_mappings = menf1_map_io; - - ppc_md.restart = menf1_restart; - ppc_md.power_off = menf1_power_off; - ppc_md.halt = menf1_halt; - - TODC_INIT(TODC_TYPE_MK48T59, - MENF1_NVRAM_AS0, - MENF1_NVRAM_AS1, - MENF1_NVRAM_DATA, - 7); - - ppc_md.time_init = todc_time_init; - ppc_md.get_rtc_time = todc_get_rtc_time; - ppc_md.set_rtc_time = todc_set_rtc_time; - ppc_md.calibrate_decr = todc_calibrate_decr; - - ppc_md.nvram_read_val = todc_m48txx_read_val; - ppc_md.nvram_write_val = todc_m48txx_write_val; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.default_io_base = menf1_ide_default_io_base; - ppc_ide_md.default_irq = menf1_ide_default_irq; - ppc_ide_md.ide_init_hwif = menf1_ide_init_hwif_ports; -#endif -} diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c new file mode 100644 index 00000000000..5c3e87fd081 --- /dev/null +++ b/arch/ppc/platforms/sandpoint.c @@ -0,0 +1,719 @@ +/* + * arch/ppc/platforms/sandpoint_setup.c + * + * Board setup routines for the Motorola SPS Sandpoint Test Platform. + * + * Author: Mark A. Greer + * mgreer@mvista.com + * + * 2000-2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +/* + * This file adds support for the Motorola SPS Sandpoint Test Platform. + * These boards have a PPMC slot for the processor so any combination + * of cpu and host bridge can be attached. This port is for an 8240 PPMC + * module from Motorola SPS and other closely related cpu/host bridge + * combinations (e.g., 750/755/7400 with MPC107 host bridge). + * The sandpoint itself has a Windbond 83c553 (PCI-ISA bridge, 2 DMA ctlrs, 2 + * cascaded 8259 interrupt ctlrs, 8254 Timer/Counter, and an IDE ctlr), a + * National 87308 (RTC, 2 UARTs, Keyboard & mouse ctlrs, and a floppy ctlr), + * and 4 PCI slots (only 2 of which are usable; the other 2 are keyed for 3.3V + * but are really 5V). + * + * The firmware on the sandpoint is called DINK (not my acronym :). This port + * depends on DINK to do some basic initialization (e.g., initialize the memory + * ctlr) and to ensure that the processor is using MAP B (CHRP map). + * + * The switch settings for the Sandpoint board MUST be as follows: + * S3: down + * S4: up + * S5: up + * S6: down + * + * 'down' is in the direction from the PCI slots towards the PPMC slot; + * 'up' is in the direction from the PPMC slot towards the PCI slots. + * Be careful, the way the sandpoint board is installed in XT chasses will + * make the directions reversed. + * + * Since Motorola listened to our suggestions for improvement, we now have + * the Sandpoint X3 board. All of the PCI slots are available, it uses + * the serial interrupt interface (just a hardware thing we need to + * configure properly). + * + * Use the default X3 switch settings. The interrupts are then: + * EPIC Source + * 0 SIOINT (8259, active low) + * 1 PCI #1 + * 2 PCI #2 + * 3 PCI #3 + * 4 PCI #4 + * 7 Winbond INTC (IDE interrupt) + * 8 Winbond INTD (IDE interrupt) + * + * + * Motorola has finally released a version of DINK32 that correctly + * (seemingly) initalizes the memory controller correctly, regardless + * of the amount of memory in the system. Once a method of determining + * what version of DINK initializes the system for us, if applicable, is + * found, we can hopefully stop hardcoding 32MB of RAM. + * + * It is important to note that this code only supports the Sandpoint X3 + * (all flavors) platform, and it does not support the X2 anymore. Code + * that at one time worked on the X2 can be found at: + * ftp://source.mvista.com/pub/linuxppc/obsolete/sandpoint/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for linux/serial_core.h */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sandpoint.h" + +extern void gen550_progress(char *, unsigned short); +extern void gen550_init(int, struct uart_port *); + +unsigned char __res[sizeof(bd_t)]; + +static void sandpoint_halt(void); + +/* + * Define all of the IRQ senses and polarities. Taken from the + * Sandpoint X3 User's manual. + */ +static u_char sandpoint_openpic_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 0: SIOINT */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 2: PCI Slot 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 3: PCI Slot 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 4: PCI Slot 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 5: PCI Slot 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 8: IDE (INT C) */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE) /* 9: IDE (INT D) */ +}; + +/* + * Motorola SPS Sandpoint interrupt routing. + */ +static inline int +sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 16, 0, 0, 0 }, /* IDSEL 11 - i8259 on Winbond */ + { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ + { 18, 21, 20, 19 }, /* IDSEL 13 - PCI slot 1 */ + { 19, 18, 21, 20 }, /* IDSEL 14 - PCI slot 2 */ + { 20, 19, 18, 21 }, /* IDSEL 15 - PCI slot 3 */ + { 21, 20, 19, 18 }, /* IDSEL 16 - PCI slot 4 */ + }; + + const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void __init +sandpoint_setup_winbond_83553(struct pci_controller *hose) +{ + int devfn; + + /* + * Route IDE interrupts directly to the 8259's IRQ 14 & 15. + * We can't route the IDE interrupt to PCI INTC# or INTD# because those + * woule interfere with the PMC's INTC# and INTD# lines. + */ + /* + * Winbond Fcn 0 + */ + devfn = PCI_DEVFN(11,0); + + early_write_config_byte(hose, + 0, + devfn, + 0x43, /* IDE Interrupt Routing Control */ + 0xef); + early_write_config_word(hose, + 0, + devfn, + 0x44, /* PCI Interrupt Routing Control */ + 0x0000); + + /* Want ISA memory cycles to be forwarded to PCI bus */ + early_write_config_byte(hose, + 0, + devfn, + 0x48, /* ISA-to-PCI Addr Decoder Control */ + 0xf0); + + /* Enable RTC and Keyboard address locations. */ + early_write_config_byte(hose, + 0, + devfn, + 0x4d, /* Chip Select Control Register */ + 0x00); + + /* Enable Port 92. */ + early_write_config_byte(hose, + 0, + devfn, + 0x4e, /* AT System Control Register */ + 0x06); + /* + * Winbond Fcn 1 + */ + devfn = PCI_DEVFN(11,1); + + /* Put IDE controller into native mode. */ + early_write_config_byte(hose, + 0, + devfn, + 0x09, /* Programming interface Register */ + 0x8f); + + /* Init IRQ routing, enable both ports, disable fast 16 */ + early_write_config_dword(hose, + 0, + devfn, + 0x40, /* IDE Control/Status Register */ + 0x00ff0011); + return; +} + +static void __init +sandpoint_find_bridges(void) +{ + struct pci_controller *hose; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + if (mpc10x_bridge_init(hose, + MPC10X_MEM_MAP_B, + MPC10X_MEM_MAP_B, + MPC10X_MAPB_EUMB_BASE) == 0) { + + /* Do early winbond init, then scan PCI bus */ + sandpoint_setup_winbond_83553(hose); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pcibios_fixup = NULL; + ppc_md.pcibios_fixup_bus = NULL; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = sandpoint_map_irq; + } + else { + if (ppc_md.progress) + ppc_md.progress("Bridge init failed", 0x100); + printk("Host bridge init failed\n"); + } + + return; +} + +#if defined(CONFIG_SERIAL_8250) && \ + (defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)) +static void __init +sandpoint_early_serial_map(void) +{ + struct uart_port serial_req; + + /* Setup serial port access */ + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.uartclk = UART_CLK; + serial_req.irq = 4; + serial_req.flags = STD_COM_FLAGS; + serial_req.iotype = SERIAL_IO_MEM; + serial_req.membase = (u_char *)SANDPOINT_SERIAL_0; + + gen550_init(0, &serial_req); + + if (early_serial_setup(&serial_req) != 0) + printk(KERN_ERR "Early serial init of port 0 failed\n"); + + /* Assume early_serial_setup() doesn't modify serial_req */ + serial_req.line = 1; + serial_req.irq = 3; /* XXXX */ + serial_req.membase = (u_char *)SANDPOINT_SERIAL_1; + + gen550_init(1, &serial_req); + + if (early_serial_setup(&serial_req) != 0) + printk(KERN_ERR "Early serial init of port 1 failed\n"); +} +#endif + +static void __init +sandpoint_setup_arch(void) +{ + loops_per_jiffy = 100000000 / HZ; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + /* Lookup PCI host bridges */ + sandpoint_find_bridges(); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); + + /* DINK32 12.3 and below do not correctly enable any caches. + * We will do this now with good known values. Future versions + * of DINK32 are supposed to get this correct. + */ + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) + /* 745x is different. We only want to pass along enable. */ + _set_L2CR(L2CR_L2E); + else if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) + /* All modules have 1MB of L2. We also assume that an + * L2 divisor of 3 will work. + */ + _set_L2CR(L2CR_L2E | L2CR_L2SIZ_1MB | L2CR_L2CLK_DIV3 + | L2CR_L2RAM_PIPE | L2CR_L2OH_1_0 | L2CR_L2DF); +#if 0 + /* Untested right now. */ + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR) { + /* Magic value. */ + _set_L3CR(0x8f032000); + } +#endif +} + +#define SANDPOINT_87308_CFG_ADDR 0x15c +#define SANDPOINT_87308_CFG_DATA 0x15d + +#define SANDPOINT_87308_CFG_INB(addr, byte) { \ + outb((addr), SANDPOINT_87308_CFG_ADDR); \ + (byte) = inb(SANDPOINT_87308_CFG_DATA); \ +} + +#define SANDPOINT_87308_CFG_OUTB(addr, byte) { \ + outb((addr), SANDPOINT_87308_CFG_ADDR); \ + outb((byte), SANDPOINT_87308_CFG_DATA); \ +} + +#define SANDPOINT_87308_SELECT_DEV(dev_num) { \ + SANDPOINT_87308_CFG_OUTB(0x07, (dev_num)); \ +} + +#define SANDPOINT_87308_DEV_ENABLE(dev_num) { \ + SANDPOINT_87308_SELECT_DEV(dev_num); \ + SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \ +} + +/* + * Initialize the ISA devices on the Nat'l PC87308VUL SuperIO chip. + */ +static int __init +sandpoint_setup_natl_87308(void) +{ + u_char reg; + + /* + * Enable all the devices on the Super I/O chip. + */ + SANDPOINT_87308_SELECT_DEV(0x00); /* Select kbd logical device */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x00); /* Set KBC clock to 8 Mhz */ + SANDPOINT_87308_DEV_ENABLE(0x00); /* Enable keyboard */ + SANDPOINT_87308_DEV_ENABLE(0x01); /* Enable mouse */ + SANDPOINT_87308_DEV_ENABLE(0x02); /* Enable rtc */ + SANDPOINT_87308_DEV_ENABLE(0x03); /* Enable fdc (floppy) */ + SANDPOINT_87308_DEV_ENABLE(0x04); /* Enable parallel */ + SANDPOINT_87308_DEV_ENABLE(0x05); /* Enable UART 2 */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ + SANDPOINT_87308_DEV_ENABLE(0x06); /* Enable UART 1 */ + SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ + + /* Set up floppy in PS/2 mode */ + outb(0x09, SIO_CONFIG_RA); + reg = inb(SIO_CONFIG_RD); + reg = (reg & 0x3F) | 0x40; + outb(reg, SIO_CONFIG_RD); + outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ + + return 0; +} + +arch_initcall(sandpoint_setup_natl_87308); + +/* + * Fix IDE interrupts. + */ +static int __init +sandpoint_fix_winbond_83553(void) +{ + /* Make all 8259 interrupt level sensitive */ + outb(0xf8, 0x4d0); + outb(0xde, 0x4d1); + + return 0; +} + +arch_initcall(sandpoint_fix_winbond_83553); + +static int __init +sandpoint_request_io(void) +{ + request_region(0x00,0x20,"dma1"); + request_region(0x20,0x20,"pic1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xa0,0x20,"pic2"); + request_region(0xc0,0x20,"dma2"); + + return 0; +} + +arch_initcall(sandpoint_request_io); + +/* + * Interrupt setup and service. Interrrupts on the Sandpoint come + * from the four PCI slots plus the 8259 in the Winbond Super I/O (SIO). + * The 8259 is cascaded from EPIC IRQ0, IRQ1-4 map to PCI slots 1-4, + * IDE is on EPIC 7 and 8. + */ +static void __init +sandpoint_init_IRQ(void) +{ + int i; + + OpenPIC_InitSenses = sandpoint_openpic_initsenses; + OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses); + + /* + * We need to tell openpic_set_sources where things actually are. + * mpc10x_common will setup OpenPIC_Addr at ioremap(EUMB phys base + + * EPIC offset (0x40000)); The EPIC IRQ Register Address Map - + * Interrupt Source Configuration Registers gives these numbers + * as offsets starting at 0x50200, we need to adjust occordinly. + */ + /* Map serial interrupts 0-15 */ + openpic_set_sources(0, 16, OpenPIC_Addr + 0x10200); + + openpic_init(NUM_8259_INTERRUPTS); + + /* + * openpic_init() has set up irq_desc[16-31] to be openpic + * interrupts. We need to set irq_desc[0-15] to be i8259 + * interrupts. + */ + for(i=0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + /* + * The EPIC allows for a read in the range of 0xFEF00000 -> + * 0xFEFFFFFF to generate a PCI interrupt-acknowledge transaction. + */ + i8259_init(0xfef00000); +} + +static u32 +sandpoint_irq_canonicalize(u32 irq) +{ + if (irq == 2) + return 9; + else + return irq; +} + +static unsigned long __init +sandpoint_find_end_of_memory(void) +{ + bd_t *bp = (bd_t *)__res; + + if (bp->bi_memsize) + return bp->bi_memsize; + + /* DINK32 13.0 correctly initalizes things, so iff you use + * this you _should_ be able to change this instead of a + * hardcoded value. */ +#if 0 + return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); +#else + return 32*1024*1024; +#endif +} + +static void __init +sandpoint_map_io(void) +{ + io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); +} + +static void +sandpoint_restart(char *cmd) +{ + local_irq_disable(); + + /* Set exception prefix high - to the firmware */ + _nmask_and_or_msr(0, MSR_IP); + + /* Reset system via Port 92 */ + outb(0x00, 0x92); + outb(0x01, 0x92); + for(;;); /* Spin until reset happens */ +} + +static void +sandpoint_power_off(void) +{ + local_irq_disable(); + for(;;); /* No way to shut power off with software */ + /* NOTREACHED */ +} + +static void +sandpoint_halt(void) +{ + sandpoint_power_off(); + /* NOTREACHED */ +} + +static int +sandpoint_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: Motorola SPS\n"); + seq_printf(m, "machine\t\t: Sandpoint\n"); + + return 0; +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +/* + * IDE support. + */ +static int sandpoint_ide_ports_known = 0; +static unsigned long sandpoint_ide_regbase[MAX_HWIFS]; +static unsigned long sandpoint_ide_ctl_regbase[MAX_HWIFS]; +static unsigned long sandpoint_idedma_regbase; + +static void +sandpoint_ide_probe(void) +{ + struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, NULL); + + if (pdev) { + sandpoint_ide_regbase[0]=pdev->resource[0].start; + sandpoint_ide_regbase[1]=pdev->resource[2].start; + sandpoint_ide_ctl_regbase[0]=pdev->resource[1].start; + sandpoint_ide_ctl_regbase[1]=pdev->resource[3].start; + sandpoint_idedma_regbase=pdev->resource[4].start; + } + + sandpoint_ide_ports_known = 1; +} + +static int +sandpoint_ide_default_irq(unsigned long base) +{ + if (sandpoint_ide_ports_known == 0) + sandpoint_ide_probe(); + + if (base == sandpoint_ide_regbase[0]) + return SANDPOINT_IDE_INT0; + else if (base == sandpoint_ide_regbase[1]) + return SANDPOINT_IDE_INT1; + else + return 0; +} + +static unsigned long +sandpoint_ide_default_io_base(int index) +{ + if (sandpoint_ide_ports_known == 0) + sandpoint_ide_probe(); + + return sandpoint_ide_regbase[index]; +} + +static void __init +sandpoint_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, + unsigned long ctrl_port, int *irq) +{ + unsigned long reg = data_port; + uint alt_status_base; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg++; + } + + if (data_port == sandpoint_ide_regbase[0]) { + alt_status_base = sandpoint_ide_ctl_regbase[0] + 2; + hw->irq = 14; + } + else if (data_port == sandpoint_ide_regbase[1]) { + alt_status_base = sandpoint_ide_ctl_regbase[1] + 2; + hw->irq = 15; + } + else { + alt_status_base = 0; + hw->irq = 0; + } + + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; + } + + if (irq != NULL) { + *irq = hw->irq; + } +} +#endif + +/* + * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. + */ +static __inline__ void +sandpoint_set_bat(void) +{ + unsigned long bat3u, bat3l; + + __asm__ __volatile__( + " lis %0,0xf800\n \ + ori %1,%0,0x002a\n \ + ori %0,%0,0x0ffe\n \ + mtspr 0x21e,%0\n \ + mtspr 0x21f,%1\n \ + isync\n \ + sync " + : "=r" (bat3u), "=r" (bat3l)); +} + +TODC_ALLOC(); + +void __init +platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + parse_bootinfo(find_bootinfo()); + + /* ASSUMPTION: If both r3 (bd_t pointer) and r6 (cmdline pointer) + * are non-zero, then we should use the board info from the bd_t + * structure and the cmdline pointed to by r6 instead of the + * information from birecs, if any. Otherwise, use the information + * from birecs as discovered by the preceeding call to + * parse_bootinfo(). This rule should work with both PPCBoot, which + * uses a bd_t board info structure, and the kernel boot wrapper, + * which uses birecs. + */ + if (r3 && r6) { + /* copy board info structure */ + memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) ); + /* copy command line */ + *(char *)(r7+KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6+KERNELBASE)); + } + +#ifdef CONFIG_BLK_DEV_INITRD + /* take care of initrd if we have one */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Map in board regs, etc. */ + sandpoint_set_bat(); + + isa_io_base = MPC10X_MAPB_ISA_IO_BASE; + isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; + pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; + ISA_DMA_THRESHOLD = 0x00ffffff; + DMA_MODE_READ = 0x44; + DMA_MODE_WRITE = 0x48; + + ppc_md.setup_arch = sandpoint_setup_arch; + ppc_md.show_cpuinfo = sandpoint_show_cpuinfo; + ppc_md.irq_canonicalize = sandpoint_irq_canonicalize; + ppc_md.init_IRQ = sandpoint_init_IRQ; + ppc_md.get_irq = openpic_get_irq; + + ppc_md.restart = sandpoint_restart; + ppc_md.power_off = sandpoint_power_off; + ppc_md.halt = sandpoint_halt; + + ppc_md.find_end_of_memory = sandpoint_find_end_of_memory; + ppc_md.setup_io_mappings = sandpoint_map_io; + + TODC_INIT(TODC_TYPE_PC97307, 0x70, 0x00, 0x71, 8); + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.calibrate_decr = todc_calibrate_decr; + + ppc_md.nvram_read_val = todc_mc146818_read_val; + ppc_md.nvram_write_val = todc_mc146818_write_val; + +#if defined(CONFIG_SERIAL_8250) && \ + (defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)) + sandpoint_early_serial_map(); +#ifdef CONFIG_SERIAL_TEXT_DEBUG + ppc_md.progress = gen550_progress; +#endif +#endif + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + ppc_ide_md.default_irq = sandpoint_ide_default_irq; + ppc_ide_md.default_io_base = sandpoint_ide_default_io_base; + ppc_ide_md.ide_init_hwif = sandpoint_ide_init_hwif_ports; +#endif +} diff --git a/arch/ppc/platforms/sandpoint.h b/arch/ppc/platforms/sandpoint.h index e1a5b36c5de..bdb7fb83f15 100644 --- a/arch/ppc/platforms/sandpoint.h +++ b/arch/ppc/platforms/sandpoint.h @@ -6,7 +6,7 @@ * Author: Mark A. Greer * mgreer@mvista.com * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under + * 2000-2003 (c) MontaVista, Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. @@ -19,8 +19,8 @@ #ifndef __PPC_PLATFORMS_SANDPOINT_H #define __PPC_PLATFORMS_SANDPOINT_H -#ifdef CONFIG_SANDPOINT_X3 -#define SANDPOINT_SIO_SLOT 0 /* Cascaded from EPIC IRQ 0 */ +#include + #if 0 /* The Sandpoint X3 allows the IDE interrupt to be directly connected * from the Windbond (PCI INTC or INTD) to the serial EPIC. Someday @@ -28,27 +28,13 @@ * initialization than change it to route the different interrupts :-). * -- Dan */ -#define SANDPOINT_IDE_INT0 23 /* EPIC 7 */ -#define SANDPOINT_IDE_INT1 24 /* EPIC 8 */ -#else -#define SANDPOINT_IDE_INT0 14 /* 8259 Test */ -#define SANDPOINT_IDE_INT1 15 /* 8259 Test */ -#endif +#define SANDPOINT_IDE_INT0 23 /* EPIC 7 */ +#define SANDPOINT_IDE_INT1 24 /* EPIC 8 */ #else - /* - * Define the PCI slot that the 8259 is sharing interrupts with. - * Valid values are 1 (PCI slot 2) and 2 (PCI slot 3). - */ -#define SANDPOINT_SIO_SLOT 1 - -/* ...and for the IDE from the 8259.... -*/ -#define SANDPOINT_IDE_INT0 14 -#define SANDPOINT_IDE_INT1 15 +#define SANDPOINT_IDE_INT0 14 /* 8259 Test */ +#define SANDPOINT_IDE_INT1 15 /* 8259 Test */ #endif -#define SANDPOINT_SIO_IRQ (SANDPOINT_SIO_SLOT + NUM_8259_INTERRUPTS) - /* * The sandpoint boards have processor modules that either have an 8240 or * an MPC107 host bridge on them. These bridges have an IDSEL line that allows @@ -62,7 +48,33 @@ */ #define SANDPOINT_HOST_BRIDGE_IDSEL 12 +/* + * Serial defines. + */ +#define SANDPOINT_SERIAL_0 0xfe0003f8 +#define SANDPOINT_SERIAL_1 0xfe0002f8 + +#define RS_TABLE_SIZE 2 + +/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ +#define BASE_BAUD ( 1843200 / 16 ) +#define UART_CLK 1843200 + +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#endif + +#define STD_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, SANDPOINT_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \ + iomem_base: (u8 *)SANDPOINT_SERIAL_0, \ + io_type: SERIAL_IO_MEM }, \ + { 0, BASE_BAUD, SANDPOINT_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \ + iomem_base: (u8 *)SANDPOINT_SERIAL_1, \ + io_type: SERIAL_IO_MEM }, -void sandpoint_find_bridges(void); +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DFNS #endif /* __PPC_PLATFORMS_SANDPOINT_H */ diff --git a/arch/ppc/platforms/sandpoint_pci.c b/arch/ppc/platforms/sandpoint_pci.c deleted file mode 100644 index e585637f05f..00000000000 --- a/arch/ppc/platforms/sandpoint_pci.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * arch/ppc/platforms/sandpoint_pci.c - * - * PCI setup routines for the Motorola SPS Sandpoint Test Platform - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "sandpoint.h" - -/* - * Motorola SPS Sandpoint interrupt routing. - */ -static inline int -sandpoint_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) -{ - static char pci_irq_table[][4] = - /* - * PCI IDSEL/INTPIN->INTLINE - * A B C D - */ - { - { SANDPOINT_SIO_IRQ, - 0, 0, 0 }, /* IDSEL 11 - i8259 on Winbond */ - { 0, 0, 0, 0 }, /* IDSEL 12 - unused */ -#ifdef CONFIG_SANDPOINT_X3 -#if 0 /* This is what it _should_ look like -- Dan */ - { 17, 20, 19, 18 }, /* IDSEL 13 - PCI slot 1 */ - { 18, 17, 20, 19 }, /* IDSEL 14 - PCI slot 2 */ - { 19, 18, 17, 20 }, /* IDSEL 15 - PCI slot 3 */ - { 20, 19, 18, 17 }, /* IDSEL 16 - PCI slot 4 */ -#else - { 18, 21, 20, 19 }, /* IDSEL 13 - PCI slot 1 */ - { 19, 18, 21, 20 }, /* IDSEL 14 - PCI slot 2 */ - { 20, 19, 18, 21 }, /* IDSEL 15 - PCI slot 3 */ - { 21, 20, 19, 18 }, /* IDSEL 16 - PCI slot 4 */ -#endif -#else - { 16, 19, 18, 17 }, /* IDSEL 13 - PCI slot 1 */ - { 17, 16, 19, 18 }, /* IDSEL 14 - PCI slot 2 */ - { 18, 17, 16, 19 }, /* IDSEL 15 - PCI slot 3 */ - { 19, 18, 17, 16 }, /* IDSEL 16 - PCI slot 4 */ -#endif - }; - - const long min_idsel = 11, max_idsel = 16, irqs_per_slot = 4; - return PCI_IRQ_TABLE_LOOKUP; -} - -static void __init -sandpoint_setup_winbond_83553(struct pci_controller *hose) -{ - int devfn; - - /* - * Route IDE interrupts directly to the 8259's IRQ 14 & 15. - * We can't route the IDE interrupt to PCI INTC# or INTD# because those - * woule interfere with the PMC's INTC# and INTD# lines. - */ - /* - * Winbond Fcn 0 - */ - devfn = PCI_DEVFN(11,0); - - early_write_config_byte(hose, - 0, - devfn, - 0x43, /* IDE Interrupt Routing Control */ - 0xef); - early_write_config_word(hose, - 0, - devfn, - 0x44, /* PCI Interrupt Routing Control */ - 0x0000); - - /* Want ISA memory cycles to be forwarded to PCI bus */ - early_write_config_byte(hose, - 0, - devfn, - 0x48, /* ISA-to-PCI Addr Decoder Control */ - 0xf0); - - /* Enable RTC and Keyboard address locations. */ - early_write_config_byte(hose, - 0, - devfn, - 0x4d, /* Chip Select Control Register */ - 0x00); - - /* Enable Port 92. */ - early_write_config_byte(hose, - 0, - devfn, - 0x4e, /* AT System Control Register */ - 0x06); - /* - * Winbond Fcn 1 - */ - devfn = PCI_DEVFN(11,1); - - /* Put IDE controller into native mode. */ - early_write_config_byte(hose, - 0, - devfn, - 0x09, /* Programming interface Register */ - 0x8f); - - /* Init IRQ routing, enable both ports, disable fast 16 */ - early_write_config_dword(hose, - 0, - devfn, - 0x40, /* IDE Control/Status Register */ - 0x00ff0011); - return; -} - -static int -sandpoint_exclude_device(u_char bus, u_char devfn) -{ - if ((bus == 0) && (PCI_SLOT(devfn) == SANDPOINT_HOST_BRIDGE_IDSEL)) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - else { - return PCIBIOS_SUCCESSFUL; - } -} - -void __init -sandpoint_find_bridges(void) -{ - struct pci_controller *hose; - - hose = pcibios_alloc_controller(); - - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - - if (mpc10x_bridge_init(hose, - MPC10X_MEM_MAP_B, - MPC10X_MEM_MAP_B, - MPC10X_MAPB_EUMB_BASE) == 0) { - - /* Do early winbond init, then scan PCI bus */ - sandpoint_setup_winbond_83553(hose); - ppc_md.pci_exclude_device = sandpoint_exclude_device; - hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); - - ppc_md.pcibios_fixup = NULL; - ppc_md.pcibios_fixup_bus = NULL; - ppc_md.pci_swizzle = common_swizzle; - ppc_md.pci_map_irq = sandpoint_map_irq; - } - else { - if (ppc_md.progress) - ppc_md.progress("Bridge init failed", 0x100); - printk("Host bridge init failed\n"); - } - - return; -} diff --git a/arch/ppc/platforms/sandpoint_serial.h b/arch/ppc/platforms/sandpoint_serial.h deleted file mode 100644 index 0981c415fa5..00000000000 --- a/arch/ppc/platforms/sandpoint_serial.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * include/asm-ppc/sandpoint_serial.h - * - * Definitions for Motorola SPS Sandpoint Test Platform - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASMPPC_SANDPOINT_SERIAL_H -#define __ASMPPC_SANDPOINT_SERIAL_H - -#include - -#define SANDPOINT_SERIAL_0 0xfe0003f8 -#define SANDPOINT_SERIAL_1 0xfe0002f8 - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 2 -#endif - -/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ -#define BASE_BAUD ( 1843200 / 16 ) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -#define STD_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, SANDPOINT_SERIAL_0, 4, STD_COM_FLAGS, /* ttyS0 */ \ - iomem_base: (u8 *)SANDPOINT_SERIAL_0, \ - io_type: SERIAL_IO_MEM }, \ - { 0, BASE_BAUD, SANDPOINT_SERIAL_1, 3, STD_COM_FLAGS, /* ttyS1 */ \ - iomem_base: (u8 *)SANDPOINT_SERIAL_1, \ - io_type: SERIAL_IO_MEM }, - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DFNS - -#endif /* __ASMPPC_SANDPOINT_SERIAL_H */ diff --git a/arch/ppc/platforms/sandpoint_setup.c b/arch/ppc/platforms/sandpoint_setup.c deleted file mode 100644 index 5860f3d0ade..00000000000 --- a/arch/ppc/platforms/sandpoint_setup.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * arch/ppc/platforms/sandpoint_setup.c - * - * Board setup routines for the Motorola SPS Sandpoint Test Platform. - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -/* - * This file adds support for the Motorola SPS Sandpoint Test Platform. - * These boards have a PPMC slot for the processor so any combination - * of cpu and host bridge can be attached. This port is for an 8240 PPMC - * module from Motorola SPS and other closely related cpu/host bridge - * combinations (e.g., 750/755/7400 with MPC107 host bridge). - * The sandpoint itself has a Windbond 83c553 (PCI-ISA bridge, 2 DMA ctlrs, 2 - * cascaded 8259 interrupt ctlrs, 8254 Timer/Counter, and an IDE ctlr), a - * National 87308 (RTC, 2 UARTs, Keyboard & mouse ctlrs, and a floppy ctlr), - * and 4 PCI slots (only 2 of which are usable; the other 2 are keyed for 3.3V - * but are really 5V). - * - * The firmware on the sandpoint is called DINK (not my acronym :). This port - * depends on DINK to do some basic initialization (e.g., initialize the memory - * ctlr) and to ensure that the processor is using MAP B (CHRP map). - * - * The switch settings for the Sandpoint board MUST be as follows: - * S3: down - * S4: up - * S5: up - * S6: down - * - * 'down' is in the direction from the PCI slots towards the PPMC slot; - * 'up' is in the direction from the PPMC slot towards the PCI slots. - * Be careful, the way the sandpoint board is installed in XT chasses will - * make the directions reversed. - * - * Since Motorola listened to our suggestions for improvement, we now have - * the Sandpoint X3 board. All of the PCI slots are available, it uses - * the serial interrupt interface (just a hardware thing we need to - * configure properly). - * - * Use the default X3 switch settings. The interrupts are then: - * EPIC Source - * 0 SIOINT (8259, active low) - * 1 PCI #1 - * 2 PCI #2 - * 3 PCI #3 - * 4 PCI #4 - * 7 Winbond INTC (IDE interrupt) - * 8 Winbond INTD (IDE interrupt) - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sandpoint.h" - -extern u_int openpic_irq(void); -extern void openpic_eoi(void); - -static void sandpoint_halt(void); - - -/* - * *** IMPORTANT *** - * - * The first 16 entries of 'sandpoint_openpic_initsenses[]' are there and - * initialized to 0 on purpose. DO NOT REMOVE THEM as the 'offset' parameter - * of 'openpic_init()' does not work for the sandpoint because the 8259 - * interrupt is NOT routed to the EPIC's IRQ 0 AND the EPIC's IRQ 0's offset is - * the same as a normal openpic's IRQ 16 offset. - */ -static u_char sandpoint_openpic_initsenses[] __initdata = { - 0, /* 0-15 not used by EPCI but by 8259 (std PC-type IRQs) */ - 0, /* 1 */ - 0, /* 2 */ - 0, /* 3 */ - 0, /* 4 */ - 0, /* 5 */ - 0, /* 6 */ - 0, /* 7 */ - 0, /* 8 */ - 0, /* 9 */ - 0, /* 10 */ - 0, /* 11 */ - 0, /* 12 */ - 0, /* 13 */ - 0, /* 14 */ - 0, /* 15 */ -#ifdef CONFIG_SANDPOINT_X3 - 1, /* 16: EPIC IRQ 0: Active Low -- SIOINT (8259) */ - 0, /* AACK! Shouldn't need this.....see sandpoint_pci.c for more info */ - 1, /* 17: EPIC IRQ 1: Active Low -- PCI Slot 1 */ - 1, /* 18: EPIC IRQ 2: Active Low -- PCI Slot 2 */ - 1, /* 19: EPIC IRQ 3: Active Low -- PCI Slot 3 */ - 1, /* 20: EPIC IRQ 4: Active Low -- PCI Slot 4 */ - 0, /* 21 -- Unused */ - 0, /* 22 -- Unused */ - 1, /* 23 -- IDE (Winbond INT C) */ - 1, /* 24 -- IDE (Winbond INT D) */ - /* 35 - 31 (EPIC 9 - 15) Unused */ -#else - 1, /* 16: EPIC IRQ 0: Active Low -- PCI intrs */ - 1, /* 17: EPIC IRQ 1: Active Low -- PCI (possibly 8259) intrs */ - 1, /* 18: EPIC IRQ 2: Active Low -- PCI (possibly 8259) intrs */ - 1 /* 19: EPIC IRQ 3: Active Low -- PCI intrs */ - /* 20: EPIC IRQ 4: Not used */ -#endif -}; - -static void __init -sandpoint_setup_arch(void) -{ - loops_per_jiffy = 100000000 / HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#ifdef CONFIG_ROOT_NFS - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_HDA1; -#endif - - /* Lookup PCI host bridges */ - sandpoint_find_bridges(); - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - printk("Motorola SPS Sandpoint Test Platform\n"); - printk("Sandpoint port (MontaVista Software, Inc. (source@mvista.com))\n"); - - /* The Sandpoint rom doesn't enable any caches. Do that now. - * The 7450 portion will also set up the L3s once I get enough - * information do do so. If the processor running doesn't have - * and L2, the _set_L2CR is a no-op. - */ - if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPEC7450) { - /* Just enable L2, the bits are different from others. - */ - _set_L2CR(L2CR_L2E); - } - else { - /* The magic number for Sandpoint/74xx PrPMCs. - */ - _set_L2CR(0xbd014000); - } -} - -#define SANDPOINT_87308_CFG_ADDR 0x15c -#define SANDPOINT_87308_CFG_DATA 0x15d - -#define SANDPOINT_87308_CFG_INB(addr, byte) { \ - outb((addr), SANDPOINT_87308_CFG_ADDR); \ - (byte) = inb(SANDPOINT_87308_CFG_DATA); \ -} - -#define SANDPOINT_87308_CFG_OUTB(addr, byte) { \ - outb((addr), SANDPOINT_87308_CFG_ADDR); \ - outb((byte), SANDPOINT_87308_CFG_DATA); \ -} - -#define SANDPOINT_87308_SELECT_DEV(dev_num) { \ - SANDPOINT_87308_CFG_OUTB(0x07, (dev_num)); \ -} - -#define SANDPOINT_87308_DEV_ENABLE(dev_num) { \ - SANDPOINT_87308_SELECT_DEV(dev_num); \ - SANDPOINT_87308_CFG_OUTB(0x30, 0x01); \ -} - -/* - * Initialize the ISA devices on the Nat'l PC87308VUL SuperIO chip. - */ -static void __init -sandpoint_setup_natl_87308(void) -{ - u_char reg; - - /* - * Enable all the devices on the Super I/O chip. - */ - SANDPOINT_87308_SELECT_DEV(0x00); /* Select kbd logical device */ - SANDPOINT_87308_CFG_OUTB(0xf0, 0x00); /* Set KBC clock to 8 Mhz */ - SANDPOINT_87308_DEV_ENABLE(0x00); /* Enable keyboard */ - SANDPOINT_87308_DEV_ENABLE(0x01); /* Enable mouse */ - SANDPOINT_87308_DEV_ENABLE(0x02); /* Enable rtc */ - SANDPOINT_87308_DEV_ENABLE(0x03); /* Enable fdc (floppy) */ - SANDPOINT_87308_DEV_ENABLE(0x04); /* Enable parallel */ - SANDPOINT_87308_DEV_ENABLE(0x05); /* Enable UART 2 */ - SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ - SANDPOINT_87308_DEV_ENABLE(0x06); /* Enable UART 1 */ - SANDPOINT_87308_CFG_OUTB(0xf0, 0x82); /* Enable bank select regs */ - - /* Set up floppy in PS/2 mode */ - outb(0x09, SIO_CONFIG_RA); - reg = inb(SIO_CONFIG_RD); - reg = (reg & 0x3F) | 0x40; - outb(reg, SIO_CONFIG_RD); - outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ - - return; -} - -/* - * Fix IDE interrupts. - */ -static void __init -sandpoint_fix_winbond_83553(void) -{ - /* Make all 8259 interrupt level sensitive */ - outb(0xf8, 0x4d0); - outb(0xde, 0x4d1); - - return; -} - -static void __init -sandpoint_init2(void) -{ - /* Do Sandpoint board specific initialization. */ - sandpoint_fix_winbond_83553(); - sandpoint_setup_natl_87308(); - - request_region(0x00,0x20,"dma1"); - request_region(0x20,0x20,"pic1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xa0,0x20,"pic2"); - request_region(0xc0,0x20,"dma2"); - - return; -} - -/* - * Interrupt setup and service. Interrrupts on the Sandpoint come - * from the four PCI slots plus the 8259 in the Winbond Super I/O (SIO). - * These interrupts are sent to one of four IRQs on the EPIC. - * The SIO shares its interrupt with either slot 2 or slot 3 (INTA#). - * Slot numbering is confusing. Sometimes in the documentation they - * use 0,1,2,3 and others 1,2,3,4. We will use slots 1,2,3,4 and - * map this to IRQ 16, 17, 18, 19. - * For Sandpoint X3, this has been better designed. The 8259 is - * cascaded from EPIC IRQ0, IRQ1-4 map to PCI slots 1-4, IDE is on - * EPIC 7 and 8. - */ -static void __init -sandpoint_init_IRQ(void) -{ - int i; - - /* - * 3 things cause us to jump through some hoops: - * 1) the EPIC on the 8240 & 107 are not full-blown openpic pic's - * 2) the 8259 is NOT cascaded on the openpic IRQ 0 - * 3) the 8259 shares its interrupt line with some PCI interrupts. - * - * What we'll do is set up the 8259 to be level sensitive, active low - * just like a PCI device. Then, when an interrupt on the IRQ that is - * shared with the 8259 comes in, we'll take a peek at the 8259 to see - * it its generating an interrupt. If it is, we'll handle the 8259 - * interrupt. Otherwise, we'll handle it just like a normal PCI - * interrupt. This does give the 8259 interrupts a higher priority - * than the EPIC ones--hopefully, not a problem. - */ - OpenPIC_InitSenses = sandpoint_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(sandpoint_openpic_initsenses); - - openpic_init(1, 0, NULL, -1); - - /* - * openpic_init() has set up irq_desc[0-23] to be openpic - * interrupts. We need to set irq_desc[0-15] to be 8259 interrupts. - * We then need to request and enable the 8259 irq. - */ - for(i=0; i < NUM_8259_INTERRUPTS; i++) - irq_desc[i].handler = &i8259_pic; - - if (request_irq(SANDPOINT_SIO_IRQ, no_action, SA_INTERRUPT, - "8259 cascade to EPIC", NULL)) { - - printk("Unable to get OpenPIC IRQ %d for cascade\n", - SANDPOINT_SIO_IRQ); - } - - i8259_init(NULL); -} - -static int -sandpoint_get_irq(struct pt_regs *regs) -{ - int irq, cascade_irq; - - irq = openpic_irq(); - - if (irq == SANDPOINT_SIO_IRQ) { - cascade_irq = i8259_irq(regs); - - if (cascade_irq != -1) { - irq = cascade_irq; - openpic_eoi(); - } - } - else if (irq == OPENPIC_VEC_SPURIOUS) { - irq = -1; - } - - return irq; -} - -static u32 -sandpoint_irq_canonicalize(u32 irq) -{ - if (irq == 2) - { - return 9; - } - else - { - return irq; - } -} - -static ulong __init -sandpoint_find_end_of_memory(void) -{ - ulong size = 0; - -#if 0 /* Leave out until DINK sets mem ctlr correctly */ - size = mpc10x_get_mem_size(MPC10X_MEM_MAP_B); -#else - size = 32*1024*1024; -#endif - - return size; -} - -static void __init -sandpoint_map_io(void) -{ - io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); -} - -/* - * Due to Sandpoint X2 errata, the Port 92 will not work. - */ -static void -sandpoint_restart(char *cmd) -{ - local_irq_disable(); - - /* Set exception prefix high - to the firmware */ - _nmask_and_or_msr(0, MSR_IP); - - /* Reset system via Port 92 */ - outb(0x00, 0x92); - outb(0x01, 0x92); - for(;;); /* Spin until reset happens */ -} - -static void -sandpoint_power_off(void) -{ - local_irq_disable(); - for(;;); /* No way to shut power off with software */ - /* NOTREACHED */ -} - -static void -sandpoint_halt(void) -{ - sandpoint_power_off(); - /* NOTREACHED */ -} - -static int -sandpoint_show_cpuinfo(struct seq_file *m) -{ - uint pvid; - - pvid = mfspr(PVR); - - seq_printf(m, "vendor\t\t: Motorola SPS\n"); - seq_printf(m, "machine\t\t: Sandpoint\n"); - seq_printf(m, "processor\t: PVID: 0x%x, vendor: %s\n", - pvid, (pvid & (1<<15) ? "IBM" : "Motorola")); - - return 0; -} - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* - * IDE support. - */ -static int sandpoint_ide_ports_known = 0; -static unsigned long sandpoint_ide_regbase[MAX_HWIFS]; -static unsigned long sandpoint_ide_ctl_regbase[MAX_HWIFS]; -static unsigned long sandpoint_idedma_regbase; - -static void -sandpoint_ide_probe(void) -{ - struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, - PCI_DEVICE_ID_WINBOND_82C105, - NULL); - - if(pdev) { - sandpoint_ide_regbase[0]=pdev->resource[0].start; - sandpoint_ide_regbase[1]=pdev->resource[2].start; - sandpoint_ide_ctl_regbase[0]=pdev->resource[1].start; - sandpoint_ide_ctl_regbase[1]=pdev->resource[3].start; - sandpoint_idedma_regbase=pdev->resource[4].start; - } - - sandpoint_ide_ports_known = 1; - return; -} - -static int -sandpoint_ide_default_irq(unsigned long base) -{ - if (sandpoint_ide_ports_known == 0) - sandpoint_ide_probe(); - - if (base == sandpoint_ide_regbase[0]) - return SANDPOINT_IDE_INT0; - else if (base == sandpoint_ide_regbase[1]) - return SANDPOINT_IDE_INT1; - else - return 0; -} - -static unsigned long -sandpoint_ide_default_io_base(int index) -{ - if (sandpoint_ide_ports_known == 0) - sandpoint_ide_probe(); - - return sandpoint_ide_regbase[index]; -} - -static void __init -sandpoint_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long reg = data_port; - uint alt_status_base; - int i; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg++; - } - - if (data_port == sandpoint_ide_regbase[0]) { - alt_status_base = sandpoint_ide_ctl_regbase[0] + 2; - hw->irq = 14; - } - else if (data_port == sandpoint_ide_regbase[1]) { - alt_status_base = sandpoint_ide_ctl_regbase[1] + 2; - hw->irq = 15; - } - else { - alt_status_base = 0; - hw->irq = 0; - } - - if (ctrl_port) { - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - } else { - hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base; - } - - if (irq != NULL) { - *irq = hw->irq; - } - - return; -} -#endif - -/* - * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1. - */ -static __inline__ void -sandpoint_set_bat(void) -{ - unsigned long bat3u, bat3l; - static int mapping_set = 0; - - if (!mapping_set) { - - __asm__ __volatile__( - " lis %0,0xf800\n \ - ori %1,%0,0x002a\n \ - ori %0,%0,0x0ffe\n \ - mtspr 0x21e,%0\n \ - mtspr 0x21f,%1\n \ - isync\n \ - sync " - : "=r" (bat3u), "=r" (bat3l)); - - mapping_set = 1; - } - - return; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -static void -sandpoint_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = rs_table[0].port; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - if (c == '\n') { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - } - } -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -__init void sandpoint_setup_pci_ptrs(void); - -TODC_ALLOC(); - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - parse_bootinfo(find_bootinfo()); - - /* Map in board regs, etc. */ - sandpoint_set_bat(); - - isa_io_base = MPC10X_MAPB_ISA_IO_BASE; - isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; - pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; - ISA_DMA_THRESHOLD = 0x00ffffff; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - - ppc_md.setup_arch = sandpoint_setup_arch; - ppc_md.show_cpuinfo = sandpoint_show_cpuinfo; - ppc_md.irq_canonicalize = sandpoint_irq_canonicalize; - ppc_md.init_IRQ = sandpoint_init_IRQ; - ppc_md.get_irq = sandpoint_get_irq; - ppc_md.init = sandpoint_init2; - - ppc_md.restart = sandpoint_restart; - ppc_md.power_off = sandpoint_power_off; - ppc_md.halt = sandpoint_halt; - - ppc_md.find_end_of_memory = sandpoint_find_end_of_memory; - ppc_md.setup_io_mappings = sandpoint_map_io; - - TODC_INIT(TODC_TYPE_PC97307, 0x70, 0x00, 0x71, 8); - ppc_md.time_init = todc_time_init; - ppc_md.set_rtc_time = todc_set_rtc_time; - ppc_md.get_rtc_time = todc_get_rtc_time; - ppc_md.calibrate_decr = todc_calibrate_decr; - - ppc_md.nvram_read_val = todc_mc146818_read_val; - ppc_md.nvram_write_val = todc_mc146818_write_val; - - ppc_md.heartbeat = NULL; - ppc_md.heartbeat_reset = 0; - ppc_md.heartbeat_count = 0; - -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = sandpoint_progress; -#else /* !CONFIG_SERIAL_TEXT_DEBUG */ - ppc_md.progress = NULL; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) - ppc_ide_md.default_irq = sandpoint_ide_default_irq; - ppc_ide_md.default_io_base = sandpoint_ide_default_io_base; - ppc_ide_md.ide_init_hwif = sandpoint_ide_init_hwif_ports; -#endif - - return; -} diff --git a/arch/ppc/platforms/zx4500.h b/arch/ppc/platforms/zx4500.h deleted file mode 100644 index 8a26e691e94..00000000000 --- a/arch/ppc/platforms/zx4500.h +++ /dev/null @@ -1,68 +0,0 @@ -/* * arch/ppc/platforms/zx4500.h - * - * Board setup routines for Znyx ZX4500 cPCI board. - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#ifndef __PPC_PLATFORMS_ZX4500_H_ -#define __PPC_PLATFORMS_ZX4500_H_ - -/* - * Define the addresses of CPLD registers in CLPD area. - */ -#define ZX4500_CPLD_BOARD_ID 0xff800001 -#define ZX4500_CPLD_REV 0xff800002 -#define ZX4500_CPLD_RESET 0xff800011 -#define ZX4500_CPLD_PHY1 0xff800014 -#define ZX4500_CPLD_PHY2 0xff800015 -#define ZX4500_CPLD_PHY3 0xff800016 -#define ZX4500_CPLD_SYSCTL 0xff800017 -#define ZX4500_CPLD_EXT_FLASH 0xff800018 -#define ZX4500_CPLD_DUAL1 0xff800019 -#define ZX4500_CPLD_DUAL2 0xff80001A -#define ZX4500_CPLD_STATUS 0xff800030 -#define ZX4500_CPLD_STREAM 0xff800032 -#define ZX4500_CPLD_PHY1_LED 0xff800034 -#define ZX4500_CPLD_PHY2_LED 0xff800035 -#define ZX4500_CPLD_PHY3_LED 0xff800036 -#define ZX4500_CPLD_PHY1_LNK 0xff80003C -#define ZX4500_CPLD_PHY2_LNK 0xff80003D -#define ZX4500_CPLD_PHY3_LNK 0xff80003E - -#define ZX4500_CPLD_RESET_SOFT 0x01 /* Soft Reset */ -#define ZX4500_CPLD_RESET_XBUS 0x40 /* Reset entire board */ - -#define ZX4500_CPLD_SYSCTL_PMC 0x01 /* Enable INTA/B/C/D from PMC */ -#define ZX4500_CPLD_SYSCTL_BCM 0x04 /* Enable INTA from BCM */ -#define ZX4500_CPLD_SYSCTL_SINTA 0x08 /* Enable SINTA from 21554 */ -#define ZX4500_CPLD_SYSCTL_WD 0x20 /* Enable Watchdog Timer */ -#define ZX4500_CPLD_SYSCTL_PMC_TRI 0x80 /* Tri-state PMC EREADY */ - -#define ZX4500_CPLD_DUAL2_LED_PULL 0x01 /* Pull LED */ -#define ZX4500_CPLD_DUAL2_LED_EXT_FAULT 0x02 /* External Fault LED */ -#define ZX4500_CPLD_DUAL2_LED_INT_FAULT 0x04 /* Internal Fault LED */ -#define ZX4500_CPLD_DUAL2_LED_OK 0x08 /* OK LED */ -#define ZX4500_CPLD_DUAL2_LED_CLK 0x10 /* CLK LED */ - -/* - * Defines related to boot string stored in flash. - */ -#define ZX4500_BOOT_STRING_ADDR 0xfff7f000 -#define ZX4500_BOOT_STRING_LEN 80 - -/* - * Define the IDSEL that the PCI bus side of the 8240 is connected to. - * This IDSEL must not be selected from the 8240 processor side. - */ -#define ZX4500_HOST_BRIDGE_IDSEL 20 - - -void zx4500_find_bridges(void); - -#endif /* __PPC_PLATFORMS_ZX4500_H_ */ diff --git a/arch/ppc/platforms/zx4500_pci.c b/arch/ppc/platforms/zx4500_pci.c deleted file mode 100644 index 325ecfe31c9..00000000000 --- a/arch/ppc/platforms/zx4500_pci.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * arch/ppc/platforms/zx4500_pci.c - * - * PCI setup routines for Znyx ZX4500 cPCI boards. - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "zx4500.h" - -/* - * Znyx ZX4500 interrupt routes. - */ -static inline int -zx4500_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) -{ - static char pci_irq_table[][4] = - /* - * PCI IDSEL/INTPIN->INTLINE - * A B C D - */ - { - { 19, 0, 0, 0 }, /* IDSEL 21 - 21554 PCI-cPCI bridge */ - { 18, 0, 0, 0 }, /* IDSEL 22 - BCM5600 INTA */ - { 16, 20, 16, 20 }, /* IDSEL 23 - PPMC Slot */ - }; - - const long min_idsel = 21, max_idsel = 23, irqs_per_slot = 4; - return PCI_IRQ_TABLE_LOOKUP; -} - -void __init -zx4500_board_init(struct pci_controller *hose) -{ - uint val; - u_char sysctl; - - /* - * CPLD Registers are mapped in by BAT 3 in zx4500_setup_arch(). - * - * Turn off all interrupts routed through the CPLD. - * Also, turn off watchdog timer and drive PMC EREADY low. - */ - sysctl = in_8((volatile u_char *)ZX4500_CPLD_SYSCTL); - sysctl &= ~(ZX4500_CPLD_SYSCTL_PMC | - ZX4500_CPLD_SYSCTL_BCM | - ZX4500_CPLD_SYSCTL_SINTA | - ZX4500_CPLD_SYSCTL_WD | - ZX4500_CPLD_SYSCTL_PMC_TRI); - out_8((volatile u_char *)ZX4500_CPLD_SYSCTL, sysctl); - - /* - * Kludge the size that BAR2 of the 21554 asks for - * (i.e., set Upstream I/O or Memory 0 Setup Register). - * Old versions of SROM wants 1 GB which is too large, make it ask - * for 256 MB. - */ - early_read_config_dword(hose, 0, PCI_DEVFN(21,0), 0xc4, &val); - - if (val != 0) { - early_write_config_dword(hose, - 0, - PCI_DEVFN(21,0), - 0xc4, - val | 0xf0000000); - } - - return; -} - -static int -zx4500_exclude_device(u_char bus, u_char devfn) -{ - if ((bus == 0) && (PCI_SLOT(devfn) == ZX4500_HOST_BRIDGE_IDSEL)) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - else { - return PCIBIOS_SUCCESSFUL; - } -} - -void __init -zx4500_find_bridges(void) -{ - struct pci_controller *hose; - - hose = pcibios_alloc_controller(); - - if (!hose) - return; - - hose->first_busno = 0; - hose->last_busno = 0xff; - - if (mpc10x_bridge_init(hose, - MPC10X_MEM_MAP_B, - MPC10X_MEM_MAP_B, - MPC10X_MAPB_EUMB_BASE) == 0) { - - hose->mem_resources[0].end = 0xffffffff; - - /* Initialize the board */ - zx4500_board_init(hose); - - /* scan PCI bus */ - ppc_md.pci_exclude_device = zx4500_exclude_device; - hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); - - ppc_md.pcibios_fixup = NULL; - ppc_md.pcibios_fixup_bus = NULL; - ppc_md.pci_swizzle = common_swizzle; - ppc_md.pci_map_irq = zx4500_map_irq; - } - else { - if (ppc_md.progress) - ppc_md.progress("Bridge init failed", 0x100); - printk("Host bridge init failed\n"); - } - - return; -} diff --git a/arch/ppc/platforms/zx4500_serial.h b/arch/ppc/platforms/zx4500_serial.h deleted file mode 100644 index e1f8c70337b..00000000000 --- a/arch/ppc/platforms/zx4500_serial.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * arch/ppc/platforms/zx4500_serial.h - * - * Definitions for Znyx ZX4500 board support - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __ASMPPC_ZX4500_SERIAL_H -#define __ASMPPC_ZX4500_SERIAL_H - -#include - -/* Define the UART base address (only 1 UART) */ -#define ZX4500_SERIAL_1 0xff880000 - -#ifdef CONFIG_SERIAL_MANY_PORTS -#define RS_TABLE_SIZE 64 -#else -#define RS_TABLE_SIZE 1 -#endif - -/* Rate for the 1.8432 Mhz clock for the onboard serial chip */ -#define BASE_BAUD ( 1843200 / 16 ) - -#ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) -#else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) -#endif - -#define STD_SERIAL_PORT_DFNS \ - { 0, BASE_BAUD, ZX4500_SERIAL_1, 17, STD_COM_FLAGS, /* ttyS0 */ \ - iomem_base: (u8 *)ZX4500_SERIAL_1, \ - io_type: SERIAL_IO_MEM }, - -#define SERIAL_PORT_DFNS \ - STD_SERIAL_PORT_DFNS - -#endif /* __ASMPPC_ZX4500_SERIAL_H */ diff --git a/arch/ppc/platforms/zx4500_setup.c b/arch/ppc/platforms/zx4500_setup.c deleted file mode 100644 index 7a71b270956..00000000000 --- a/arch/ppc/platforms/zx4500_setup.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * arch/ppc/platforms/zx4500_setup.c - * - * Board setup routines for Znyx ZX4500 family of cPCI boards. - * - * Author: Mark A. Greer - * mgreer@mvista.com - * - * 2000-2001 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -/* - * This file adds support for the Znyx ZX4500 series of cPCI boards. - * These boards have an 8240, UART on the processor bus, a PPMC slot (for now - * the card in this slot can _not_ be a monarch), Broadcom BCM5600, and an - * Intel 21554 bridge. - * - * Currently, this port assumes that the 8240 is the master and performs PCI - * arbitration, etc. It is also assumed that the 8240 is wired to come up - * using memory MAP B (CHRP map). - * - * Note: This board port will not work properly as it is. You must apply the - * patch that is at ftp://ftp.mvista.com/pub/Area51/zx4500/zx_patch_2_5 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "zx4500.h" - -static u_char zx4500_openpic_initsenses[] __initdata = { - 0, /* 0-15 are not used on an 8240 EPIC */ - 0, /* 1 */ - 0, /* 2 */ - 0, /* 3 */ - 0, /* 4 */ - 0, /* 5 */ - 0, /* 6 */ - 0, /* 7 */ - 0, /* 8 */ - 0, /* 9 */ - 0, /* 10 */ - 0, /* 11 */ - 0, /* 12 */ - 0, /* 13 */ - 0, /* 14 */ - 0, /* 15 */ - 1, /* 16: EPIC IRQ 0: Active Low -- PMC #INTA & #INTC */ - 1, /* 17: EPIC IRQ 1: Active Low -- UART */ - 1, /* 18: EPIC IRQ 2: Active Low -- BCM5600 #INTA */ - 1, /* 19: EPIC IRQ 3: Active Low -- 21554 #SINTA */ - 1, /* 20: EPIC IRQ 4: Active Low -- PMC #INTB & #INTD */ -}; - - -static void __init -zx4500_setup_arch(void) -{ - char boot_string[ZX4500_BOOT_STRING_LEN + 1]; - char *boot_arg; - extern char cmd_line[]; - - - loops_per_jiffy = 50000000 / HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif -#if defined(CONFIG_ROOT_NFS) - ROOT_DEV = Root_NFS; -#else - ROOT_DEV = Root_SDA1; -#endif - - /* Get boot string from flash */ - strlcpy(boot_string, - (char *)ZX4500_BOOT_STRING_ADDR, - sizeof(boot_string)); - boot_string[ZX4500_BOOT_STRING_LEN] = '\0'; - - /* Can be delimited by 0xff */ - boot_arg = strchr(boot_string, 0xff); - - if (boot_arg != NULL) { - *boot_arg = '\0'; - } - - /* First 3 chars must be 'dev'. If not, ignore. */ - if (!strncmp(boot_string, "dev", 3)) { - /* skip 'dev?' and any blanks after it */ - boot_arg = strchr(boot_string, ' '); - - if (boot_arg != NULL) { - while (*boot_arg == ' ') boot_arg++; - strcat(cmd_line, " "); - strcat(cmd_line, boot_arg); - } - } - - /* nothing but serial consoles... */ - printk("Znyx ZX4500 Series High Performance Switch\n"); - printk("ZX4500 port (C) 2000, 2001 MontaVista Software, Inc. (source@mvista.com)\n"); - - /* Lookup PCI host bridge */ - zx4500_find_bridges(); - - printk("ZX4500 Board ID: 0x%x, Revision #: 0x%x\n", - in_8((volatile u_char *)ZX4500_CPLD_BOARD_ID), - in_8((volatile u_char *)ZX4500_CPLD_REV)); - - return; -} - -static ulong __init -zx4500_find_end_of_memory(void) -{ - return mpc10x_get_mem_size(MPC10X_MEM_MAP_B); -} - -static void __init -zx4500_map_io(void) -{ - io_block_mapping(0xfe000000, 0xfe000000, 0x02000000, _PAGE_IO); -} - -/* - * Enable interrupts routed thru CPLD to reach the 8240's EPIC. - * Need to enable all 4 PMC intrs, BCM INTA, and 21554 SINTA to 8240. - * UART intrs routed directly to 8240 (not thru CPLD). - */ -static void __init -zx4500_enable_cpld_intrs(void) -{ - u_char sysctl; - - sysctl = in_8((volatile u_char *)ZX4500_CPLD_SYSCTL); - sysctl |= (ZX4500_CPLD_SYSCTL_PMC | - ZX4500_CPLD_SYSCTL_BCM | - ZX4500_CPLD_SYSCTL_SINTA); - out_8((volatile u_char *)ZX4500_CPLD_SYSCTL, sysctl); - - return; -} - -static void __init -zx4500_init_IRQ(void) -{ - OpenPIC_InitSenses = zx4500_openpic_initsenses; - OpenPIC_NumInitSenses = sizeof(zx4500_openpic_initsenses); - - openpic_init(1, 0, NULL, -1); - - zx4500_enable_cpld_intrs(); /* Allow CPLD to route intrs to 8240 */ - - return; -} - -static void -zx4500_restart(char *cmd) -{ - local_irq_disable(); - - out_8((volatile u_char *)ZX4500_CPLD_RESET, ZX4500_CPLD_RESET_XBUS); - for (;;); - - panic("Restart failed.\n"); - /* NOTREACHED */ -} - -static void -zx4500_power_off(void) -{ - local_irq_disable(); - for(;;); /* No way to shut power off with software */ - /* NOTREACHED */ -} - -static void -zx4500_halt(void) -{ - zx4500_power_off(); - /* NOTREACHED */ -} - -static int -zx4500_get_bus_speed(void) -{ - int bus_speed; - - bus_speed = 100000000; - - return bus_speed; -} - -static int -zx4500_show_cpuinfo(struct seq_file *m) -{ - uint pvid; - - seq_printf(m, "vendor\t\t: Znyx\n"); - seq_printf(m, "machine\t\t: ZX4500\n"); - seq_printf(m, "processor\t: PVID: 0x%x, vendor: %s\n", - pvid, (pvid & (1<<15) ? "IBM" : "Motorola")); - seq_printf(m, "bus speed\t: %dMhz\n", - zx4500_get_bus_speed()/1000000); - - return 0; -} - -static void __init -zx4500_calibrate_decr(void) -{ - ulong freq; - - freq = zx4500_get_bus_speed() / 4; - - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - freq/1000000, freq%1000000); - - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); - - return; -} - -/* - * Set BAT 3 to map 0xf0000000 to end of physical memory space 1-1. - */ -static __inline__ void -zx4500_set_bat(void) -{ - unsigned long bat3u, bat3l; - static int mapping_set = 0; - - if (!mapping_set) { - - __asm__ __volatile__( - " lis %0,0xf800\n \ - ori %1,%0,0x002a\n \ - ori %0,%0,0x0ffe\n \ - mtspr 0x21e,%0\n \ - mtspr 0x21f,%1\n \ - isync\n \ - sync " - : "=r" (bat3u), "=r" (bat3l)); - - mapping_set = 1; - } - - return; -} - -#ifdef CONFIG_SERIAL_TEXT_DEBUG -#include -#include -#include - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in */ -}; - -void -zx4500_progress(char *s, unsigned short hex) -{ - volatile char c; - volatile unsigned long com_port; - u16 shift; - - com_port = rs_table[0].port; - shift = rs_table[0].iomem_reg_shift; - - while ((c = *s++) != 0) { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = c; - - if (c == '\n') { - while ((*((volatile unsigned char *)com_port + - (UART_LSR << shift)) & UART_LSR_THRE) == 0) - ; - *(volatile unsigned char *)com_port = '\r'; - } - } -} -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - parse_bootinfo(find_bootinfo()); - - /* Map in board registers, etc. */ - zx4500_set_bat(); - - isa_io_base = MPC10X_MAPB_ISA_IO_BASE; - isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE; - pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET; - - ppc_md.setup_arch = zx4500_setup_arch; - ppc_md.show_cpuinfo = zx4500_show_cpuinfo; - ppc_md.irq_canonicalize = NULL; - ppc_md.init_IRQ = zx4500_init_IRQ; - ppc_md.get_irq = openpic_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = zx4500_restart; - ppc_md.power_off = zx4500_power_off; - ppc_md.halt = zx4500_halt; - - ppc_md.find_end_of_memory = zx4500_find_end_of_memory; - ppc_md.setup_io_mappings = zx4500_map_io; - - ppc_md.calibrate_decr = zx4500_calibrate_decr; - - ppc_md.heartbeat = NULL; - ppc_md.heartbeat_reset = 0; - ppc_md.heartbeat_count = 0; - -#ifdef CONFIG_SERIAL_TEXT_DEBUG - ppc_md.progress = zx4500_progress; -#else /* !CONFIG_SERIAL_TEXT_DEBUG */ - ppc_md.progress = NULL; -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - - return; -} diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 62bb56c8e6c..9fd63b6030a 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -61,8 +61,9 @@ obj-$(CONFIG_SANDPOINT) += i8259.o open_pic.o mpc10x_common.o \ pci_auto.o indirect_pci.o todc_time.o obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \ todc_time.o -obj-$(CONFIG_ZX4500) += indirect_pci.o pci_auto.o mpc10x_common.o \ - i8259.o open_pic.o obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o +ifeq ($(CONFIG_SERIAL_8250)$(CONFIG_PPC_GEN550),yy) +obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o +obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o +endif obj-$(CONFIG_BOOTX_TEXT) += btext.o - diff --git a/arch/ppc/syslib/gen550_dbg.c b/arch/ppc/syslib/gen550_dbg.c new file mode 100644 index 00000000000..7fb0b41a241 --- /dev/null +++ b/arch/ppc/syslib/gen550_dbg.c @@ -0,0 +1,174 @@ +/* + * arch/ppc/syslib/gen550_dbg.c + * + * A library of polled 16550 serial routines. These are intended to + * be used to support progress messages, xmon, kgdb, etc. on a + * variety of platforms. + * + * Adapted from lots of code ripped from the arch/ppc/boot/ polled + * 16550 support. + * + * Author: Matt Porter + * + * 2002-2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include /* For linux/serial_core.h */ +#include +#include +#include +#include +#include +#include + +#define SERIAL_BAUD 9600 + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* defined in */ +}; + +static void (*serial_outb)(unsigned long, unsigned char); +static unsigned long (*serial_inb)(unsigned long); + +static int shift; + +unsigned long direct_inb(unsigned long addr) +{ + return readb(addr); +} + +void direct_outb(unsigned long addr, unsigned char val) +{ + writeb(val, addr); +} + +unsigned long io_inb(unsigned long port) +{ + return inb(port); +} + +void io_outb(unsigned long port, unsigned char val) +{ + outb(val, port); +} + +unsigned long serial_init(int chan, void *ignored) +{ + unsigned long com_port; + unsigned char lcr, dlm; + + /* We need to find out which type io we're expecting. If it's + * 'SERIAL_IO_PORT', we get an offset from the isa_io_base. + * If it's 'SERIAL_IO_MEM', we can the exact location. -- Tom */ + switch (rs_table[chan].io_type) { + case SERIAL_IO_PORT: + com_port = rs_table[chan].port; + serial_outb = io_outb; + serial_inb = io_inb; + break; + case SERIAL_IO_MEM: + com_port = (unsigned long)rs_table[chan].iomem_base; + serial_outb = direct_outb; + serial_inb = direct_inb; + break; + default: + /* We can't deal with it. */ + return -1; + } + + /* How far apart the registers are. */ + shift = rs_table[chan].iomem_reg_shift; + + /* save the LCR */ + lcr = serial_inb(com_port + (UART_LCR << shift)); + + /* Access baud rate */ + serial_outb(com_port + (UART_LCR << shift), UART_LCR_DLAB); + dlm = serial_inb(com_port + (UART_DLM << shift)); + + /* + * Test if serial port is unconfigured + * We assume that no-one uses less than 110 baud or + * less than 7 bits per character these days. + * -- paulus. + */ + if ((dlm <= 4) && (lcr & 2)) { + /* port is configured, put the old LCR back */ + serial_outb(com_port + (UART_LCR << shift), lcr); + } + else { + /* Input clock. */ + serial_outb(com_port + (UART_DLL << shift), + (rs_table[chan].baud_base / SERIAL_BAUD) & 0xFF); + serial_outb(com_port + (UART_DLM << shift), + (rs_table[chan].baud_base / SERIAL_BAUD) >> 8); + /* 8 data, 1 stop, no parity */ + serial_outb(com_port + (UART_LCR << shift), 0x03); + /* RTS/DTR */ + serial_outb(com_port + (UART_MCR << shift), 0x03); + + /* Clear & enable FIFOs */ + serial_outb(com_port + (UART_FCR << shift), 0x07); + } + + return (com_port); +} + +void +serial_putc(unsigned long com_port, unsigned char c) +{ + while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0) + ; + serial_outb(com_port, c); +} + +unsigned char +serial_getc(unsigned long com_port) +{ + while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0) + ; + return serial_inb(com_port); +} + +int +serial_tstc(unsigned long com_port) +{ + return ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0); +} + +void +serial_close(unsigned long com_port) +{ +} + +void +gen550_init(int i, struct uart_port *serial_req) +{ + rs_table[i].io_type = serial_req->iotype; + rs_table[i].port = serial_req->line; + rs_table[i].iomem_base = serial_req->membase; + rs_table[i].iomem_reg_shift = serial_req->regshift; +} + +#ifdef CONFIG_SERIAL_TEXT_DEBUG +void +gen550_progress(char *s, unsigned short hex) +{ + volatile unsigned int progress_debugport; + volatile char c; + + progress_debugport = serial_init(0, NULL); + + serial_putc(progress_debugport, '\r'); + + while ((c = *s++) != 0) + serial_putc(progress_debugport, c); + + serial_putc(progress_debugport, '\n'); + serial_putc(progress_debugport, '\r'); +} +#endif /* CONFIG_SERIAL_TEXT_DEBUG */ diff --git a/arch/ppc/syslib/gen550_kgdb.c b/arch/ppc/syslib/gen550_kgdb.c new file mode 100644 index 00000000000..93b374f25dc --- /dev/null +++ b/arch/ppc/syslib/gen550_kgdb.c @@ -0,0 +1,84 @@ +/* + * arch/ppc/syslib/gen550_kgdb.c + * + * Generic 16550 kgdb support intended to be useful on a variety + * of platforms. To enable this support, it is necessary to set + * the CONFIG_GEN550 option. Any virtual mapping of the serial + * port(s) to be used can be accomplished by setting + * ppc_md.early_serial_map to a platform-specific mapping function. + * + * Adapted from ppc4xx_kgdb.c. + * + * Author: Matt Porter + * + * 2002-2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include + +#include + +extern unsigned long serial_init(int, void *); +extern unsigned long serial_getc(unsigned long); +extern unsigned long serial_putc(unsigned long, unsigned char); + +#if defined(CONFIG_KGDB_TTYS0) +#define KGDB_PORT 0 +#elif defined(CONFIG_KGDB_TTYS1) +#define KGDB_PORT 1 +#elif defined(CONFIG_KGDB_TTYS2) +#define KGDB_PORT 2 +#elif defined(CONFIG_KGDB_TTYS3) +#define KGDB_PORT 3 +#else +#error "invalid kgdb_tty port" +#endif + +static volatile unsigned int kgdb_debugport; + +void putDebugChar(unsigned char c) +{ + if (kgdb_debugport == 0) + kgdb_debugport = serial_init(KGDB_PORT, NULL); + + serial_putc(kgdb_debugport, c); +} + +int getDebugChar(void) +{ + if (kgdb_debugport == 0) + kgdb_debugport = serial_init(KGDB_PORT, NULL); + + return(serial_getc(kgdb_debugport)); +} + +void kgdb_interruptible(int enable) +{ + return; +} + +void putDebugString(char* str) +{ + while (*str != '\0') { + putDebugChar(*str); + str++; + } + putDebugChar('\r'); + return; +} + +/* + * Note: gen550_init() must be called already on the port we are going + * to use. + */ +void +kgdb_map_scc(void) +{ + printk(KERN_DEBUG "kgdb init\n"); + kgdb_debugport = serial_init(KGDB_PORT, NULL); +} diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 9c292607e4a..dbbc9d6ecd0 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -33,6 +33,7 @@ void* OpenPIC_Addr; static volatile struct OpenPIC *OpenPIC = NULL; + /* * We define OpenPIC_InitSenses table thusly: * bit 0x1: sense, 0 for edge and 1 for level. @@ -261,32 +262,32 @@ static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int } #endif /* CONFIG_SMP */ -#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK) -static void openpic_reset(void) +#ifdef CONFIG_EPIC_SERIAL_MODE +static void __init openpic_eicr_set_clk(u_int clkval) { - openpic_setfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_RESET); - while (openpic_readfield(&OpenPIC->Global.Global_Configuration0, - OPENPIC_CONFIG_RESET)) - mb(); + openpic_writefield(&OpenPIC->Global.Global_Configuration1, + OPENPIC_EICR_S_CLK_MASK, (clkval << 28)); } -#endif -#ifdef CONFIG_EPIC_SERIAL_MODE -static void openpic_enable_sie(void) +static void __init openpic_enable_sie(void) { openpic_setfield(&OpenPIC->Global.Global_Configuration1, - OPENPIC_EICR_SIE); + OPENPIC_EICR_SIE); } +#endif -static void openpic_eicr_set_clk(u_int clkval) +#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK) +static void openpic_reset(void) { - openpic_writefield(&OpenPIC->Global.Global_Configuration1, - OPENPIC_EICR_S_CLK_MASK, (clkval << 28)); + openpic_setfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET); + while (openpic_readfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET)) + mb(); } #endif -void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR) +void __init openpic_set_sources(int first_irq, int num_irqs, void *first_ISR) { volatile OpenPIC_Source *src = first_ISR; int i, last_irq; @@ -300,7 +301,14 @@ void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR) ISR[i] = src; } -void __init openpic_init(int linux_irq_offset) +/* + * The `offset' parameter defines where the interrupts handled by the + * OpenPIC start in the space of interrupt numbers that the kernel knows + * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the + * kernel's interrupt numbering scheme. + * We assume there is only one OpenPIC. + */ +void __init openpic_init(int offset) { u_int t, i; u_int timerfreq; @@ -349,13 +357,13 @@ void __init openpic_init(int linux_irq_offset) printk("OpenPIC timer frequency is %d.%06d MHz\n", timerfreq / 1000000, timerfreq % 1000000); - open_pic_irq_offset = linux_irq_offset; + open_pic_irq_offset = offset; /* Initialize timer interrupts */ if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba); for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+linux_irq_offset); + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset); /* No processor */ openpic_maptimer(i, 0); } @@ -365,12 +373,10 @@ void __init openpic_init(int linux_irq_offset) if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb); for (i = 0; i < OPENPIC_NUM_IPI; i++) { /* Disabled, Priority 10..13 */ - openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+linux_irq_offset); + openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset); /* IPIs are per-CPU */ - irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].status |= - IRQ_PER_CPU; - irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].handler = - &open_pic_ipi; + irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU; + irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi; } #endif @@ -387,40 +393,36 @@ void __init openpic_init(int linux_irq_offset) continue; /* the bootloader may have left it enabled (bad !) */ - openpic_disable_irq(i+linux_irq_offset); + openpic_disable_irq(i+offset); - /* - * We find the value from either the InitSenses table - * or assume a negative polarity level interrupt. - */ - sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1; + sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE); - if ((sense & IRQ_SENSE_MASK) == 1) - irq_desc[i+linux_irq_offset].status = IRQ_LEVEL; + if (sense & IRQ_SENSE_MASK) + irq_desc[i+offset].status = IRQ_LEVEL; /* Enabled, Priority 8 */ - openpic_initirq(i, 8, i + linux_irq_offset, - (sense & IRQ_POLARITY_MASK), + openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK), (sense & IRQ_SENSE_MASK)); /* Processor 0 */ openpic_mapirq(i, 1<<0, 0); } /* Init descriptors */ - for (i = linux_irq_offset; i < NumSources + linux_irq_offset; i++) + for (i = offset; i < NumSources + offset; i++) irq_desc[i].handler = &open_pic; /* Initialize the spurious interrupt */ if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd); - openpic_set_spurious(OPENPIC_VEC_SPURIOUS+linux_irq_offset); + openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset); /* Initialize the cascade */ - if (linux_irq_offset) { - if (request_irq(linux_irq_offset, no_action, SA_INTERRUPT, + if (offset) { + if (request_irq(offset, no_action, SA_INTERRUPT, "82c59 cascade", NULL)) printk("Unable to get OpenPIC IRQ 0 for cascade\n"); } - openpic_disable_8259_pass_through(); + openpic_disable_8259_pass_through(); #ifdef CONFIG_EPIC_SERIAL_MODE openpic_eicr_set_clk(7); /* Slowest value until we know better */ openpic_enable_sie(); @@ -479,7 +481,7 @@ static u_int openpic_get_priority(void) } #endif /* notused */ -static void openpic_set_priority(u_int pri) +static void __init openpic_set_priority(u_int pri) { DECL_THIS_CPU; @@ -656,29 +658,18 @@ static void __init openpic_maptimer(u_int timer, u_int cpumask) } /* - * Initalize the interrupt source which will generate an NMI (and disable it). + * Initalize the interrupt source which will generate an NMI. + * This raises the interrupt's priority from 8 to 9. * * irq: The logical IRQ which generates an NMI. */ void __init openpic_init_nmi_irq(u_int irq) { - int sense; - - /* If this wasn't given, assume a level, negative polarity interrupt. */ - sense = (irq < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[irq] : - (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE); - - openpic_safe_writefield(&ISR[irq]->Vector_Priority, - OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | - OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, - (9 << OPENPIC_PRIORITY_SHIFT) | - (irq + open_pic_irq_offset) | - ((sense & IRQ_POLARITY_MASK) ? - OPENPIC_POLARITY_POSITIVE : - OPENPIC_POLARITY_NEGATIVE) | - ((sense & IRQ_SENSE_MASK) ? OPENPIC_SENSE_LEVEL - : OPENPIC_SENSE_EDGE)); + check_arg_irq(irq); + openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority, + OPENPIC_PRIORITY_MASK, + 9 << OPENPIC_PRIORITY_SHIFT); } /* @@ -752,7 +743,8 @@ void openpic_disable_ipi(u_int irq) * pol: polarity (1 for positive, 0 for negative) * sense: 1 for level, 0 for edge */ -static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) +static void __init +openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense) { openpic_safe_writefield(&ISR[irq]->Vector_Priority, OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | diff --git a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c index 79b716dbe6d..ca2472a9116 100644 --- a/arch/ppc64/mm/init.c +++ b/arch/ppc64/mm/init.c @@ -109,7 +109,7 @@ void show_mem(void) show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_size; i++) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { page = pgdat->node_mem_map + i; total++; if (PageReserved(page)) @@ -564,7 +564,7 @@ void __init mem_init(void) int nid; for (nid = 0; nid < numnodes; nid++) { - if (node_data[nid].node_size != 0) { + if (node_data[nid].node_spanned_pages != 0) { printk("freeing bootmem node %x\n", nid); totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); diff --git a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c index fd86d7ec826..19b4ee36ee8 100644 --- a/arch/ppc64/mm/numa.c +++ b/arch/ppc64/mm/numa.c @@ -160,21 +160,21 @@ new_range: * this simple case and complain if there is a gap in * memory */ - if (node_data[numa_domain].node_size) { + if (node_data[numa_domain].node_spanned_pages) { unsigned long shouldstart = node_data[numa_domain].node_start_pfn + - node_data[numa_domain].node_size; + node_data[numa_domain].node_spanned_pages; if (shouldstart != (start / PAGE_SIZE)) { printk(KERN_ERR "Hole in node, disabling " "region start %lx length %lx\n", start, size); continue; } - node_data[numa_domain].node_size += size / PAGE_SIZE; + node_data[numa_domain].node_spanned_pages += size / PAGE_SIZE; } else { node_data[numa_domain].node_start_pfn = start / PAGE_SIZE; - node_data[numa_domain].node_size = size / PAGE_SIZE; + node_data[numa_domain].node_spanned_pages = size / PAGE_SIZE; } for (i = start ; i < (start+size); i += MEMORY_INCREMENT) @@ -202,7 +202,7 @@ void setup_nonnuma(void) map_cpu_to_node(i, 0); node_data[0].node_start_pfn = 0; - node_data[0].node_size = lmb_end_of_DRAM() / PAGE_SIZE; + node_data[0].node_spanned_pages = lmb_end_of_DRAM() / PAGE_SIZE; for (i = 0 ; i < lmb_end_of_DRAM(); i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = 0; @@ -224,12 +224,12 @@ void __init do_init_bootmem(void) unsigned long bootmem_paddr; unsigned long bootmap_pages; - if (node_data[nid].node_size == 0) + if (node_data[nid].node_spanned_pages == 0) continue; start_paddr = node_data[nid].node_start_pfn * PAGE_SIZE; end_paddr = start_paddr + - (node_data[nid].node_size * PAGE_SIZE); + (node_data[nid].node_spanned_pages * PAGE_SIZE); dbg("node %d\n", nid); dbg("start_paddr = %lx\n", start_paddr); @@ -311,7 +311,7 @@ void __init paging_init(void) unsigned long start_pfn; unsigned long end_pfn; - if (node_data[nid].node_size == 0) + if (node_data[nid].node_spanned_pages == 0) continue; start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT; diff --git a/arch/ppc64/oprofile/init.c b/arch/ppc64/oprofile/init.c index 6bc6dc42217..d0c67f193c4 100644 --- a/arch/ppc64/oprofile/init.c +++ b/arch/ppc64/oprofile/init.c @@ -19,6 +19,6 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { } diff --git a/arch/s390/kernel/compat_exec.c b/arch/s390/kernel/compat_exec.c index 74245a64e51..33832846833 100644 --- a/arch/s390/kernel/compat_exec.c +++ b/arch/s390/kernel/compat_exec.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,7 @@ int setup_arg_pages32(struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; - if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + if (security_vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 1c43b3d4078..a4f84f8c6bc 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -107,7 +107,7 @@ void __devinit cpu_init (void) current->active_mm = &init_mm; if (current->mm) BUG(); - enter_lazy_tlb(&init_mm, current, nr); + enter_lazy_tlb(&init_mm, current); } /* diff --git a/arch/sh/kernel/cpu/sh4/pci-sh7751.c b/arch/sh/kernel/cpu/sh4/pci-sh7751.c index 365c71a4fbe..0831b1c646a 100644 --- a/arch/sh/kernel/cpu/sh4/pci-sh7751.c +++ b/arch/sh/kernel/cpu/sh4/pci-sh7751.c @@ -200,7 +200,7 @@ static void __init pcibios_fixup_peer_bridges(void) return; PCIDBG(2,"PCI: Peer bridge fixup\n"); for (n=0; n <= pcibios_last_bus; n++) { - if (pci_bus_exists(&pci_root_buses, n)) + if (pci_find_bus(0, n)) continue; bus.number = n; bus.ops = pci_root_ops; diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 5764acac848..8ee1cc05272 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -924,6 +924,13 @@ config DEBUG_SPINLOCK best used in conjunction with the NMI watchdog so that spinlock deadlocks are also debuggable. +config KALLSYMS + bool "Load all symbols for debugging/ksymoops" + help + Say Y here to let the kernel print out symbolic crash information and + symbolic stack backtraces. This increases the size of the kernel + somewhat, as all symbols have to be loaded into the kernel image. + config DEBUG_SPINLOCK_SLEEP bool "Sleep-inside-spinlock checking" help diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile index 0e46fc2d982..5eb14ff1c51 100644 --- a/arch/sparc64/boot/Makefile +++ b/arch/sparc64/boot/Makefile @@ -10,11 +10,11 @@ ELFTOAOUT := elftoaout host-progs := piggyback targets := image tftpboot.img vmlinux.aout -quiet_cmd_elftoaout = ELT2AOUT $@ +quiet_cmd_elftoaout = ELF2AOUT $@ cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@ -quiet_cmd_piggy = PIGGY $@ +quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $@ System.map $(ROOT_IMG) -quiet_cmd_strip = STRIP $@ +quiet_cmd_strip = STRIP $@ cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@ diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 7902b35f01d..c606b4721b5 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -733,7 +733,7 @@ void handler_irq(int irq, struct pt_regs *regs) #endif irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; /* Sliiiick... */ #ifndef CONFIG_SMP @@ -805,7 +805,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(); - kstat_cpu(cpu).irqs[irq]++; + kstat_this_cpu.irqs[irq]++; *(irq_work(cpu, irq)) = 0; bucket = get_ino_in_irqaction(action) + ivector_table; diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 6326ab3761e..46d473c1041 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -284,6 +285,7 @@ void __show_regs(struct pt_regs * regs) #endif printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x %s\n", regs->tstate, regs->tpc, regs->tnpc, regs->y, print_tainted()); + print_symbol("TPC: <%s>\n", regs->tpc); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], regs->u_regs[3]); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index a5504b89917..0d0ff4e2042 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -1060,7 +1060,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) irq_enter(); if (cpu == boot_cpu_id) { - kstat_cpu(cpu).irqs[0]++; + kstat_this_cpu.irqs[0]++; timer_tick_interrupt(regs); } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index f2f9c9d0540..2af4669e339 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -116,6 +116,14 @@ extern unsigned long pfn_base; extern unsigned int sys_call_table[]; +extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); +extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, + unsigned long *); +extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *); +extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *, unsigned long *); + /* used by various drivers */ #ifdef CONFIG_SMP #ifndef CONFIG_DEBUG_SPINLOCK @@ -376,3 +384,8 @@ EXPORT_SYMBOL(ns87303_lock); EXPORT_SYMBOL_GPL(sys_call_table); EXPORT_SYMBOL(tick_ops); + +EXPORT_SYMBOL(xor_vis_2); +EXPORT_SYMBOL(xor_vis_3); +EXPORT_SYMBOL(xor_vis_4); +EXPORT_SYMBOL(xor_vis_5); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index bfeedd653c2..3ae4b144b27 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -12,6 +12,7 @@ #include #include /* for jiffies */ #include +#include #include #include #include @@ -1644,7 +1645,9 @@ void die_if_kernel(char *str, struct pt_regs *regs) (char *) rw < ((char *) current) + sizeof (union thread_union) && !(((unsigned long) rw) & 0x7)) { - printk("Caller[%016lx]\n", rw->ins[7]); + printk("Caller[%016lx]", rw->ins[7]); + print_symbol(": %s\n", rw->ins[7]); + printk("\n"); lastrw = rw; rw = (struct reg_window *) (rw->ins[6] + STACK_BIAS); diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index bc822e42b2c..394c4e2914d 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -10,4 +10,4 @@ lib-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o ipcsum.o rwsem.o + U3copy_in_user.o mcount.o ipcsum.o rwsem.o xor.o diff --git a/include/asm-sparc64/xor.h b/arch/sparc64/lib/xor.S similarity index 82% copy from include/asm-sparc64/xor.h copy to arch/sparc64/lib/xor.S index 9ecc98f667d..8eeba353dee 100644 --- a/include/asm-sparc64/xor.h +++ b/arch/sparc64/lib/xor.S @@ -1,53 +1,22 @@ /* - * include/asm-sparc64/xor.h + * arch/sparc64/lib/xor.S * * High speed xor_block operation for RAID4/5 utilizing the * UltraSparc Visual Instruction Set. * * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include +#include + /* * Requirements: * !(((long)dest | (long)sourceN) & (64 - 1)) && * !(len & 127) && len >= 256 - * - * It is done in pure assembly, as otherwise gcc makes it a non-leaf - * function, which is not what we want. */ - -#include -#include - -extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); - -#define _S(x) __S(x) -#define __S(x) #x -#define DEF(x) __asm__(#x " = " _S(x)) - -DEF(FPRS_FEF); -DEF(FPRS_DU); -DEF(ASI_BLK_P); - -/* ??? We set and use %asi instead of using ASI_BLK_P directly because gas - currently does not accept symbolic constants for the ASI specifier. */ - -__asm__ (" .text .globl xor_vis_2 .type xor_vis_2,@function @@ -385,14 +354,3 @@ xor_vis_5: retl wr %g0, 0, %fprs .size xor_vis_5, .-xor_vis_5 -"); - -static struct xor_block_template xor_block_VIS = { - .name = "VIS", - .do_2 = xor_vis_2, - .do_3 = xor_vis_3, - .do_4 = xor_vis_4, - .do_5 = xor_vis_5, -}; - -#define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) diff --git a/arch/sparc64/oprofile/init.c b/arch/sparc64/oprofile/init.c index 65a40a2cbf2..b49fe60c03d 100644 --- a/arch/sparc64/oprofile/init.c +++ b/arch/sparc64/oprofile/init.c @@ -20,6 +20,6 @@ int __init oprofile_arch_init(struct oprofile_operations ** ops) } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { } diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 9f0fba36177..18c53d71658 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -113,8 +113,9 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) } void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { + unsigned cpu = smp_processor_id(); if (prev != next) clear_bit(cpu, &prev->cpu_vm_mask); set_bit(cpu, &next->cpu_vm_mask); diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index 496dfa9da74..e4b86e6cbf9 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include #include @@ -339,7 +341,7 @@ int setup_arg_pages(struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; - if (!vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index 6b71af1d106..82a75fa6b67 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -288,7 +288,7 @@ void __init cpu_init (void) me->active_mm = &init_mm; if (me->mm) BUG(); - enter_lazy_tlb(&init_mm, me, cpu); + enter_lazy_tlb(&init_mm, me); set_tss_desc(cpu, t); load_TR_desc(); diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 3be6a8e4b67..cafd352ba63 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -64,7 +64,7 @@ void show_mem(void) printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); for_each_pgdat(pgdat) { - for (i = 0; i < pgdat->node_size; ++i) { + for (i = 0; i < pgdat->node_spanned_pages; ++i) { page = pgdat->node_mem_map + i; total++; if (PageReserved(page)) diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 0150d11586a..738ae097fae 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -86,7 +86,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t)); NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid]; NODE_DATA(nodeid)->node_start_pfn = start_pfn; - NODE_DATA(nodeid)->node_size = end_pfn - start_pfn; + NODE_DATA(nodeid)->node_spanned_pages = end_pfn - start_pfn; /* Find a place for the bootmem map */ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 7c555c819de..3b17c9d2e87 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -238,7 +238,7 @@ acpi_suspend ( /* do we have a wakeup address for S2 and S3? */ /* Here, we support only S4BIOS, those we set the wakeup address */ /* S4OS is only supported for now via swsusp.. */ - if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3 || ACPI_STATE_S4) { + if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3 || state == ACPI_STATE_S4) { if (!acpi_wakeup_address) return AE_ERROR; acpi_set_firmware_waking_vector((acpi_physical_address) acpi_wakeup_address); diff --git a/drivers/base/class.c b/drivers/base/class.c index ea551b8dc28..2a9c349bd7c 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2003 Greg Kroah-Hartman + * Copyright (c) 2003 IBM Corp. * * This file is released under the GPLv2 * @@ -339,6 +341,24 @@ void class_device_unregister(struct class_device *class_dev) class_device_put(class_dev); } +int class_device_rename(struct class_device *class_dev, char *new_name) +{ + class_dev = class_device_get(class_dev); + if (!class_dev) + return -EINVAL; + + pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id, + new_name); + + strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); + + kobject_rename(&class_dev->kobj, new_name); + + class_device_put(class_dev); + + return 0; +} + struct class_device * class_device_get(struct class_device *class_dev) { if (class_dev) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b186dba8d2d..f3981af9457 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -149,7 +149,7 @@ firmware_data_read(struct kobject *kobj, if (offset + count > fw->size) count = fw->size - offset; - memcpy(buffer, fw->data + offset, count); + memcpy(buffer + offset, fw->data + offset, count); return count; } static int @@ -198,7 +198,7 @@ firmware_data_write(struct kobject *kobj, if (retval) return retval; - memcpy(fw->data + offset, buffer, count); + memcpy(fw->data + offset, buffer + offset, count); fw->size = max_t(size_t, offset + count, fw->size); diff --git a/drivers/block/Makefile b/drivers/block/Makefile index c723e8ecc58..4733ec79a6d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -8,7 +8,13 @@ # In the future, some of these should be built conditionally. # -obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o deadline-iosched.o +# +# NOTE that ll_rw_blk.c must come early in linkage order - it starts the +# kblockd threads +# + +obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o \ + deadline-iosched.o as-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c new file mode 100644 index 00000000000..b19289348fb --- /dev/null +++ b/drivers/block/as-iosched.c @@ -0,0 +1,1837 @@ +/* + * linux/drivers/block/as-iosched.c + * + * Anticipatory & deadline i/o scheduler. + * + * Copyright (C) 2002 Jens Axboe + * Nick Piggin + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REQ_SYNC 1 +#define REQ_ASYNC 0 + +/* + * See Documentation/as-iosched.txt + */ + +/* + * max time before a read is submitted. + */ +#define default_read_expire (HZ / 20) + +/* + * ditto for writes, these limits are not hard, even + * if the disk is capable of satisfying them. + */ +#define default_write_expire (HZ / 5) + +/* + * read_batch_expire describes how long we will allow a stream of reads to + * persist before looking to see whether it is time to switch over to writes. + */ +#define default_read_batch_expire (HZ / 5) + +/* + * write_batch_expire describes how long we want a stream of writes to run for. + * This is not a hard limit, but a target we set for the auto-tuning thingy. + * See, the problem is: we can send a lot of writes to disk cache / TCQ in + * a short amount of time... + */ +#define default_write_batch_expire (HZ / 20) + +/* + * max time we may wait to anticipate a read (default around 6ms) + */ +#define default_antic_expire ((HZ / 150) ? HZ / 150 : 1) + +/* + * Keep track of up to 20ms thinktimes. We can go as big as we like here, + * however huge values tend to interfere and not decay fast enough. A program + * might be in a non-io phase of operation. Waiting on user input for example, + * or doing a lengthy computation. A small penalty can be justified there, and + * will still catch out those processes that constantly have large thinktimes. + */ +#define MAX_THINKTIME (HZ/50UL) + +/* Bits in as_io_context.state */ +enum as_io_states { + AS_TASK_RUNNING=0, /* Process has not exitted */ + AS_TASK_IORUNNING, /* Process has completed some IO */ +}; + +enum anticipation_status { + ANTIC_OFF=0, /* Not anticipating (normal operation) */ + ANTIC_WAIT_REQ, /* The last read has not yet completed */ + ANTIC_WAIT_NEXT, /* Currently anticipating a request vs + last read (which has completed) */ + ANTIC_FINISHED, /* Anticipating but have found a candidate + * or timed out */ +}; + +struct as_data { + /* + * run time data + */ + + struct request_queue *q; /* the "owner" queue */ + + /* + * requests (as_rq s) are present on both sort_list and fifo_list + */ + struct rb_root sort_list[2]; + struct list_head fifo_list[2]; + + struct as_rq *next_arq[2]; /* next in sort order */ + sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */ + struct list_head *dispatch; /* driver dispatch queue */ + struct list_head *hash; /* request hash */ + unsigned long hash_valid_count; /* barrier hash count */ + unsigned long current_batch_expires; + unsigned long last_check_fifo[2]; + int changed_batch; + int batch_data_dir; /* current batch REQ_SYNC / REQ_ASYNC */ + int write_batch_count; /* max # of reqs in a write batch */ + int current_write_count; /* how many requests left this batch */ + int write_batch_idled; /* has the write batch gone idle? */ + mempool_t *arq_pool; + + enum anticipation_status antic_status; + unsigned long antic_start; /* jiffies: when it started */ + struct timer_list antic_timer; /* anticipatory scheduling timer */ + struct work_struct antic_work; /* Deferred unplugging */ + struct io_context *io_context; /* Identify the expected process */ + int ioc_finished; /* IO associated with io_context is finished */ + int nr_dispatched; + + /* + * settings that change how the i/o scheduler behaves + */ + unsigned long fifo_expire[2]; + unsigned long batch_expire[2]; + unsigned long antic_expire; +}; + +#define list_entry_fifo(ptr) list_entry((ptr), struct as_rq, fifo) + +/* + * per-request data. + */ +enum arq_state { + AS_RQ_NEW=0, /* New - not referenced and not on any lists */ + AS_RQ_QUEUED, /* In the request queue. It belongs to the + scheduler */ + AS_RQ_DISPATCHED, /* On the dispatch list. It belongs to the + driver now */ +}; + +struct as_rq { + /* + * rbtree index, key is the starting offset + */ + struct rb_node rb_node; + sector_t rb_key; + + struct request *request; + + struct io_context *io_context; /* The submitting task */ + + /* + * request hash, key is the ending offset (for back merge lookup) + */ + struct list_head hash; + unsigned long hash_valid_count; + + /* + * expire fifo + */ + struct list_head fifo; + unsigned long expires; + + int is_sync; + enum arq_state state; /* debug only */ +}; + +#define RQ_DATA(rq) ((struct as_rq *) (rq)->elevator_private) + +static kmem_cache_t *arq_pool; + +/* + * IO Context helper functions + */ +/* Debug */ +static atomic_t nr_as_io_requests = ATOMIC_INIT(0); + +/* Called to deallocate the as_io_context */ +static void free_as_io_context(struct as_io_context *aic) +{ + atomic_dec(&nr_as_io_requests); + kfree(aic); +} + +/* Called when the task exits */ +static void exit_as_io_context(struct as_io_context *aic) +{ + clear_bit(AS_TASK_RUNNING, &aic->state); +} + +static struct as_io_context *alloc_as_io_context(void) +{ + struct as_io_context *ret; + + ret = kmalloc(sizeof(*ret), GFP_ATOMIC); + if (ret) { + atomic_inc(&nr_as_io_requests); + ret->dtor = free_as_io_context; + ret->exit = exit_as_io_context; + ret->state = 1 << AS_TASK_RUNNING; + atomic_set(&ret->nr_queued, 0); + atomic_set(&ret->nr_dispatched, 0); + spin_lock_init(&ret->lock); + ret->ttime_total = 0; + ret->ttime_samples = 0; + ret->ttime_mean = 0; + ret->seek_total = 0; + ret->seek_samples = 0; + ret->seek_mean = 0; + } + + return ret; +} + +/* + * If the current task has no AS IO context then create one and initialise it. + * Then take a ref on the task's io context and return it. + */ +static struct io_context *as_get_io_context(void) +{ + struct io_context *ioc = get_io_context(GFP_ATOMIC); + if (ioc && !ioc->aic) { + ioc->aic = alloc_as_io_context(); + if (!ioc->aic) { + put_io_context(ioc); + ioc = NULL; + } + } + return ioc; +} + +/* + * the back merge hash support functions + */ +static const int as_hash_shift = 6; +#define AS_HASH_BLOCK(sec) ((sec) >> 3) +#define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift)) +#define AS_HASH_ENTRIES (1 << as_hash_shift) +#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors) +#define list_entry_hash(ptr) list_entry((ptr), struct as_rq, hash) +#define ON_HASH(arq) (arq)->hash_valid_count + +#define AS_INVALIDATE_HASH(ad) \ + do { \ + if (!++(ad)->hash_valid_count) \ + (ad)->hash_valid_count = 1; \ + } while (0) + +static inline void __as_del_arq_hash(struct as_rq *arq) +{ + arq->hash_valid_count = 0; + list_del_init(&arq->hash); +} + +static inline void as_del_arq_hash(struct as_rq *arq) +{ + if (ON_HASH(arq)) + __as_del_arq_hash(arq); +} + +static void as_remove_merge_hints(request_queue_t *q, struct as_rq *arq) +{ + as_del_arq_hash(arq); + + if (q->last_merge == &arq->request->queuelist) + q->last_merge = NULL; +} + +static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq) +{ + struct request *rq = arq->request; + + BUG_ON(ON_HASH(arq)); + + arq->hash_valid_count = ad->hash_valid_count; + list_add(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]); +} + +/* + * move hot entry to front of chain + */ +static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq) +{ + struct request *rq = arq->request; + struct list_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))]; + + if (!ON_HASH(arq)) { + WARN_ON(1); + return; + } + + if (arq->hash.prev != head) { + list_del(&arq->hash); + list_add(&arq->hash, head); + } +} + +static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset) +{ + struct list_head *hash_list = &ad->hash[AS_HASH_FN(offset)]; + struct list_head *entry, *next = hash_list->next; + + while ((entry = next) != hash_list) { + struct as_rq *arq = list_entry_hash(entry); + struct request *__rq = arq->request; + + next = entry->next; + + BUG_ON(!ON_HASH(arq)); + + if (!rq_mergeable(__rq) + || arq->hash_valid_count != ad->hash_valid_count) { + __as_del_arq_hash(arq); + continue; + } + + if (rq_hash_key(__rq) == offset) + return __rq; + } + + return NULL; +} + +/* + * rb tree support functions + */ +#define RB_NONE (2) +#define RB_EMPTY(root) ((root)->rb_node == NULL) +#define ON_RB(node) ((node)->rb_color != RB_NONE) +#define RB_CLEAR(node) ((node)->rb_color = RB_NONE) +#define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node) +#define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync]) +#define rq_rb_key(rq) (rq)->sector + +/* + * as_find_first_arq finds the first (lowest sector numbered) request + * for the specified data_dir. Used to sweep back to the start of the disk + * (1-way elevator) after we process the last (highest sector) request. + */ +static struct as_rq *as_find_first_arq(struct as_data *ad, int data_dir) +{ + struct rb_node *n = ad->sort_list[data_dir].rb_node; + + if (n == NULL) + return NULL; + + for (;;) { + if (n->rb_left == NULL) + return rb_entry_arq(n); + + n = n->rb_left; + } +} + +static struct as_rq *__as_add_arq_rb(struct as_data *ad, struct as_rq *arq) +{ + struct rb_node **p = &ARQ_RB_ROOT(ad, arq)->rb_node; + struct rb_node *parent = NULL; + struct as_rq *__arq; + + while (*p) { + parent = *p; + __arq = rb_entry_arq(parent); + + if (arq->rb_key < __arq->rb_key) + p = &(*p)->rb_left; + else if (arq->rb_key > __arq->rb_key) + p = &(*p)->rb_right; + else + return __arq; + } + + rb_link_node(&arq->rb_node, parent, p); + return 0; +} + +static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); +/* + * Add the request to the rb tree if it is unique. If there is an alias (an + * existing request against the same sector), which can happen when using + * direct IO, then move the alias to the dispatch list and then add the + * request. + */ +static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq) +{ + struct as_rq *alias; + struct request *rq = arq->request; + + arq->rb_key = rq_rb_key(rq); + + /* This can be caused by direct IO */ + while ((alias = __as_add_arq_rb(ad, arq))) + as_move_to_dispatch(ad, alias); + + rb_insert_color(&arq->rb_node, ARQ_RB_ROOT(ad, arq)); +} + +static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq) +{ + if (!ON_RB(&arq->rb_node)) { + WARN_ON(1); + return; + } + + rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq)); + RB_CLEAR(&arq->rb_node); +} + +static struct request * +as_find_arq_rb(struct as_data *ad, sector_t sector, int data_dir) +{ + struct rb_node *n = ad->sort_list[data_dir].rb_node; + struct as_rq *arq; + + while (n) { + arq = rb_entry_arq(n); + + if (sector < arq->rb_key) + n = n->rb_left; + else if (sector > arq->rb_key) + n = n->rb_right; + else + return arq->request; + } + + return NULL; +} + +/* + * IO Scheduler proper + */ + +#define MAXBACK (1024 * 1024) /* + * Maximum distance the disk will go backward + * for a request. + */ + +/* + * as_choose_req selects the preferred one of two requests of the same data_dir + * ignoring time - eg. timeouts, which is the job of as_dispatch_request + */ +static struct as_rq * +as_choose_req(struct as_data *ad, struct as_rq *arq1, struct as_rq *arq2) +{ + int data_dir; + sector_t last, s1, s2, d1, d2; + int r1_wrap=0, r2_wrap=0; /* requests are behind the disk head */ + const sector_t maxback = MAXBACK; + + if (arq1 == NULL || arq1 == arq2) + return arq2; + if (arq2 == NULL) + return arq1; + + data_dir = arq1->is_sync; + + last = ad->last_sector[data_dir]; + s1 = arq1->request->sector; + s2 = arq2->request->sector; + + BUG_ON(data_dir != arq2->is_sync); + + /* + * Strict one way elevator _except_ in the case where we allow + * short backward seeks which are biased as twice the cost of a + * similar forward seek. + */ + if (s1 >= last) + d1 = s1 - last; + else if (s1+maxback >= last) + d1 = (last - s1)*2; + else { + r1_wrap = 1; + d1 = 0; /* shut up, gcc */ + } + + if (s2 >= last) + d2 = s2 - last; + else if (s2+maxback >= last) + d2 = (last - s2)*2; + else { + r2_wrap = 1; + d2 = 0; + } + + /* Found required data */ + if (!r1_wrap && r2_wrap) + return arq1; + else if (!r2_wrap && r1_wrap) + return arq2; + else if (r1_wrap && r2_wrap) { + /* both behind the head */ + if (s1 <= s2) + return arq1; + else + return arq2; + } + + /* Both requests in front of the head */ + if (d1 < d2) + return arq1; + else if (d2 < d1) + return arq2; + else { + if (s1 >= s2) + return arq1; + else + return arq2; + } +} + +/* + * as_find_next_arq finds the next request after @prev in elevator order. + * this with as_choose_req form the basis for how the scheduler chooses + * what request to process next. Anticipation works on top of this. + */ +static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last) +{ + const int data_dir = last->is_sync; + struct as_rq *ret; + struct rb_node *rbnext = rb_next(&last->rb_node); + struct rb_node *rbprev = rb_prev(&last->rb_node); + struct as_rq *arq_next, *arq_prev; + + BUG_ON(!ON_RB(&last->rb_node)); + + if (rbprev) + arq_prev = rb_entry_arq(rbprev); + else + arq_prev = NULL; + + if (rbnext) + arq_next = rb_entry_arq(rbnext); + else { + arq_next = as_find_first_arq(ad, data_dir); + if (arq_next == last) + arq_next = NULL; + } + + ret = as_choose_req(ad, arq_next, arq_prev); + + return ret; +} + +/* + * anticipatory scheduling functions follow + */ + +/* + * as_antic_expired tells us when we have anticipated too long. + * The funny "absolute difference" math on the elapsed time is to handle + * jiffy wraps, and disks which have been idle for 0x80000000 jiffies. + */ +static int as_antic_expired(struct as_data *ad) +{ + long delta_jif; + + delta_jif = jiffies - ad->antic_start; + if (unlikely(delta_jif < 0)) + delta_jif = -delta_jif; + if (delta_jif < ad->antic_expire) + return 0; + + return 1; +} + +/* + * as_antic_waitnext starts anticipating that a nice request will soon be + * submitted. See also as_antic_waitreq + */ +static void as_antic_waitnext(struct as_data *ad) +{ + unsigned long timeout; + + BUG_ON(ad->antic_status != ANTIC_OFF + && ad->antic_status != ANTIC_WAIT_REQ); + + timeout = ad->antic_start + ad->antic_expire; + + mod_timer(&ad->antic_timer, timeout); + + ad->antic_status = ANTIC_WAIT_NEXT; +} + +/* + * as_antic_waitreq starts anticipating. We don't start timing the anticipation + * until the request that we're anticipating on has finished. This means we + * are timing from when the candidate process wakes up hopefully. + */ +static void as_antic_waitreq(struct as_data *ad) +{ + BUG_ON(ad->antic_status == ANTIC_FINISHED); + if (ad->antic_status == ANTIC_OFF) { + if (!ad->io_context || ad->ioc_finished) + as_antic_waitnext(ad); + else + ad->antic_status = ANTIC_WAIT_REQ; + } +} + +/* + * This is called directly by the functions in this file to stop anticipation. + * We kill the timer and schedule a call to the request_fn asap. + */ +static void as_antic_stop(struct as_data *ad) +{ + int status = ad->antic_status; + + if (status == ANTIC_WAIT_REQ || status == ANTIC_WAIT_NEXT) { + if (status == ANTIC_WAIT_NEXT) + del_timer(&ad->antic_timer); + ad->antic_status = ANTIC_FINISHED; + /* see as_work_handler */ + kblockd_schedule_work(&ad->antic_work); + } +} + +/* + * as_antic_timeout is the timer function set by as_antic_waitnext. + */ +static void as_antic_timeout(unsigned long data) +{ + struct request_queue *q = (struct request_queue *)data; + struct as_data *ad = q->elevator.elevator_data; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + if (ad->antic_status == ANTIC_WAIT_REQ + || ad->antic_status == ANTIC_WAIT_NEXT) { + ad->antic_status = ANTIC_FINISHED; + kblockd_schedule_work(&ad->antic_work); + } + spin_unlock_irqrestore(q->queue_lock, flags); +} + +/* + * as_close_req decides if one request is considered "close" to the + * previous one issued. + */ +static int as_close_req(struct as_data *ad, struct as_rq *arq) +{ + unsigned long delay; /* milliseconds */ + sector_t last = ad->last_sector[ad->batch_data_dir]; + sector_t next = arq->request->sector; + sector_t delta; /* acceptable close offset (in sectors) */ + + if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished) + delay = 0; + else + delay = ((jiffies - ad->antic_start) * 1000) / HZ; + + if (delay <= 1) + delta = 64; + else if (delay <= 20 && delay <= ad->antic_expire) + delta = 64 << (delay-1); + else + return 1; + + return (last - (delta>>1) <= next) && (next <= last + delta); +} + +/* + * as_can_break_anticipation returns true if we have been anticipating this + * request. + * + * It also returns true if the process against which we are anticipating + * submits a write - that's presumably an fsync, O_SYNC write, etc. We want to + * dispatch it ASAP, because we know that application will not be submitting + * any new reads. + * + * If the task which has submitted the request has exitted, break anticipation. + * + * If this task has queued some other IO, do not enter enticipation. + */ +static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) +{ + struct io_context *ioc; + struct as_io_context *aic; + + if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, arq)) { + /* close request */ + return 1; + } + + if (ad->ioc_finished && as_antic_expired(ad)) { + /* + * In this situation status should really be FINISHED, + * however the timer hasn't had the chance to run yet. + */ + return 1; + } + + ioc = ad->io_context; + BUG_ON(!ioc); + + if (arq && ioc == arq->io_context) { + /* request from same process */ + return 1; + } + + aic = ioc->aic; + if (!aic) + return 0; + + if (!test_bit(AS_TASK_RUNNING, &aic->state)) { + /* process anticipated on has exitted */ + return 1; + } + + if (atomic_read(&aic->nr_queued) > 0) { + /* process has more requests queued */ + return 1; + } + + if (atomic_read(&aic->nr_dispatched) > 0) { + /* process has more requests dispatched */ + return 1; + } + + if (aic->ttime_mean > ad->antic_expire) { + /* the process thinks too much between requests */ + return 1; + } + + if (arq && aic->seek_samples) { + sector_t s; + if (ad->last_sector[REQ_SYNC] < arq->request->sector) + s = arq->request->sector - ad->last_sector[REQ_SYNC]; + else + s = ad->last_sector[REQ_SYNC] - arq->request->sector; + + if (aic->seek_mean > (s>>1)) { + /* this request is better than what we're expecting */ + return 1; + } + } + + return 0; +} + +/* + * as_can_anticipate indicates weather we should either run arq + * or keep anticipating a better request. + */ +static int as_can_anticipate(struct as_data *ad, struct as_rq *arq) +{ + if (!ad->io_context) + /* + * Last request submitted was a write + */ + return 0; + + if (ad->antic_status == ANTIC_FINISHED) + /* + * Don't restart if we have just finished. Run the next request + */ + return 0; + + if (as_can_break_anticipation(ad, arq)) + /* + * This request is a good candidate. Don't keep anticipating, + * run it. + */ + return 0; + + /* + * OK from here, we haven't finished, and don't have a decent request! + * Status is either ANTIC_OFF so start waiting, + * ANTIC_WAIT_REQ so continue waiting for request to finish + * or ANTIC_WAIT_NEXT so continue waiting for an acceptable request. + * + */ + + return 1; +} + +/* + * as_update_iohist keeps a decaying histogram of IO thinktimes, and + * updates @aic->ttime_mean based on that. It is called when a new + * request is queued. + */ +static void as_update_iohist(struct as_io_context *aic, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + int data_dir = arq->is_sync; + unsigned long thinktime; + sector_t seek_dist; + + if (aic == NULL) + return; + + if (data_dir == REQ_SYNC) { + spin_lock(&aic->lock); + + if (test_bit(AS_TASK_IORUNNING, &aic->state) + && !atomic_read(&aic->nr_queued) + && !atomic_read(&aic->nr_dispatched)) { + /* Calculate read -> read thinktime */ + thinktime = jiffies - aic->last_end_request; + thinktime = min(thinktime, MAX_THINKTIME-1); + /* fixed point: 1.0 == 1<<8 */ + aic->ttime_samples += 256; + aic->ttime_total += 256*thinktime; + if (aic->ttime_samples) + /* fixed point factor is cancelled here */ + aic->ttime_mean = (aic->ttime_total + 128) + / aic->ttime_samples; + aic->ttime_samples = (aic->ttime_samples>>1) + + (aic->ttime_samples>>2); + aic->ttime_total = (aic->ttime_total>>1) + + (aic->ttime_total>>2); + } + + /* Calculate read -> read seek distance */ + if (!aic->seek_samples) + seek_dist = 0; + else if (aic->last_request_pos < rq->sector) + seek_dist = rq->sector - aic->last_request_pos; + else + seek_dist = aic->last_request_pos - rq->sector; + + aic->last_request_pos = rq->sector + rq->nr_sectors; + + /* + * Don't allow the seek distance to get too large from the + * odd fragment, pagein, etc + */ + if (aic->seek_samples < 400) /* second&third seek */ + seek_dist = min(seek_dist, (aic->seek_mean * 4) + + 2*1024*1024); + else + seek_dist = min(seek_dist, (aic->seek_mean * 4) + + 2*1024*64); + + aic->seek_samples += 256; + aic->seek_total += 256*seek_dist; + if (aic->seek_samples) { + aic->seek_mean = aic->seek_total + 128; + do_div(aic->seek_mean, aic->seek_samples); + } + aic->seek_samples = (aic->seek_samples>>1) + + (aic->seek_samples>>2); + aic->seek_total = (aic->seek_total>>1) + + (aic->seek_total>>2); + + spin_unlock(&aic->lock); + } +} + +/* + * as_update_arq must be called whenever a request (arq) is added to + * the sort_list. This function keeps caches up to date, and checks if the + * request might be one we are "anticipating" + */ +static void as_update_arq(struct as_data *ad, struct as_rq *arq) +{ + const int data_dir = arq->is_sync; + + /* keep the next_arq cache up to date */ + ad->next_arq[data_dir] = as_choose_req(ad, arq, ad->next_arq[data_dir]); + + /* + * have we been anticipating this request? + * or does it come from the same process as the one we are anticipating + * for? + */ + if (ad->antic_status == ANTIC_WAIT_REQ + || ad->antic_status == ANTIC_WAIT_NEXT) { + if (as_can_break_anticipation(ad, arq)) + as_antic_stop(ad); + } +} + +/* + * Gathers timings and resizes the write batch automatically + */ +void update_write_batch(struct as_data *ad) +{ + unsigned long batch = ad->batch_expire[REQ_ASYNC]; + long write_time; + + write_time = (jiffies - ad->current_batch_expires) + batch; + if (write_time < 0) + write_time = 0; + + if (write_time > batch && !ad->write_batch_idled) { + if (write_time > batch * 3) + ad->write_batch_count /= 2; + else + ad->write_batch_count--; + } else if (write_time < batch && ad->current_write_count == 0) { + if (batch > write_time * 3) + ad->write_batch_count *= 2; + else + ad->write_batch_count++; + } + + if (ad->write_batch_count < 1) + ad->write_batch_count = 1; +} + +/* + * as_completed_request is to be called when a request has completed and + * returned something to the requesting process, be it an error or data. + */ +static void as_completed_request(request_queue_t *q, struct request *rq) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(rq); + struct as_io_context *aic; + + if (unlikely(!blk_fs_request(rq))) + return; + + WARN_ON(blk_fs_request(rq) && arq->state == AS_RQ_NEW); + + if (arq->state != AS_RQ_DISPATCHED) + return; + + if (ad->changed_batch && ad->nr_dispatched == 1) { + kblockd_schedule_work(&ad->antic_work); + ad->changed_batch = 2; + } + ad->nr_dispatched--; + + /* + * Start counting the batch from when a request of that direction is + * actually serviced. This should help devices with big TCQ windows + * and writeback caches + */ + if (ad->batch_data_dir == REQ_SYNC && ad->changed_batch + && ad->batch_data_dir == arq->is_sync) { + update_write_batch(ad); + ad->current_batch_expires = jiffies + + ad->batch_expire[REQ_SYNC]; + ad->changed_batch = 0; + } + + if (!arq->io_context) + return; + + if (ad->io_context == arq->io_context) { + ad->antic_start = jiffies; + ad->ioc_finished = 1; + if (ad->antic_status == ANTIC_WAIT_REQ) { + /* + * We were waiting on this request, now anticipate + * the next one + */ + as_antic_waitnext(ad); + } + } + + aic = arq->io_context->aic; + if (!aic) + return; + + spin_lock(&aic->lock); + if (arq->is_sync == REQ_SYNC) { + set_bit(AS_TASK_IORUNNING, &aic->state); + aic->last_end_request = jiffies; + } + spin_unlock(&aic->lock); + + put_io_context(arq->io_context); +} + +/* + * as_remove_queued_request removes a request from the pre dispatch queue + * without updating refcounts. It is expected the caller will drop the + * reference unless it replaces the request at somepart of the elevator + * (ie. the dispatch queue) + */ +static void as_remove_queued_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + const int data_dir = arq->is_sync; + struct as_data *ad = q->elevator.elevator_data; + + WARN_ON(arq->state != AS_RQ_QUEUED); + + if (arq->io_context && arq->io_context->aic) { + BUG_ON(!atomic_read(&arq->io_context->aic->nr_queued)); + atomic_dec(&arq->io_context->aic->nr_queued); + } + + /* + * Update the "next_arq" cache if we are about to remove its + * entry + */ + if (ad->next_arq[data_dir] == arq) + ad->next_arq[data_dir] = as_find_next_arq(ad, arq); + + list_del_init(&arq->fifo); + as_remove_merge_hints(q, arq); + as_del_arq_rb(ad, arq); +} + +/* + * as_remove_dispatched_request is called to remove a request which has gone + * to the dispatch list. + */ +static void as_remove_dispatched_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + struct as_io_context *aic; + + if (!arq) { + WARN_ON(1); + return; + } + + WARN_ON(arq->state != AS_RQ_DISPATCHED); + WARN_ON(ON_RB(&arq->rb_node)); + if (arq->io_context && arq->io_context->aic) { + aic = arq->io_context->aic; + if (aic) { + WARN_ON(!atomic_read(&aic->nr_dispatched)); + atomic_dec(&aic->nr_dispatched); + } + } +} +/* + * as_remove_request is called when a driver has finished with a request. + * This should be only called for dispatched requests, but for some reason + * a POWER4 box running hwscan it does not. + */ +static void as_remove_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + + if (unlikely(!blk_fs_request(rq))) + return; + + if (!arq) { + WARN_ON(1); + return; + } + + if (ON_RB(&arq->rb_node)) + as_remove_queued_request(q, rq); + else + as_remove_dispatched_request(q, rq); +} + +/* + * as_fifo_expired returns 0 if there are no expired reads on the fifo, + * 1 otherwise. It is ratelimited so that we only perform the check once per + * `fifo_expire' interval. Otherwise a large number of expired requests + * would create a hopeless seekstorm. + * + * See as_antic_expired comment. + */ +static int as_fifo_expired(struct as_data *ad, int adir) +{ + struct as_rq *arq; + long delta_jif; + + delta_jif = jiffies - ad->last_check_fifo[adir]; + if (unlikely(delta_jif < 0)) + delta_jif = -delta_jif; + if (delta_jif < ad->fifo_expire[adir]) + return 0; + + ad->last_check_fifo[adir] = jiffies; + + if (list_empty(&ad->fifo_list[adir])) + return 0; + + arq = list_entry_fifo(ad->fifo_list[adir].next); + + return time_after(jiffies, arq->expires); +} + +/* + * as_batch_expired returns true if the current batch has expired. A batch + * is a set of reads or a set of writes. + */ +static inline int as_batch_expired(struct as_data *ad) +{ + if (ad->changed_batch) + return 0; + + if (ad->batch_data_dir == REQ_SYNC) + /* TODO! add a check so a complete fifo gets written? */ + return time_after(jiffies, ad->current_batch_expires); + + return time_after(jiffies, ad->current_batch_expires) + || ad->current_write_count == 0; +} + +/* + * move an entry to dispatch queue + */ +static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq) +{ + const int data_dir = arq->is_sync; + + BUG_ON(!ON_RB(&arq->rb_node)); + + as_antic_stop(ad); + ad->antic_status = ANTIC_OFF; + + /* + * This has to be set in order to be correctly updated by + * as_find_next_arq + */ + ad->last_sector[data_dir] = arq->request->sector + + arq->request->nr_sectors; + + ad->nr_dispatched++; + + if (data_dir == REQ_SYNC) { + /* In case we have to anticipate after this */ + copy_io_context(&ad->io_context, &arq->io_context); + } else { + if (ad->io_context) { + put_io_context(ad->io_context); + ad->io_context = NULL; + } + + if (ad->current_write_count != 0) + ad->current_write_count--; + } + ad->ioc_finished = 0; + + ad->next_arq[data_dir] = as_find_next_arq(ad, arq); + + /* + * take it off the sort and fifo list, add to dispatch queue + */ + as_remove_queued_request(ad->q, arq->request); + list_add_tail(&arq->request->queuelist, ad->dispatch); + if (arq->io_context && arq->io_context->aic) + atomic_inc(&arq->io_context->aic->nr_dispatched); + + WARN_ON(arq->state != AS_RQ_QUEUED); + arq->state = AS_RQ_DISPATCHED; +} + +/* + * as_dispatch_request selects the best request according to + * read/write expire, batch expire, etc, and moves it to the dispatch + * queue. Returns 1 if a request was found, 0 otherwise. + */ +static int as_dispatch_request(struct as_data *ad) +{ + struct as_rq *arq; + const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]); + const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]); + + /* Signal that the write batch was uncontended, so we can't time it */ + if (ad->batch_data_dir == REQ_ASYNC && !reads) { + if (ad->current_write_count == 0 || !writes) + ad->write_batch_idled = 1; + } + + if (!(reads || writes) + || ad->antic_status == ANTIC_WAIT_REQ + || ad->antic_status == ANTIC_WAIT_NEXT + || ad->changed_batch == 1) + return 0; + + if (!(reads && writes && as_batch_expired(ad)) ) { + /* + * batch is still running or no reads or no writes + */ + arq = ad->next_arq[ad->batch_data_dir]; + + if (ad->batch_data_dir == REQ_SYNC && ad->antic_expire) { + if (as_fifo_expired(ad, REQ_SYNC)) + goto fifo_expired; + + if (as_can_anticipate(ad, arq)) { + as_antic_waitreq(ad); + return 0; + } + } + + if (arq) { + /* we have a "next request" */ + if (reads && !writes) + ad->current_batch_expires = + jiffies + ad->batch_expire[REQ_SYNC]; + goto dispatch_request; + } + } + + /* + * at this point we are not running a batch. select the appropriate + * data direction (read / write) + */ + + if (reads) { + BUG_ON(RB_EMPTY(&ad->sort_list[REQ_SYNC])); + + if (writes && ad->batch_data_dir == REQ_SYNC) + /* + * Last batch was a read, switch to writes + */ + goto dispatch_writes; + + if (ad->batch_data_dir == REQ_ASYNC) + ad->changed_batch = 1; + ad->batch_data_dir = REQ_SYNC; + arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next); + ad->last_check_fifo[ad->batch_data_dir] = jiffies; + goto dispatch_request; + } + + /* + * the last batch was a read + */ + + if (writes) { +dispatch_writes: + BUG_ON(RB_EMPTY(&ad->sort_list[REQ_ASYNC])); + + if (ad->batch_data_dir == REQ_SYNC) + ad->changed_batch = 1; + ad->batch_data_dir = REQ_ASYNC; + ad->current_write_count = ad->write_batch_count; + ad->write_batch_idled = 0; + arq = ad->next_arq[ad->batch_data_dir]; + goto dispatch_request; + } + + BUG(); + return 0; + +dispatch_request: + /* + * If a request has expired, service it. + */ + + if (as_fifo_expired(ad, ad->batch_data_dir)) { +fifo_expired: + arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next); + BUG_ON(arq == NULL); + } + + if (ad->changed_batch) { + if (ad->changed_batch == 1 && ad->nr_dispatched) + return 0; + if (ad->batch_data_dir == REQ_ASYNC) { + ad->current_batch_expires = jiffies + + ad->batch_expire[REQ_ASYNC]; + ad->changed_batch = 0; + } else + ad->changed_batch = 2; + arq->request->flags |= REQ_HARDBARRIER; + } + + /* + * arq is the selected appropriate request. + */ + as_move_to_dispatch(ad, arq); + + return 1; +} + +static struct request *as_next_request(request_queue_t *q) +{ + struct as_data *ad = q->elevator.elevator_data; + struct request *rq = NULL; + + /* + * if there are still requests on the dispatch queue, grab the first + */ + if (!list_empty(ad->dispatch) || as_dispatch_request(ad)) + rq = list_entry_rq(ad->dispatch->next); + + return rq; +} + +/* + * add arq to rbtree and fifo + */ +static void as_add_request(struct as_data *ad, struct as_rq *arq) +{ + int data_dir; + + if (rq_data_dir(arq->request) == READ + || current->flags&PF_SYNCWRITE) + arq->is_sync = 1; + else + arq->is_sync = 0; + data_dir = arq->is_sync; + + arq->io_context = as_get_io_context(); + + if (arq->io_context) { + atomic_inc(&arq->io_context->aic->nr_queued); + as_update_iohist(arq->io_context->aic, arq->request); + } + + as_add_arq_rb(ad, arq); + + /* + * set expire time (only used for reads) and add to fifo list + */ + arq->expires = jiffies + ad->fifo_expire[data_dir]; + list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]); + arq->state = AS_RQ_QUEUED; + as_update_arq(ad, arq); /* keep state machine up to date */ +} + +static void +as_insert_request(request_queue_t *q, struct request *rq, + struct list_head *insert_here) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(rq); + + if (unlikely(rq->flags & REQ_HARDBARRIER)) { + AS_INVALIDATE_HASH(ad); + q->last_merge = NULL; + + while (ad->next_arq[REQ_SYNC]) + as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]); + + while (ad->next_arq[REQ_ASYNC]) + as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]); + } + + if (unlikely(!blk_fs_request(rq))) { + if (!insert_here) + insert_here = ad->dispatch->prev; + + list_add(&rq->queuelist, insert_here); + + /* Stop anticipating - let this request get through */ + if (!list_empty(ad->dispatch) + && (ad->antic_status == ANTIC_WAIT_REQ + || ad->antic_status == ANTIC_WAIT_NEXT)) + as_antic_stop(ad); + + return; + } + + if (rq_mergeable(rq)) { + as_add_arq_hash(ad, arq); + + if (!q->last_merge) + q->last_merge = &rq->queuelist; + } + + as_add_request(ad, arq); +} + +/* + * as_queue_empty tells us if there are requests left in the device. It may + * not be the case that a driver can get the next request even if the queue + * is not empty - it is used in the block layer to check for plugging and + * merging opportunities + */ +static int as_queue_empty(request_queue_t *q) +{ + struct as_data *ad = q->elevator.elevator_data; + + if (!list_empty(&ad->fifo_list[REQ_ASYNC]) + || !list_empty(&ad->fifo_list[REQ_SYNC]) + || !list_empty(ad->dispatch)) + return 0; + + return 1; +} + +static struct request * +as_former_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + struct rb_node *rbprev = rb_prev(&arq->rb_node); + struct request *ret = NULL; + + if (rbprev) + ret = rb_entry_arq(rbprev)->request; + + return ret; +} + +static struct request * +as_latter_request(request_queue_t *q, struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + struct rb_node *rbnext = rb_next(&arq->rb_node); + struct request *ret = NULL; + + if (rbnext) + ret = rb_entry_arq(rbnext)->request; + + return ret; +} + +static int +as_merge(request_queue_t *q, struct list_head **insert, struct bio *bio) +{ + struct as_data *ad = q->elevator.elevator_data; + sector_t rb_key = bio->bi_sector + bio_sectors(bio); + struct request *__rq; + int ret; + + /* + * try last_merge to avoid going to hash + */ + ret = elv_try_last_merge(q, bio); + if (ret != ELEVATOR_NO_MERGE) { + __rq = list_entry_rq(q->last_merge); + goto out_insert; + } + + /* + * see if the merge hash can satisfy a back merge + */ + __rq = as_find_arq_hash(ad, bio->bi_sector); + if (__rq) { + BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector); + + if (elv_rq_merge_ok(__rq, bio)) { + ret = ELEVATOR_BACK_MERGE; + goto out; + } + } + + /* + * check for front merge + */ + __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio)); + if (__rq) { + BUG_ON(rb_key != rq_rb_key(__rq)); + + if (elv_rq_merge_ok(__rq, bio)) { + ret = ELEVATOR_FRONT_MERGE; + goto out; + } + } + + return ELEVATOR_NO_MERGE; +out: + q->last_merge = &__rq->queuelist; +out_insert: + if (ret) + as_hot_arq_hash(ad, RQ_DATA(__rq)); + *insert = &__rq->queuelist; + return ret; +} + +static void as_merged_request(request_queue_t *q, struct request *req) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(req); + + /* + * hash always needs to be repositioned, key is end sector + */ + as_del_arq_hash(arq); + as_add_arq_hash(ad, arq); + + /* + * if the merge was a front merge, we need to reposition request + */ + if (rq_rb_key(req) != arq->rb_key) { + as_del_arq_rb(ad, arq); + as_add_arq_rb(ad, arq); + /* + * Note! At this stage of this and the next function, our next + * request may not be optimal - eg the request may have "grown" + * behind the disk head. We currently don't bother adjusting. + */ + } + + q->last_merge = &req->queuelist; +} + +static void +as_merged_requests(request_queue_t *q, struct request *req, + struct request *next) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(req); + struct as_rq *anext = RQ_DATA(next); + + BUG_ON(!arq); + BUG_ON(!anext); + + /* + * reposition arq (this is the merged request) in hash, and in rbtree + * in case of a front merge + */ + as_del_arq_hash(arq); + as_add_arq_hash(ad, arq); + + if (rq_rb_key(req) != arq->rb_key) { + as_del_arq_rb(ad, arq); + as_add_arq_rb(ad, arq); + } + + /* + * if anext expires before arq, assign its expire time to arq + * and move into anext position (anext will be deleted) in fifo + */ + if (!list_empty(&arq->fifo) && !list_empty(&anext->fifo)) { + if (time_before(anext->expires, arq->expires)) { + list_move(&arq->fifo, &anext->fifo); + arq->expires = anext->expires; + /* + * Don't copy here but swap, because when anext is + * removed below, it must contain the unused context + */ + swap_io_context(&arq->io_context, &anext->io_context); + } + } + + /* + * kill knowledge of next, this one is a goner + */ + as_remove_queued_request(q, next); + put_io_context(anext->io_context); +} + +/* + * This is executed in a "deferred" process context, by kblockd. It calls the + * driver's request_fn so the driver can submit that request. + * + * IMPORTANT! This guy will reenter the elevator, so set up all queue global + * state before calling, and don't rely on any state over calls. + * + * FIXME! dispatch queue is not a queue at all! + */ +static void as_work_handler(void *data) +{ + struct request_queue *q = data; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + if (as_next_request(q)) + q->request_fn(q); + spin_unlock_irqrestore(q->queue_lock, flags); +} + +static void as_put_request(request_queue_t *q, struct request *rq) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = RQ_DATA(rq); + + if (!arq) { + WARN_ON(1); + return; + } + + mempool_free(arq, ad->arq_pool); + rq->elevator_private = NULL; +} + +static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask) +{ + struct as_data *ad = q->elevator.elevator_data; + struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask); + + if (arq) { + RB_CLEAR(&arq->rb_node); + arq->request = rq; + arq->state = AS_RQ_NEW; + arq->io_context = NULL; + INIT_LIST_HEAD(&arq->hash); + arq->hash_valid_count = 0; + INIT_LIST_HEAD(&arq->fifo); + rq->elevator_private = arq; + return 0; + } + + return 1; +} + +static int as_may_queue(request_queue_t *q, int rw) +{ + int ret = 0; + struct as_data *ad = q->elevator.elevator_data; + struct io_context *ioc; + if (ad->antic_status == ANTIC_WAIT_REQ || + ad->antic_status == ANTIC_WAIT_NEXT) { + ioc = as_get_io_context(); + if (ad->io_context == ioc) + ret = 1; + put_io_context(ioc); + } + + return ret; +} + +static void as_exit(request_queue_t *q, elevator_t *e) +{ + struct as_data *ad = e->elevator_data; + + del_timer_sync(&ad->antic_timer); + kblockd_flush(); + + BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC])); + BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC])); + + mempool_destroy(ad->arq_pool); + put_io_context(ad->io_context); + kfree(ad->hash); + kfree(ad); +} + +/* + * initialize elevator private data (as_data), and alloc a arq for + * each request on the free lists + */ +static int as_init(request_queue_t *q, elevator_t *e) +{ + struct as_data *ad; + int i; + + if (!arq_pool) + return -ENOMEM; + + ad = kmalloc(sizeof(*ad), GFP_KERNEL); + if (!ad) + return -ENOMEM; + memset(ad, 0, sizeof(*ad)); + + ad->q = q; /* Identify what queue the data belongs to */ + + ad->hash = kmalloc(sizeof(struct list_head)*AS_HASH_ENTRIES,GFP_KERNEL); + if (!ad->hash) { + kfree(ad); + return -ENOMEM; + } + + ad->arq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, arq_pool); + if (!ad->arq_pool) { + kfree(ad->hash); + kfree(ad); + return -ENOMEM; + } + + /* anticipatory scheduling helpers */ + ad->antic_timer.function = as_antic_timeout; + ad->antic_timer.data = (unsigned long)q; + init_timer(&ad->antic_timer); + INIT_WORK(&ad->antic_work, as_work_handler, q); + + for (i = 0; i < AS_HASH_ENTRIES; i++) + INIT_LIST_HEAD(&ad->hash[i]); + + INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]); + INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]); + ad->sort_list[REQ_SYNC] = RB_ROOT; + ad->sort_list[REQ_ASYNC] = RB_ROOT; + ad->dispatch = &q->queue_head; + ad->fifo_expire[REQ_SYNC] = default_read_expire; + ad->fifo_expire[REQ_ASYNC] = default_write_expire; + ad->hash_valid_count = 1; + ad->antic_expire = default_antic_expire; + ad->batch_expire[REQ_SYNC] = default_read_batch_expire; + ad->batch_expire[REQ_ASYNC] = default_write_batch_expire; + e->elevator_data = ad; + + ad->current_batch_expires = jiffies + ad->batch_expire[REQ_SYNC]; + ad->write_batch_count = ad->batch_expire[REQ_ASYNC] / 10; + if (ad->write_batch_count < 2) + ad->write_batch_count = 2; + return 0; +} + +/* + * sysfs parts below + */ +struct as_fs_entry { + struct attribute attr; + ssize_t (*show)(struct as_data *, char *); + ssize_t (*store)(struct as_data *, const char *, size_t); +}; + +static ssize_t +as_var_show(unsigned int var, char *page) +{ + var = (var * 1000) / HZ; + return sprintf(page, "%d\n", var); +} + +static ssize_t +as_var_store(unsigned long *var, const char *page, size_t count) +{ + unsigned long tmp; + char *p = (char *) page; + + tmp = simple_strtoul(p, &p, 10); + if (tmp != 0) { + tmp = (tmp * HZ) / 1000; + if (tmp == 0) + tmp = 1; + } + *var = tmp; + return count; +} + +#define SHOW_FUNCTION(__FUNC, __VAR) \ +static ssize_t __FUNC(struct as_data *ad, char *page) \ +{ \ + return as_var_show(__VAR, (page)); \ +} +SHOW_FUNCTION(as_readexpire_show, ad->fifo_expire[REQ_SYNC]); +SHOW_FUNCTION(as_writeexpire_show, ad->fifo_expire[REQ_ASYNC]); +SHOW_FUNCTION(as_anticexpire_show, ad->antic_expire); +SHOW_FUNCTION(as_read_batchexpire_show, ad->batch_expire[REQ_SYNC]); +SHOW_FUNCTION(as_write_batchexpire_show, ad->batch_expire[REQ_ASYNC]); +#undef SHOW_FUNCTION + +#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ +static ssize_t __FUNC(struct as_data *ad, const char *page, size_t count) \ +{ \ + int ret = as_var_store(__PTR, (page), count); \ + if (*(__PTR) < (MIN)) \ + *(__PTR) = (MIN); \ + else if (*(__PTR) > (MAX)) \ + *(__PTR) = (MAX); \ + return ret; \ +} +STORE_FUNCTION(as_readexpire_store, &ad->fifo_expire[REQ_SYNC], 0, INT_MAX); +STORE_FUNCTION(as_writeexpire_store, &ad->fifo_expire[REQ_ASYNC], 0, INT_MAX); +STORE_FUNCTION(as_anticexpire_store, &ad->antic_expire, 0, INT_MAX); +STORE_FUNCTION(as_read_batchexpire_store, + &ad->batch_expire[REQ_SYNC], 0, INT_MAX); +STORE_FUNCTION(as_write_batchexpire_store, + &ad->batch_expire[REQ_ASYNC], 0, INT_MAX); +#undef STORE_FUNCTION + +static struct as_fs_entry as_readexpire_entry = { + .attr = {.name = "read_expire", .mode = S_IRUGO | S_IWUSR }, + .show = as_readexpire_show, + .store = as_readexpire_store, +}; +static struct as_fs_entry as_writeexpire_entry = { + .attr = {.name = "write_expire", .mode = S_IRUGO | S_IWUSR }, + .show = as_writeexpire_show, + .store = as_writeexpire_store, +}; +static struct as_fs_entry as_anticexpire_entry = { + .attr = {.name = "antic_expire", .mode = S_IRUGO | S_IWUSR }, + .show = as_anticexpire_show, + .store = as_anticexpire_store, +}; +static struct as_fs_entry as_read_batchexpire_entry = { + .attr = {.name = "read_batch_expire", .mode = S_IRUGO | S_IWUSR }, + .show = as_read_batchexpire_show, + .store = as_read_batchexpire_store, +}; +static struct as_fs_entry as_write_batchexpire_entry = { + .attr = {.name = "write_batch_expire", .mode = S_IRUGO | S_IWUSR }, + .show = as_write_batchexpire_show, + .store = as_write_batchexpire_store, +}; + +static struct attribute *default_attrs[] = { + &as_readexpire_entry.attr, + &as_writeexpire_entry.attr, + &as_anticexpire_entry.attr, + &as_read_batchexpire_entry.attr, + &as_write_batchexpire_entry.attr, + NULL, +}; + +#define to_as(atr) container_of((atr), struct as_fs_entry, attr) + +static ssize_t +as_attr_show(struct kobject *kobj, struct attribute *attr, char *page) +{ + elevator_t *e = container_of(kobj, elevator_t, kobj); + struct as_fs_entry *entry = to_as(attr); + + if (!entry->show) + return 0; + + return entry->show(e->elevator_data, page); +} + +static ssize_t +as_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t length) +{ + elevator_t *e = container_of(kobj, elevator_t, kobj); + struct as_fs_entry *entry = to_as(attr); + + if (!entry->store) + return -EINVAL; + + return entry->store(e->elevator_data, page, length); +} + +static struct sysfs_ops as_sysfs_ops = { + .show = as_attr_show, + .store = as_attr_store, +}; + +struct kobj_type as_ktype = { + .sysfs_ops = &as_sysfs_ops, + .default_attrs = default_attrs, +}; + +static int __init as_slab_setup(void) +{ + arq_pool = kmem_cache_create("as_arq", sizeof(struct as_rq), + 0, 0, NULL, NULL); + + if (!arq_pool) + panic("as: can't init slab pool\n"); + + return 0; +} + +subsys_initcall(as_slab_setup); + +elevator_t iosched_as = { + .elevator_merge_fn = as_merge, + .elevator_merged_fn = as_merged_request, + .elevator_merge_req_fn = as_merged_requests, + .elevator_next_req_fn = as_next_request, + .elevator_add_req_fn = as_insert_request, + .elevator_remove_req_fn = as_remove_request, + .elevator_queue_empty_fn = as_queue_empty, + .elevator_completed_req_fn = as_completed_request, + .elevator_former_req_fn = as_former_request, + .elevator_latter_req_fn = as_latter_request, + .elevator_set_req_fn = as_set_request, + .elevator_put_req_fn = as_put_request, + .elevator_may_queue_fn = as_may_queue, + .elevator_init_fn = as_init, + .elevator_exit_fn = as_exit, + + .elevator_ktype = &as_ktype, +}; + +EXPORT_SYMBOL(iosched_as); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 2933c96a614..03165688ccc 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1887,7 +1887,7 @@ queue: BUG(); if (( c = cmd_alloc(h, 1)) == NULL) - goto startio; + goto full; blkdev_dequeue_request(creq); @@ -1960,8 +1960,9 @@ queue: h->maxQsinceinit = h->Qdepth; goto queue; -startio: +full: blk_stop_queue(q); +startio: start_io(h); } diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 00b56d022b0..485561a037f 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -361,17 +361,31 @@ void elv_put_request(request_queue_t *q, struct request *rq) e->elevator_put_req_fn(q, rq); } -int elv_register_queue(struct gendisk *disk) +int elv_may_queue(request_queue_t *q, int rw) { - request_queue_t *q = disk->queue; - elevator_t *e; + elevator_t *e = &q->elevator; + + if (e->elevator_may_queue_fn) + return e->elevator_may_queue_fn(q, rw); + + return 0; +} + +void elv_completed_request(request_queue_t *q, struct request *rq) +{ + elevator_t *e = &q->elevator; - if (!q) - return -ENXIO; + if (e->elevator_completed_req_fn) + e->elevator_completed_req_fn(q, rq); +} + +int elv_register_queue(struct request_queue *q) +{ + elevator_t *e; e = &q->elevator; - e->kobj.parent = kobject_get(&disk->kobj); + e->kobj.parent = kobject_get(&q->kobj); if (!e->kobj.parent) return -EBUSY; @@ -381,14 +395,12 @@ int elv_register_queue(struct gendisk *disk) return kobject_register(&e->kobj); } -void elv_unregister_queue(struct gendisk *disk) +void elv_unregister_queue(struct request_queue *q) { - request_queue_t *q = disk->queue; - if (q) { elevator_t * e = &q->elevator; kobject_unregister(&e->kobj); - kobject_put(&disk->kobj); + kobject_put(&q->kobj); } } @@ -408,5 +420,6 @@ EXPORT_SYMBOL(__elv_add_request); EXPORT_SYMBOL(elv_next_request); EXPORT_SYMBOL(elv_remove_request); EXPORT_SYMBOL(elv_queue_empty); +EXPORT_SYMBOL(elv_completed_request); EXPORT_SYMBOL(elevator_exit); EXPORT_SYMBOL(elevator_init); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index ca2332522f9..40ff4c76558 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3767,7 +3767,7 @@ static int floppy_open(struct inode * inode, struct file * filp) * Needed so that programs such as fdrawcmd still can work on write * protected disks */ if ((filp->f_mode & 2) || - (inode->i_sb && (permission(inode,2) == 0))) + (inode->i_sb && (permission(inode,2, NULL) == 0))) filp->private_data = (void*) 8; if (UFDCS->rawcmd == 1) diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 889b8753c29..361aee8ab25 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -191,7 +191,7 @@ void add_disk(struct gendisk *disk) blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); - elv_register_queue(disk); + blk_register_queue(disk); } EXPORT_SYMBOL(add_disk); @@ -199,7 +199,7 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ void unlink_gendisk(struct gendisk *disk) { - elv_unregister_queue(disk); + blk_unregister_queue(disk); blk_unregister_region(MKDEV(disk->major, disk->first_minor), disk->minors); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 6287b0064d9..f03a77be82b 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -42,40 +42,50 @@ static kmem_cache_t *request_cachep; static LIST_HEAD(blk_plug_list); static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; +static wait_queue_head_t congestion_wqh[2]; + /* - * Number of requests per queue. This many for reads and for writes (twice - * this number, total). + * Controlling structure to kblockd */ -static int queue_nr_requests; +static struct workqueue_struct *kblockd_workqueue; unsigned long blk_max_low_pfn, blk_max_pfn; -static wait_queue_head_t congestion_wqh[2]; + +/* Amount of time in which a process may batch requests */ +#define BLK_BATCH_TIME (HZ/50UL) + +/* Number of requests a "batching" process may submit */ +#define BLK_BATCH_REQ 32 /* - * Return the threshold (number of free requests) at which the queue is + * Return the threshold (number of used requests) at which the queue is * considered to be congested. It include a little hysteresis to keep the * context switch rate down. */ -static inline int queue_congestion_on_threshold(void) +static inline int queue_congestion_on_threshold(struct request_queue *q) { int ret; - ret = queue_nr_requests / 8 - 1; - if (ret < 0) - ret = 1; + ret = q->nr_requests - (q->nr_requests / 8) + 1; + + if (ret > q->nr_requests) + ret = q->nr_requests; + return ret; } /* * The threshold at which a queue is considered to be uncongested */ -static inline int queue_congestion_off_threshold(void) +static inline int queue_congestion_off_threshold(struct request_queue *q) { int ret; - ret = queue_nr_requests / 8 + 1; - if (ret > queue_nr_requests) - ret = queue_nr_requests; + ret = q->nr_requests - (q->nr_requests / 8) - 1; + + if (ret < 1) + ret = 1; + return ret; } @@ -188,6 +198,7 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) /* * set defaults */ + q->nr_requests = BLKDEV_MAX_RQ; q->max_phys_segments = MAX_PHYS_SEGMENTS; q->max_hw_segments = MAX_HW_SEGMENTS; q->make_request_fn = mfn; @@ -441,13 +452,15 @@ void blk_queue_free_tags(request_queue_t *q) q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED); } -static int init_tag_map(struct blk_queue_tag *tags, int depth) +static int +init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) { int bits, i; - if (depth > (queue_nr_requests*2)) { - depth = (queue_nr_requests*2); - printk(KERN_ERR "%s: adjusted depth to %d\n", __FUNCTION__, depth); + if (depth > q->nr_requests * 2) { + depth = q->nr_requests * 2; + printk(KERN_ERR "%s: adjusted depth to %d\n", + __FUNCTION__, depth); } tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); @@ -476,7 +489,6 @@ fail: return -ENOMEM; } - /** * blk_queue_init_tags - initialize the queue tag info * @q: the request queue for the device @@ -490,7 +502,7 @@ int blk_queue_init_tags(request_queue_t *q, int depth) if (!tags) goto fail; - if (init_tag_map(tags, depth)) + if (init_tag_map(q, tags, depth)) goto fail; INIT_LIST_HEAD(&tags->busy_list); @@ -540,7 +552,7 @@ int blk_queue_resize_tags(request_queue_t *q, int new_depth) tag_map = bqt->tag_map; max_depth = bqt->real_max_depth; - if (init_tag_map(bqt, new_depth)) + if (init_tag_map(q, bqt, new_depth)) return -ENOMEM; memcpy(bqt->tag_index, tag_index, max_depth * sizeof(struct request *)); @@ -1022,7 +1034,7 @@ static inline void __generic_unplug_device(request_queue_t *q) /* * was plugged, fire request_fn if queue has stuff to do */ - if (!elv_queue_empty(q)) + if (elv_next_request(q)) q->request_fn(q); } @@ -1057,7 +1069,7 @@ static void blk_unplug_timeout(unsigned long data) { request_queue_t *q = (request_queue_t *)data; - schedule_work(&q->unplug_work); + kblockd_schedule_work(&q->unplug_work); } /** @@ -1072,8 +1084,8 @@ static void blk_unplug_timeout(unsigned long data) **/ void blk_start_queue(request_queue_t *q) { - if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) - schedule_work(&q->unplug_work); + clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); + schedule_work(&q->unplug_work); } /** @@ -1165,7 +1177,7 @@ void blk_cleanup_queue(request_queue_t * q) elevator_exit(q); del_timer_sync(&q->unplug_timer); - flush_scheduled_work(); + kblockd_flush(); mempool_destroy(rl->rq_pool); @@ -1180,6 +1192,8 @@ static int blk_init_free_list(request_queue_t *q) struct request_list *rl = &q->rq; rl->count[READ] = rl->count[WRITE] = 0; + init_waitqueue_head(&rl->wait[READ]); + init_waitqueue_head(&rl->wait[WRITE]); rl->rq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep); @@ -1191,6 +1205,18 @@ static int blk_init_free_list(request_queue_t *q) static int __make_request(request_queue_t *, struct bio *); +static elevator_t *chosen_elevator = &iosched_as; + +static int __init elevator_setup(char *str) +{ + if (!strcmp(str, "deadline")) + chosen_elevator = &iosched_deadline; + if (!strcmp(str, "as")) + chosen_elevator = &iosched_as; + return 1; +} +__setup("elevator=", elevator_setup); + /** * blk_init_queue - prepare a request queue for use with a block device * @q: The &request_queue_t to be initialised @@ -1222,11 +1248,20 @@ static int __make_request(request_queue_t *, struct bio *); int blk_init_queue(request_queue_t *q, request_fn_proc *rfn, spinlock_t *lock) { int ret; + static int printed; if (blk_init_free_list(q)) return -ENOMEM; - if ((ret = elevator_init(q, &iosched_deadline))) { + if (!printed) { + printed = 1; + if (chosen_elevator == &iosched_deadline) + printk("deadline elevator\n"); + else if (chosen_elevator == &iosched_as) + printk("anticipatory scheduling elevator\n"); + } + + if ((ret = elevator_init(q, chosen_elevator))) { blk_cleanup_queue(q); return ret; } @@ -1271,6 +1306,60 @@ static inline struct request *blk_alloc_request(request_queue_t *q,int gfp_mask) return NULL; } +/* + * ioc_batching returns true if the ioc is a valid batching request and + * should be given priority access to a request. + */ +static inline int ioc_batching(struct io_context *ioc) +{ + if (!ioc) + return 0; + + /* + * Make sure the process is able to allocate at least 1 request + * even if the batch times out, otherwise we could theoretically + * lose wakeups. + */ + return ioc->nr_batch_requests == BLK_BATCH_REQ || + (ioc->nr_batch_requests > 0 + && time_before(jiffies, ioc->last_waited + BLK_BATCH_TIME)); +} + +/* + * ioc_set_batching sets ioc to be a new "batcher" if it is not one. This + * will cause the process to be a "batcher" on all queues in the system. This + * is the behaviour we want though - once it gets a wakeup it should be given + * a nice run. + */ +void ioc_set_batching(struct io_context *ioc) +{ + if (!ioc || ioc_batching(ioc)) + return; + + ioc->nr_batch_requests = BLK_BATCH_REQ; + ioc->last_waited = jiffies; +} + +/* + * A request has just been released. Account for it, update the full and + * congestion status, wake up any waiters. Called under q->queue_lock. + */ +static void freed_request(request_queue_t *q, int rw) +{ + struct request_list *rl = &q->rq; + + rl->count[rw]--; + if (rl->count[rw] < queue_congestion_off_threshold(q)) + clear_queue_congested(q, rw); + if (rl->count[rw]+1 <= q->nr_requests) { + smp_mb(); + if (waitqueue_active(&rl->wait[rw])) + wake_up(&rl->wait[rw]); + if (!waitqueue_active(&rl->wait[rw])) + blk_clear_queue_full(q, rw); + } +} + #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) /* * Get a free request, queue_lock must not be held @@ -1279,26 +1368,54 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask) { struct request *rq = NULL; struct request_list *rl = &q->rq; + struct io_context *ioc = get_io_context(gfp_mask); spin_lock_irq(q->queue_lock); - if (rl->count[rw] == BLKDEV_MAX_RQ) { + if (rl->count[rw]+1 >= q->nr_requests) { + /* + * The queue will fill after this allocation, so set it as + * full, and mark this process as "batching". This process + * will be allowed to complete a batch of requests, others + * will be blocked. + */ + if (!blk_queue_full(q, rw)) { + ioc_set_batching(ioc); + blk_set_queue_full(q, rw); + } + } + + if (blk_queue_full(q, rw) + && !ioc_batching(ioc) && !elv_may_queue(q, rw)) { + /* + * The queue is full and the allocating process is not a + * "batcher", and not exempted by the IO scheduler + */ spin_unlock_irq(q->queue_lock); goto out; } + rl->count[rw]++; - if ((BLKDEV_MAX_RQ - rl->count[rw]) < queue_congestion_on_threshold()) + if (rl->count[rw] >= queue_congestion_on_threshold(q)) set_queue_congested(q, rw); spin_unlock_irq(q->queue_lock); rq = blk_alloc_request(q, gfp_mask); if (!rq) { + /* + * Allocation failed presumably due to memory. Undo anything + * we might have messed up. + * + * Allocating task should really be put onto the front of the + * wait queue, but this is pretty rare. + */ spin_lock_irq(q->queue_lock); - rl->count[rw]--; - if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold()) - clear_queue_congested(q, rw); + freed_request(q, rw); spin_unlock_irq(q->queue_lock); goto out; } + + if (ioc_batching(ioc)) + ioc->nr_batch_requests--; INIT_LIST_HEAD(&rq->queuelist); @@ -1321,22 +1438,44 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask) rq->sense = NULL; out: + put_io_context(ioc); return rq; } /* - * No available requests for this queue, unplug the device. + * No available requests for this queue, unplug the device and wait for some + * requests to become available. */ static struct request *get_request_wait(request_queue_t *q, int rw) { + DEFINE_WAIT(wait); struct request *rq; generic_unplug_device(q); do { + struct request_list *rl = &q->rq; + + prepare_to_wait_exclusive(&rl->wait[rw], &wait, + TASK_UNINTERRUPTIBLE); + rq = get_request(q, rw, GFP_NOIO); - if (!rq) - blk_congestion_wait(rw, HZ / 50); + if (!rq) { + struct io_context *ioc; + + io_schedule(); + + /* + * After sleeping, we become a "batching" process and + * will be able to allocate at least one request, and + * up to a big batch of them for a small period time. + * See ioc_batching, ioc_set_batching + */ + ioc = get_io_context(GFP_NOIO); + ioc_set_batching(ioc); + put_io_context(ioc); + } + finish_wait(&rl->wait[rw], &wait); } while (!rq); return rq; @@ -1348,10 +1487,10 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) BUG_ON(rw != READ && rw != WRITE); - rq = get_request(q, rw, gfp_mask); - - if (!rq && (gfp_mask & __GFP_WAIT)) + if (gfp_mask & __GFP_WAIT) rq = get_request_wait(q, rw); + else + rq = get_request(q, rw, gfp_mask); return rq; } @@ -1482,6 +1621,8 @@ void __blk_put_request(request_queue_t *q, struct request *req) if (unlikely(--req->ref_count)) return; + elv_completed_request(req->q, req); + req->rq_status = RQ_INACTIVE; req->q = NULL; req->rl = NULL; @@ -1496,10 +1637,7 @@ void __blk_put_request(request_queue_t *q, struct request *req) BUG_ON(!list_empty(&req->queuelist)); blk_free_request(q, req); - - rl->count[rw]--; - if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold()) - clear_queue_congested(q, rw); + freed_request(q, rw); } } @@ -1786,13 +1924,12 @@ out: __blk_put_request(q, freereq); if (blk_queue_plugged(q)) { - int nr_queued = q->rq.count[0] + q->rq.count[1]; + int nr_queued = q->rq.count[READ] + q->rq.count[WRITE]; if (nr_queued == q->unplug_thresh) __generic_unplug_device(q); } spin_unlock_irq(q->queue_lock); - return 0; end_io: @@ -1800,7 +1937,6 @@ end_io: return 0; } - /* * If bio->bi_dev is a partition, remap the location */ @@ -1850,8 +1986,7 @@ static inline void blk_partition_remap(struct bio *bio) * bio happens to be merged with someone else, and may change bi_dev and * bi_sector for remaps as it sees fit. So the values of these fields * should NOT be depended on after the call to generic_make_request. - * - * */ + */ void generic_make_request(struct bio *bio) { request_queue_t *q; @@ -2282,31 +2417,287 @@ void blk_rq_prep_restart(struct request *rq) rq->current_nr_sectors = rq->hard_cur_sectors; } +int kblockd_schedule_work(struct work_struct *work) +{ + return queue_work(kblockd_workqueue, work); +} + +void kblockd_flush(void) +{ + flush_workqueue(kblockd_workqueue); +} + int __init blk_dev_init(void) { int i; + kblockd_workqueue = create_workqueue("kblockd"); + if (!kblockd_workqueue) + panic("Failed to create kblockd\n"); + request_cachep = kmem_cache_create("blkdev_requests", sizeof(struct request), 0, 0, NULL, NULL); if (!request_cachep) panic("Can't create request pool slab cache\n"); - queue_nr_requests = BLKDEV_MAX_RQ; - - printk("block request queues:\n"); - printk(" %d/%d requests per read queue\n", BLKDEV_MIN_RQ, queue_nr_requests); - printk(" %d/%d requests per write queue\n", BLKDEV_MIN_RQ, queue_nr_requests); - printk(" enter congestion at %d\n", queue_congestion_on_threshold()); - printk(" exit congestion at %d\n", queue_congestion_off_threshold()); - blk_max_low_pfn = max_low_pfn; blk_max_pfn = max_pfn; for (i = 0; i < ARRAY_SIZE(congestion_wqh); i++) init_waitqueue_head(&congestion_wqh[i]); return 0; +} + +static atomic_t nr_io_contexts = ATOMIC_INIT(0); + +/* + * IO Context helper functions + */ +void put_io_context(struct io_context *ioc) +{ + if (ioc == NULL) + return; + + BUG_ON(atomic_read(&ioc->refcount) == 0); + + if (atomic_dec_and_test(&ioc->refcount)) { + if (ioc->aic && ioc->aic->dtor) + ioc->aic->dtor(ioc->aic); + kfree(ioc); + atomic_dec(&nr_io_contexts); + } +} + +/* Called by the exitting task */ +void exit_io_context(void) +{ + unsigned long flags; + struct io_context *ioc; + + local_irq_save(flags); + ioc = current->io_context; + if (ioc) { + if (ioc->aic && ioc->aic->exit) + ioc->aic->exit(ioc->aic); + put_io_context(ioc); + current->io_context = NULL; + } else + WARN_ON(1); + local_irq_restore(flags); +} + +/* + * If the current task has no IO context then create one and initialise it. + * If it does have a context, take a ref on it. + * + * This is always called in the context of the task which submitted the I/O. + * But weird things happen, so we disable local interrupts to ensure exclusive + * access to *current. + */ +struct io_context *get_io_context(int gfp_flags) +{ + struct task_struct *tsk = current; + unsigned long flags; + struct io_context *ret; + + local_irq_save(flags); + ret = tsk->io_context; + if (ret == NULL) { + ret = kmalloc(sizeof(*ret), GFP_ATOMIC); + if (ret) { + atomic_inc(&nr_io_contexts); + atomic_set(&ret->refcount, 1); + ret->pid = tsk->pid; + ret->last_waited = jiffies; /* doesn't matter... */ + ret->nr_batch_requests = 0; /* because this is 0 */ + ret->aic = NULL; + tsk->io_context = ret; + } + } + if (ret) + atomic_inc(&ret->refcount); + local_irq_restore(flags); + return ret; +} + +void copy_io_context(struct io_context **pdst, struct io_context **psrc) +{ + struct io_context *src = *psrc; + struct io_context *dst = *pdst; + + if (src) { + BUG_ON(atomic_read(&src->refcount) == 0); + atomic_inc(&src->refcount); + put_io_context(dst); + *pdst = src; + } +} + +void swap_io_context(struct io_context **ioc1, struct io_context **ioc2) +{ + struct io_context *temp; + temp = *ioc1; + *ioc1 = *ioc2; + *ioc2 = temp; +} + + +/* + * sysfs parts below + */ +struct queue_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct request_queue *, char *); + ssize_t (*store)(struct request_queue *, const char *, size_t); +}; + +static ssize_t +queue_var_show(unsigned int var, char *page) +{ + return sprintf(page, "%d\n", var); +} + +static ssize_t +queue_var_store(unsigned long *var, const char *page, size_t count) +{ + char *p = (char *) page; + + *var = simple_strtoul(p, &p, 10); + return count; +} + +static ssize_t queue_requests_show(struct request_queue *q, char *page) +{ + return queue_var_show(q->nr_requests, (page)); +} + +static ssize_t +queue_requests_store(struct request_queue *q, const char *page, size_t count) +{ + struct request_list *rl = &q->rq; + + int ret = queue_var_store(&q->nr_requests, page, count); + if (q->nr_requests < BLKDEV_MIN_RQ) + q->nr_requests = BLKDEV_MIN_RQ; + + if (rl->count[READ] >= queue_congestion_on_threshold(q)) + set_queue_congested(q, READ); + else if (rl->count[READ] < queue_congestion_off_threshold(q)) + clear_queue_congested(q, READ); + + if (rl->count[WRITE] >= queue_congestion_on_threshold(q)) + set_queue_congested(q, WRITE); + else if (rl->count[WRITE] < queue_congestion_off_threshold(q)) + clear_queue_congested(q, WRITE); + + if (rl->count[READ] >= q->nr_requests) { + blk_set_queue_full(q, READ); + } else if (rl->count[READ]+1 <= q->nr_requests) { + blk_clear_queue_full(q, READ); + wake_up(&rl->wait[READ]); + } + + if (rl->count[WRITE] >= q->nr_requests) { + blk_set_queue_full(q, WRITE); + } else if (rl->count[WRITE]+1 <= q->nr_requests) { + blk_clear_queue_full(q, WRITE); + wake_up(&rl->wait[WRITE]); + } + return ret; +} + +static struct queue_sysfs_entry queue_requests_entry = { + .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, + .show = queue_requests_show, + .store = queue_requests_store, }; +static struct attribute *default_attrs[] = { + &queue_requests_entry.attr, + NULL, +}; + +#define to_queue(atr) container_of((atr), struct queue_sysfs_entry, attr) + +static ssize_t +queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) +{ + struct queue_sysfs_entry *entry = to_queue(attr); + struct request_queue *q; + + q = container_of(kobj, struct request_queue, kobj); + if (!entry->show) + return 0; + + return entry->show(q, page); +} + +static ssize_t +queue_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t length) +{ + struct queue_sysfs_entry *entry = to_queue(attr); + struct request_queue *q; + + q = container_of(kobj, struct request_queue, kobj); + if (!entry->store) + return -EINVAL; + + return entry->store(q, page, length); +} + +static struct sysfs_ops queue_sysfs_ops = { + .show = queue_attr_show, + .store = queue_attr_store, +}; + +struct kobj_type queue_ktype = { + .sysfs_ops = &queue_sysfs_ops, + .default_attrs = default_attrs, +}; + +int blk_register_queue(struct gendisk *disk) +{ + int ret; + + request_queue_t *q = disk->queue; + + if (!q) + return -ENXIO; + + q->kobj.parent = kobject_get(&disk->kobj); + if (!q->kobj.parent) + return -EBUSY; + + snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); + q->kobj.ktype = &queue_ktype; + + ret = kobject_register(&q->kobj); + if (ret < 0) + return ret; + + ret = elv_register_queue(q); + if (ret) { + kobject_unregister(&q->kobj); + return ret; + } + + return 0; +} + +void blk_unregister_queue(struct gendisk *disk) +{ + request_queue_t *q = disk->queue; + + if (q) { + elv_unregister_queue(q); + + kobject_unregister(&q->kobj); + kobject_put(&disk->kobj); + } +} + + EXPORT_SYMBOL(process_that_request_first); EXPORT_SYMBOL(end_that_request_first); EXPORT_SYMBOL(end_that_request_chunk); diff --git a/drivers/char/agp/amd-k8-agp.c b/drivers/char/agp/amd-k8-agp.c index 91492df0546..c89c41cca85 100644 --- a/drivers/char/agp/amd-k8-agp.c +++ b/drivers/char/agp/amd-k8-agp.c @@ -342,6 +342,14 @@ static struct pci_device_id agp_amdk8_pci_table[] __initdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_755, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { } }; diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 9d0f14a70b4..06d3ffa396d 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -345,13 +345,29 @@ static struct agp_device_ids via_agp_device_ids[] __initdata = { }, /* dummy final entry, always present */ }; + +/* + * VIA's AGP3 chipsets do magick to put the AGP bridge compliant + * with the same standards version as the graphics card. + */ +static void check_via_agp3 (struct agp_bridge_data *bridge) +{ + u8 reg; + + pci_read_config_byte(bridge->dev, VIA_AGPSEL, ®); + /* Check AGP 2.0 compatibility mode. */ + if ((reg & (1<<1))==0) + bridge->driver = &via_agp3_driver; +} + + static int __init 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; int j = 0; - u8 cap_ptr, reg; + u8 cap_ptr; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) @@ -386,36 +402,21 @@ found: bridge->capndx = cap_ptr; bridge->driver = &via_driver; - switch (pdev->device) { - case PCI_DEVICE_ID_VIA_8367_0: - /* - * Garg, there are KT400s with KT266 IDs. - */ + /* + * Garg, there are KT400s with KT266 IDs. + */ + if (pdev->device == PCI_DEVICE_ID_VIA_8367_0) { /* Is there a KT400 subsystem ? */ - if (pdev->subsystem_device != PCI_DEVICE_ID_VIA_8377_0) - break; - - printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n"); - /*FALLTHROUGH*/ - case PCI_DEVICE_ID_VIA_8377_0: - /* - * The KT400 does magick to put the AGP bridge compliant - * with the same standards version as the graphics card. - */ - pci_read_config_byte(pdev, VIA_AGPSEL, ®); - /* Check AGP 2.0 compatibility mode. */ - if ((reg & (1<<1))==0) { - bridge->driver = &via_agp3_driver; - break; + if (pdev->subsystem_device == PCI_DEVICE_ID_VIA_8377_0) { + printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n"); + check_via_agp3(bridge); } - /*FALLTHROUGH*/ - default: - break; } - - bridge->dev = pdev; - bridge->capndx = cap_ptr; + /* If this is an AGP3 bridge, check which mode its in and adjust. */ + get_agp_version(bridge); + if (bridge->major_version >= 3) + check_via_agp3(bridge); /* Fill in the mode register */ pci_read_config_dword(pdev, diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 115a16feb0d..980c1b7dc8e 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.10 2003/05/13 16:06:03 paulkf Exp $ + * $Id: synclink_cs.c,v 4.13 2003/06/18 15:29:32 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -467,7 +467,6 @@ static int break_on_load=0; * assigned major number. May be forced as module parameter. */ static int ttymajor=0; -static int cuamajor=0; static int debug_level = 0; static int maxframe[MAX_DEVICE_COUNT] = {0,}; @@ -485,7 +484,6 @@ MODULE_PARM(irq_list, "1-4i"); MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); -MODULE_PARM(cuamajor,"i"); MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); @@ -493,7 +491,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.10 $"; +static char *driver_version = "$Revision: 4.13 $"; static struct tty_driver *serial_driver; @@ -1290,7 +1288,7 @@ void dcd_change(MGSLPC_INFO *info) (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); if (info->serial_signals & SerialSignal_DCD) wake_up_interruptible(&info->open_wait); - else if (!(info->flags & ASYNC_CALLOUT_NOHUP)) { + else { if (debug_level >= DEBUG_LEVEL_ISR) printk("doing serial hangup..."); if (info->tty) @@ -2538,14 +2536,17 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) { MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; - if (!info || mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) + if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_close(%s) entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->count); - if (!info->count || tty_hung_up_p(filp)) + if (!info->count) + return; + + if (tty_hung_up_p(filp)) goto cleanup; if ((tty->count == 1) && (info->count != 1)) { @@ -2822,16 +2823,11 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) info = mgslpc_device_list; while(info && info->line != line) info = info->next_device; - if ( !info ){ - printk("%s(%d):Can't find specified device on open (line=%d)\n", - __FILE__,__LINE__,line); + if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) return -ENODEV; - } tty->driver_data = info; info->tty = tty; - if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open")) - return -ENODEV; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", @@ -2879,6 +2875,8 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) cleanup: if (retval) { + if (tty->count == 1) + info->tty = 0; /* tty layer will release tty struct */ if(info->count) info->count--; } diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index b68901640a1..ccb3804e497 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.9 2003/05/06 21:18:51 paulkf Exp $ + * $Id: synclink.c,v 4.12 2003/06/18 15:29:32 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -910,7 +910,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.9 $"; +static char *driver_version = "$Revision: 4.12 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -3170,14 +3170,17 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) { struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; - if (!info || mgsl_paranoia_check(info, tty->name, "mgsl_close")) + if (mgsl_paranoia_check(info, tty->name, "mgsl_close")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_close(%s) entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->count); - if (!info->count || tty_hung_up_p(filp)) + if (!info->count) + return; + + if (tty_hung_up_p(filp)) goto cleanup; if ((tty->count == 1) && (info->count != 1)) { @@ -3493,16 +3496,11 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) info = mgsl_device_list; while(info && info->line != line) info = info->next_device; - if ( !info ){ - printk("%s(%d):Can't find specified device on open (line=%d)\n", - __FILE__,__LINE__,line); + if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) return -ENODEV; - } tty->driver_data = info; info->tty = tty; - if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) - return -ENODEV; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_open(%s), old ref count = %d\n", @@ -3562,6 +3560,8 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) cleanup: if (retval) { + if (tty->count == 1) + info->tty = 0; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -4461,7 +4461,6 @@ static struct tty_operations mgsl_ops = { int mgsl_init_tty(void); int mgsl_init_tty() { - struct mgsl_struct *info; serial_driver = alloc_tty_driver(mgsl_device_count); if (!serial_driver) return -ENOMEM; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 99e5a937be5..46c23f3f1e6 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.8 2003/04/21 17:46:55 paulkf Exp $ + * $Id: synclinkmp.c,v 4.12 2003/06/18 15:29:33 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -481,7 +481,6 @@ static int break_on_load=0; * assigned major number. May be forced as module parameter. */ static int ttymajor=0; -static int cuamajor=0; /* * Array of user specified options for ISA adapters. @@ -492,13 +491,12 @@ static int dosyncppp[MAX_DEVICES] = {0,}; MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); -MODULE_PARM(cuamajor,"i"); MODULE_PARM(debug_level,"i"); MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i"); MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.8 $"; +static char *driver_version = "$Revision: 4.12 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -739,12 +737,8 @@ static int open(struct tty_struct *tty, struct file *filp) info = synclinkmp_device_list; while(info && info->line != line) info = info->next_device; - if ( !info ){ - printk("%s(%d):%s Can't find specified device on open (line=%d)\n", - __FILE__,__LINE__,info->device_name,line); + if (sanity_check(info, tty->name, "open")) return -ENODEV; - } - if ( info->init_error ) { printk("%s(%d):%s device is not allocated, init error=%d\n", __FILE__,__LINE__,info->device_name,info->init_error); @@ -753,8 +747,6 @@ static int open(struct tty_struct *tty, struct file *filp) tty->driver_data = info; info->tty = tty; - if (sanity_check(info, tty->name, "open")) - return -ENODEV; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open(), old ref count = %d\n", @@ -802,6 +794,8 @@ static int open(struct tty_struct *tty, struct file *filp) cleanup: if (retval) { + if (tty->count == 1) + info->tty = 0; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -816,14 +810,17 @@ static void close(struct tty_struct *tty, struct file *filp) { SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; - if (!info || sanity_check(info, tty->name, "close")) + if (sanity_check(info, tty->name, "close")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->count); - if (!info->count || tty_hung_up_p(filp)) + if (!info->count) + return; + + if (tty_hung_up_p(filp)) goto cleanup; if ((tty->count == 1) && (info->count != 1)) { @@ -3775,8 +3772,6 @@ static struct tty_operations ops = { static int __init synclinkmp_init(void) { - SLMP_INFO *info; - if (break_on_load) { synclinkmp_get_text_ptr(); BREAKPOINT(); diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b05d3948b8e..85b512348ac 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -1,4 +1,7 @@ -#CPUfreq governors and cross-arch helpers +# CPUfreq governors +obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o + +# CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o -obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o + diff --git a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c index dc89b83710b..d314e526af9 100644 --- a/drivers/cpufreq/proc_intf.c +++ b/drivers/cpufreq/proc_intf.c @@ -13,6 +13,8 @@ #include +#define CPUFREQ_ALL_CPUS ((NR_CPUS)) + /** * cpufreq_parse_policy - parse a policy string * @input_string: the string to parse. diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index a5241c65d63..116298c5f7b 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -1,7 +1,7 @@ /* * EISA bus support functions for sysfs. * - * (C) 2002 Marc Zyngier + * (C) 2002, 2003 Marc Zyngier * * This code is released under the GPL version 2. */ @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,7 @@ struct eisa_device_info { char name[DEVICE_NAME_SIZE]; }; -struct eisa_device_info __initdata eisa_table[] = { +static struct eisa_device_info __initdata eisa_table[] = { #ifdef CONFIG_EISA_NAMES #include "devlist.h" #endif @@ -32,6 +33,30 @@ struct eisa_device_info __initdata eisa_table[] = { #define EISA_INFOS (sizeof (eisa_table) / (sizeof (struct eisa_device_info))) +#define EISA_MAX_FORCED_DEV 16 +#define EISA_FORCED_OFFSET 2 + +static int enable_dev[EISA_MAX_FORCED_DEV + EISA_FORCED_OFFSET] = { 1, EISA_MAX_FORCED_DEV, }; +static int disable_dev[EISA_MAX_FORCED_DEV + EISA_FORCED_OFFSET] = { 1, EISA_MAX_FORCED_DEV, }; + +static int is_forced_dev (int *forced_tab, + struct eisa_root_device *root, + struct eisa_device *edev) +{ + int i, x; + + for (i = 0; i < EISA_MAX_FORCED_DEV; i++) { + if (!forced_tab[EISA_FORCED_OFFSET + i]) + return 0; + + x = (root->bus_nr << 8) | edev->slot; + if (forced_tab[EISA_FORCED_OFFSET + i] == x) + return 1; + } + + return 0; +} + static void __init eisa_name_device (struct eisa_device *edev) { int i; @@ -92,7 +117,8 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; while (strlen (eids->sig)) { - if (!strcmp (eids->sig, edev->id.sig)) { + if (!strcmp (eids->sig, edev->id.sig) && + edev->state & EISA_CONFIG_ENABLED) { edev->id.driver_data = eids->driver_data; return 1; } @@ -132,41 +158,160 @@ static ssize_t eisa_show_sig (struct device *dev, char *buf) static DEVICE_ATTR(signature, S_IRUGO, eisa_show_sig, NULL); -static int __init eisa_register_device (struct eisa_root_device *root, - struct eisa_device *edev, - char *sig, int slot) +static ssize_t eisa_show_state (struct device *dev, char *buf) +{ + struct eisa_device *edev = to_eisa_device (dev); + return sprintf (buf,"%d\n", edev->state & EISA_CONFIG_ENABLED); +} + +static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL); + +static int __init eisa_init_device (struct eisa_root_device *root, + struct eisa_device *edev, + int slot) { + char *sig; + unsigned long sig_addr; + int i; + + sig_addr = SLOT_ADDRESS (root, slot) + EISA_VENDOR_ID_OFFSET; + + if (!(sig = decode_eisa_sig (sig_addr))) + return -1; /* No EISA device here */ + memcpy (edev->id.sig, sig, EISA_SIG_LEN); edev->slot = slot; + edev->state = inb (SLOT_ADDRESS (root, slot) + EISA_CONFIG_OFFSET) & EISA_CONFIG_ENABLED; edev->base_addr = SLOT_ADDRESS (root, slot); - edev->dma_mask = 0xffffffff; /* Default DMA mask */ + edev->dma_mask = root->dma_mask; /* Default DMA mask */ eisa_name_device (edev); edev->dev.parent = root->dev; edev->dev.bus = &eisa_bus_type; edev->dev.dma_mask = &edev->dma_mask; sprintf (edev->dev.bus_id, "%02X:%02X", root->bus_nr, slot); - edev->res.name = edev->dev.name; + for (i = 0; i < EISA_MAX_RESOURCES; i++) + edev->res[i].name = edev->dev.name; + + if (is_forced_dev (enable_dev, root, edev)) + edev->state = EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED; + + if (is_forced_dev (disable_dev, root, edev)) + edev->state = EISA_CONFIG_FORCED; + + return 0; +} +static int __init eisa_register_device (struct eisa_device *edev) +{ if (device_register (&edev->dev)) return -1; device_create_file (&edev->dev, &dev_attr_signature); + device_create_file (&edev->dev, &dev_attr_enabled); + + return 0; +} + +static int __init eisa_request_resources (struct eisa_root_device *root, + struct eisa_device *edev, + int slot) +{ + int i; + + for (i = 0; i < EISA_MAX_RESOURCES; i++) { + /* Don't register resource for slot 0, since this is + * very likely to fail... :-( Instead, grab the EISA + * id, now we can display something in /proc/ioports. + */ + + /* Only one region for mainboard */ + if (!slot && i > 0) { + edev->res[i].start = edev->res[i].end = 0; + continue; + } + + if (slot) { + edev->res[i].name = NULL; + edev->res[i].start = SLOT_ADDRESS (root, slot) + (i * 0x400); + edev->res[i].end = edev->res[i].start + 0xff; + edev->res[i].flags = IORESOURCE_IO; + } else { + edev->res[i].name = NULL; + edev->res[i].start = SLOT_ADDRESS (root, slot) + EISA_VENDOR_ID_OFFSET; + edev->res[i].end = edev->res[i].start + 3; + edev->res[i].flags = IORESOURCE_BUSY; + } + + if (request_resource (root->res, &edev->res[i])) + goto failed; + } return 0; + + failed: + while (--i >= 0) + release_resource (&edev->res[i]); + + return -1; +} + +static void __init eisa_release_resources (struct eisa_device *edev) +{ + int i; + + for (i = 0; i < EISA_MAX_RESOURCES; i++) + if (edev->res[i].start || edev->res[i].end) + release_resource (&edev->res[i]); } static int __init eisa_probe (struct eisa_root_device *root) { int i, c; - char *str; - unsigned long sig_addr; struct eisa_device *edev; printk (KERN_INFO "EISA: Probing bus %d at %s\n", root->bus_nr, root->dev->name); + + /* First try to get hold of slot 0. If there is no device + * here, simply fail, unless root->force_probe is set. */ - for (c = 0, i = 0; i <= root->slots; i++) { + if (!(edev = kmalloc (sizeof (*edev), GFP_KERNEL))) { + printk (KERN_ERR "EISA: Couldn't allocate mainboard slot\n"); + return -ENOMEM; + } + + memset (edev, 0, sizeof (*edev)); + + if (eisa_request_resources (root, edev, 0)) { + printk (KERN_WARNING \ + "EISA: Cannot allocate resource for mainboard\n"); + kfree (edev); + if (!root->force_probe) + return -EBUSY; + goto force_probe; + } + + if (eisa_init_device (root, edev, 0)) { + eisa_release_resources (edev); + kfree (edev); + if (!root->force_probe) + return -ENODEV; + goto force_probe; + } + + printk (KERN_INFO "EISA: Mainboard %s detected.\n", edev->id.sig); + + if (eisa_register_device (edev)) { + printk (KERN_ERR "EISA: Failed to register %s\n", + edev->id.sig); + eisa_release_resources (edev); + kfree (edev); + } + + force_probe: + + for (c = 0, i = 1; i <= root->slots; i++) { if (!(edev = kmalloc (sizeof (*edev), GFP_KERNEL))) { printk (KERN_ERR "EISA: Out of memory for slot %d\n", i); @@ -175,24 +320,7 @@ static int __init eisa_probe (struct eisa_root_device *root) memset (edev, 0, sizeof (*edev)); - /* Don't register resource for slot 0, since this is - * very likely to fail... :-( Instead, grab the EISA - * id, now we can display something in /proc/ioports. - */ - - if (i) { - edev->res.name = NULL; - edev->res.start = SLOT_ADDRESS (root, i); - edev->res.end = edev->res.start + 0xfff; - edev->res.flags = IORESOURCE_IO; - } else { - edev->res.name = NULL; - edev->res.start = SLOT_ADDRESS (root, i) + EISA_VENDOR_ID_OFFSET; - edev->res.end = edev->res.start + 3; - edev->res.flags = IORESOURCE_BUSY; - } - - if (request_resource (root->res, &edev->res)) { + if (eisa_request_resources (root, edev, i)) { printk (KERN_WARNING \ "Cannot allocate resource for EISA slot %d\n", i); @@ -200,30 +328,41 @@ static int __init eisa_probe (struct eisa_root_device *root) continue; } - sig_addr = SLOT_ADDRESS (root, i) + EISA_VENDOR_ID_OFFSET; - - if (!(str = decode_eisa_sig (sig_addr))) { - release_resource (&edev->res); + if (eisa_init_device (root, edev, i)) { + eisa_release_resources (edev); kfree (edev); continue; } - if (!i) - printk (KERN_INFO "EISA: Motherboard %s detected\n", - str); - else { - printk (KERN_INFO "EISA: slot %d : %s detected.\n", - i, str); - - c++; + printk (KERN_INFO "EISA: slot %d : %s detected", + i, edev->id.sig); + + switch (edev->state) { + case EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED: + printk (" (forced enabled)"); + break; + + case EISA_CONFIG_FORCED: + printk (" (forced disabled)"); + break; + + case 0: + printk (" (disabled)"); + break; } + + printk (".\n"); - if (eisa_register_device (root, edev, str, i)) { - printk (KERN_ERR "EISA: Failed to register %s\n", str); - release_resource (&edev->res); + c++; + + if (eisa_register_device (edev)) { + printk (KERN_ERR "EISA: Failed to register %s\n", + edev->id.sig); + eisa_release_resources (edev); kfree (edev); } } + printk (KERN_INFO "EISA: Detected %d card%s.\n", c, c == 1 ? "" : "s"); return 0; @@ -274,6 +413,13 @@ static int __init eisa_init (void) return 0; } +/* Couldn't use intarray with checking on... :-( */ +#undef param_check_intarray +#define param_check_intarray(name, p) + +module_param(enable_dev, intarray, 0444); +module_param(disable_dev, intarray, 0444); + postcore_initcall (eisa_init); EXPORT_SYMBOL (eisa_bus_type); diff --git a/drivers/eisa/eisa.ids b/drivers/eisa/eisa.ids index 819f9470d7c..ed69837d8b7 100644 --- a/drivers/eisa/eisa.ids +++ b/drivers/eisa/eisa.ids @@ -504,6 +504,7 @@ DTK0001 "DTK PLM-3300I 80486 EISA Board" DTK0003 "DTK PLM-3331P EISACACHE486 33/25/50 MHZ" ECS0580 "DI-580A EISA SCSI Host Adapter" ECS0590 "DI-590 EISA SCSI Cache Host Adapter" +EGL0101 "Eagle Technology EP3210 EtherXpert EISA Adapter" ELS8041 "ELSA WINNER 1000 Enhanced VGA" ETI1001 "NE3300 Ethernet Rev. C & D" EVX0002 "PN-3000 System Board" @@ -515,6 +516,9 @@ FIX1516 "15-16MB Memory Hole Patch - Netserver LF/LC 5/66" FSI2001 "ESA-200 ATM" FSI2002 "ESA-200A ATM" FSI2003 "ESA-200E ATM" +GCI0101 "Gateway G/Ethernet 32EB -- 32-Bit EISA Bus Master Ethernet Adpater" +GCI0102 "Gateway G/Ethernet 32EB -- 32-Bit EISA Bus Master Ethernet Adapter" +GCI0103 "Gateway G/Ethernet 32EB -- 32-Bit EISA Bus Master Ethernet Adapter" GDT2001 "GDT2000/GDT2020 Fast-SCSI Cache Controller - Rev. 1.0" GDT3001 "GDT3000/GDT3020 Dual Channel SCSI Controller - Rev. 1.0" GDT3002 "GDT30x0A Cache Controller" @@ -1138,12 +1142,14 @@ NON0501 "c't Universal 16-Bit Sound Adapter" NON0601 "c't Universal 8-Bit Adapter" NSS0011 "Newport Systems Solutions WNIC Adapter" NVL0701 "Novell NE3200 Bus Master Ethernet" +NVL0702 "Novell NE3200T Bus Master Ethernet" NVL0901 "Novell NE2100 Ethernet/Cheapernet Adapter" NVL1001 "Novell NMSL (Netware Mirrored Server Link)" NVL1201 "Novell NE32HUB 32-bit Base EISA Adapter" NVL1301 "Novell NE32HUB 32-bit TPE EISA Adapter" NVL1401 "Novell NE32HUB PME ISA Adapter" NVL1501 "Novell NE2000PLUS Ethernet Adapter" +NVL1801 "Eagle Technology NE3210 EISA Ethernet LAN Adapter" OLC0701 "Olicom ISA 16/4 Token-Ring Network Adapter" OLC0702 "Olicom OC-3117, ISA 16/4 Adapter (NIC)" OLC0801 "OC-3118 Olicom ISA 16/4 Token-Ring Network Adapter" diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index 635c2997a04..3dedb1997b8 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -20,7 +20,7 @@ static struct eisa_root_device pci_eisa_root; static int __devinit pci_eisa_init (struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { int rc; @@ -35,6 +35,7 @@ static int __devinit pci_eisa_init (struct pci_dev *pdev, pci_eisa_root.res = pdev->bus->resource[0]; pci_eisa_root.bus_base_addr = pdev->bus->resource[0]->start; pci_eisa_root.slots = EISA_MAX_SLOTS; + pci_eisa_root.dma_mask = pdev->dma_mask; if (eisa_root_register (&pci_eisa_root)) { printk (KERN_ERR "pci_eisa : Could not register EISA root\n"); diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c index 12f684f9dc8..3c384ccfe48 100644 --- a/drivers/eisa/virtual_root.c +++ b/drivers/eisa/virtual_root.c @@ -7,12 +7,22 @@ * This code is released under the GPL version 2. */ +#include #include #include #include #include +#include #include +#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_EISA_VLB_PRIMING) +#define EISA_FORCE_PROBE_DEFAULT 1 +#else +#define EISA_FORCE_PROBE_DEFAULT 0 +#endif + +static int force_probe = EISA_FORCE_PROBE_DEFAULT; + /* The default EISA device parent (virtual root device). * Now use a platform device, since that's the obvious choice. */ @@ -29,6 +39,7 @@ static struct eisa_root_device eisa_bus_root = { .bus_base_addr = 0, .res = &ioport_resource, .slots = EISA_MAX_SLOTS, + .dma_mask = 0xffffffff, }; static int virtual_eisa_root_init (void) @@ -39,6 +50,8 @@ static int virtual_eisa_root_init (void) return r; } + eisa_bus_root.force_probe = force_probe; + eisa_root_dev.dev.driver_data = &eisa_bus_root; if (eisa_root_register (&eisa_bus_root)) { @@ -51,4 +64,6 @@ static int virtual_eisa_root_init (void) return 0; } +module_param (force_probe, int, 0444); + device_initcall (virtual_eisa_root_init); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 1f68755e239..1008bd73aac 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -385,11 +385,21 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) int autoprobe = 0; unsigned long cookie = 0; - if (IDE_CONTROL_REG && !hwif->irq) { - autoprobe = 1; - cookie = probe_irq_on(); - /* enable device irq */ - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + /* + * Disable device irq unless we need to + * probe for it. Otherwise we'll get spurious + * interrupts during the identify-phase that + * the irq handler isn't expecting. + */ + if (IDE_CONTROL_REG) { + u8 ctl = drive->ctl | 2; + if (!hwif->irq) { + autoprobe = 1; + cookie = probe_irq_on(); + /* enable device irq */ + ctl &= ~2; + } + hwif->OUTB(ctl, IDE_CONTROL_REG); } retval = actual_try_to_identify(drive, cmd); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index f8630422466..8cdcb9a0a73 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1514,6 +1514,8 @@ pmac_ide_setup_dma(struct device_node *np, int ix) ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout; ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune; ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq; + ide_hwifs[ix].ide_dma_queued_on = &__ide_dma_queued_on; + ide_hwifs[ix].ide_dma_queued_off = &__ide_dma_queued_off; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO if (!noautodma) diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 3fd94842cfb..e93e9e3fece 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -56,6 +56,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index 1c087bfc934..9f4b7cdd2f6 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -76,6 +76,8 @@ static struct pmu_sleep_notifier serial_sleep_notifier = { in the order we want. */ #define RECOVERY_DELAY eieio() +static struct tty_driver *serial_driver; + struct mac_zschannel zs_channels[NUM_CHANNELS]; struct mac_serial zs_soft[NUM_CHANNELS]; @@ -2093,12 +2095,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if (info->flags & ZILOG_CLOSING) { interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ZILOG_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else return -EAGAIN; -#endif } /* @@ -2139,14 +2136,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ZILOG_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else retval = -EAGAIN; -#endif break; } if (!(info->flags & ZILOG_CLOSING) && @@ -2222,12 +2212,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) (info->flags & ZILOG_CLOSING)) { if (info->flags & ZILOG_CLOSING) interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ZILOG_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else return -EAGAIN; -#endif } /* diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index 9cccfba214c..abb054dc30e 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 3b0c9c469ea..d15606605f8 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -211,9 +211,10 @@ static int blktrans_ioctl(struct inode *inode, struct file *file, case HDIO_GETGEO: if (tr->getgeo) { struct hd_geometry g; + int ret; memset(&g, 0, sizeof(g)); - int ret = tr->getgeo(dev, &g); + ret = tr->getgeo(dev, &g); if (ret) return ret; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index af7c1e4281f..a72eb1909f4 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2070,7 +2070,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance, RTL_W16 (IntrStatus, ackstat); DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", - dev->name, ackstat, status, RTL_R16 (IntrStatus)); + dev->name, status, ackstat, RTL_R16 (IntrStatus)); if (netif_running (dev) && (status & RxAckBits)) rtl8139_rx_interrupt (dev, tp, ioaddr); diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c index 9d8d7a1e85a..d102b207be1 100644 --- a/drivers/net/e100/e100_main.c +++ b/drivers/net/e100/e100_main.c @@ -1085,10 +1085,10 @@ e100_xmit_frame(struct sk_buff *skb, struct net_device *dev) goto exit1; } - e100_prepare_xmit_buff(bdp, skb); - bdp->drv_stats.net_stats.tx_bytes += skb->len; + e100_prepare_xmit_buff(bdp, skb); + dev->trans_start = jiffies; exit1: diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 8891f273269..1908c7b08f3 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -224,6 +224,5 @@ struct e1000_adapter { uint32_t pci_state[16]; - char ifname[IFNAMSIZ]; }; #endif /* _E1000_H_ */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c979393d925..1e001f83822 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1112,8 +1112,9 @@ e1000_ethtool_test(struct e1000_adapter *adapter, if(if_running) e1000_down(adapter); - - e1000_reset(adapter); + else + e1000_reset(adapter); + if(e1000_reg_test(adapter, &data[0])) eth_test->flags |= ETH_TEST_FL_FAILED; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 539533515e2..efd366fbe84 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -135,6 +135,41 @@ e1000_phy_init_script(struct e1000_hw *hw) e1000_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000); e1000_write_phy_reg(hw,0x0000,0x3300); + + + if(hw->mac_type == e1000_82547) { + uint16_t fused, fine, coarse; + + /* Move to analog registers page */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_ANALOG_REGS_PAGE); + + e1000_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused); + + if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { + e1000_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused); + + fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; + coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; + + if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { + coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10; + fine -= IGP01E1000_ANALOG_FUSE_FINE_1; + } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH) + fine -= IGP01E1000_ANALOG_FUSE_FINE_10; + + fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) | + (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) | + (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK); + + e1000_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_CONTROL, fused); + e1000_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS, + IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL); + } + /* Return to first page of registers */ + e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, + IGP01E1000_IEEE_REGS_PAGE); + } } } @@ -259,10 +294,20 @@ e1000_reset_hw(struct e1000_hw *hw) msec_delay(5); } - if(hw->mac_type > e1000_82543) - E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); - else - E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); + switch(hw->mac_type) { + case e1000_82544: + case e1000_82540: + case e1000_82545: + case e1000_82546: + case e1000_82541: + /* These controllers can't ack the 64-bit write when issuing the + * reset, so use IO-mapping as a workaround to issue the reset */ + E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST)); + break; + default: + E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); + break; + } /* Force a reload from the EEPROM if necessary */ if(hw->mac_type < e1000_82540) { @@ -687,7 +732,8 @@ e1000_setup_fiber_link(struct e1000_hw *hw) static int32_t e1000_setup_copper_link(struct e1000_hw *hw) { - uint32_t ctrl, led_ctrl; + uint32_t ctrl; + uint32_t led_ctrl; int32_t ret_val; uint16_t i; uint16_t phy_data; @@ -2249,7 +2295,8 @@ e1000_write_phy_reg(struct e1000_hw *hw, void e1000_phy_hw_reset(struct e1000_hw *hw) { - uint32_t ctrl, ctrl_ext, led_ctrl; + uint32_t ctrl, ctrl_ext; + uint32_t led_ctrl; DEBUGFUNC("e1000_phy_hw_reset"); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index bfb91bc5d8a..f650d8c52a5 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1668,6 +1668,7 @@ struct e1000_hw { #define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ #define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ +#define IGP01E1000_IEEE_REGS_PAGE 0x0000 /* IGP01E1000 Specific Registers */ #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */ #define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */ @@ -1690,6 +1691,7 @@ struct e1000_hw { * speed = 1000 Mbps. */ #define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_ANALOG_REGS_PAGE 0x20C0 #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ @@ -1980,6 +1982,22 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] = #define IGP01E1000_GMII_FLEX_SPD 0x10 /* Enable flexible speed * on Link-Up */ #define IGP01E1000_GMII_SPD 0x20 /* Enable SPD */ +/* IGP01E1000 Analog Register */ +#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x0011 +#define IGP01E1000_ANALOG_FUSE_STATUS 0x0010 +#define IGP01E1000_ANALOG_FUSE_CONTROL 0x001C +#define IGP01E1000_ANALOG_FUSE_BYPASS 0x001E + +#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000 +#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80 +#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070 +#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100 +#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002 + +#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040 +#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010 +#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080 +#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500 /* Bit definitions for valid PHY IDs. */ #define M88E1000_E_PHY_ID 0x01410C50 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f3dcd6998a5..8f734f3cb9b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -30,6 +30,14 @@ /* Change Log * + * 5.1.13 5/28/03 + * o Bug fix: request_irq() failure resulted in freeing resources twice! + * [Don Fry (brazilnut@us.ibm.com)] + * o Bug fix: fix VLAN support on ppc64 [Mark Rakes (mrakes@vivato.net)] + * o Bug fix: missing Tx cleanup opportunities during interrupt handling. + * o Bug fix: alloc_etherdev failure didn't cleanup regions in probe. + * o Cleanup: s/int/unsigned int/ for descriptor ring indexes. + * * 5.1.11 5/6/03 * o Feature: Added support for 82546EB (Quad-port) hardware. * o Feature: Added support for Diagnostics through Ethtool. @@ -38,26 +46,11 @@ * o Bug fix: TSO bug fixes. * * 5.0.42 3/5/03 - * o Feature: Added support for 82541 and 82547 hardware. - * o Feature: Added support for Intel Gigabit PHY (IGP) and a variety of - * eeproms. - * o Feature: Added support for TCP Segmentation Offload (TSO). - * o Feature: Added MII ioctl. - * o Feature: Added support for statistics reporting through ethtool. - * o Cleanup: Removed proprietary hooks for ANS. - * o Cleanup: Miscellaneous code changes to improve CPU utilization. - * - Replaced "%" with conditionals and "+-" operators. - * - Implemented dynamic Interrupt Throttle Rate (ITR). - * - Reduced expensive PCI reads of ICR in interrupt. - * o Bug fix: Request IRQ after descriptor ring setup to avoid panic in - * shared interrupt instances. - * - * 4.4.18 11/27/02 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.1.11-k1"; +char e1000_driver_version[] = "5.1.13-k1"; char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table @@ -128,6 +121,7 @@ static void e1000_update_stats(struct e1000_adapter *adapter); static inline void e1000_irq_disable(struct e1000_adapter *adapter); static inline void e1000_irq_enable(struct e1000_adapter *adapter); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); +static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); #ifdef CONFIG_E1000_NAPI static int e1000_clean(struct net_device *netdev, int *budget); static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, @@ -135,7 +129,6 @@ static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter, #else static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter); #endif -static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter); static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter); static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, @@ -248,12 +241,8 @@ e1000_up(struct e1000_adapter *adapter) e1000_alloc_rx_buffers(adapter); if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, - netdev->name, netdev)) { - e1000_reset_hw(&adapter->hw); - e1000_free_tx_resources(adapter); - e1000_free_rx_resources(adapter); + netdev->name, netdev)) return -1; - } mod_timer(&adapter->watchdog_timer, jiffies); e1000_irq_enable(adapter); @@ -504,9 +493,9 @@ err_sw_init: err_eeprom: iounmap(adapter->hw.hw_addr); err_ioremap: - pci_release_regions(pdev); kfree(netdev); err_alloc_etherdev: + pci_release_regions(pdev); return -ENOMEM; } @@ -981,35 +970,38 @@ e1000_free_tx_resources(struct e1000_adapter *adapter) static void e1000_clean_tx_ring(struct e1000_adapter *adapter) { + struct e1000_desc_ring *tx_ring = &adapter->tx_ring; + struct e1000_buffer *buffer_info; struct pci_dev *pdev = adapter->pdev; unsigned long size; - int i; + unsigned int i; /* Free all the Tx ring sk_buffs */ - for(i = 0; i < adapter->tx_ring.count; i++) { - if(adapter->tx_ring.buffer_info[i].skb) { + for(i = 0; i < tx_ring->count; i++) { + buffer_info = &tx_ring->buffer_info[i]; + if(buffer_info->skb) { pci_unmap_page(pdev, - adapter->tx_ring.buffer_info[i].dma, - adapter->tx_ring.buffer_info[i].length, + buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); - dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb); + dev_kfree_skb(buffer_info->skb); - adapter->tx_ring.buffer_info[i].skb = NULL; + buffer_info->skb = NULL; } } - size = sizeof(struct e1000_buffer) * adapter->tx_ring.count; - memset(adapter->tx_ring.buffer_info, 0, size); + size = sizeof(struct e1000_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); /* Zero out the descriptor ring */ - memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size); + memset(tx_ring->desc, 0, tx_ring->size); - adapter->tx_ring.next_to_use = 0; - adapter->tx_ring.next_to_clean = 0; + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; E1000_WRITE_REG(&adapter->hw, TDH, 0); E1000_WRITE_REG(&adapter->hw, TDT, 0); @@ -1025,17 +1017,17 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter) static void e1000_free_rx_resources(struct e1000_adapter *adapter) { + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct pci_dev *pdev = adapter->pdev; e1000_clean_rx_ring(adapter); - kfree(adapter->rx_ring.buffer_info); - adapter->rx_ring.buffer_info = NULL; + kfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; - pci_free_consistent(pdev, adapter->rx_ring.size, - adapter->rx_ring.desc, adapter->rx_ring.dma); + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); - adapter->rx_ring.desc = NULL; + rx_ring->desc = NULL; } /** @@ -1046,35 +1038,38 @@ e1000_free_rx_resources(struct e1000_adapter *adapter) static void e1000_clean_rx_ring(struct e1000_adapter *adapter) { + struct e1000_desc_ring *rx_ring = &adapter->rx_ring; + struct e1000_buffer *buffer_info; struct pci_dev *pdev = adapter->pdev; unsigned long size; - int i; + unsigned int i; /* Free all the Rx ring sk_buffs */ - for(i = 0; i < adapter->rx_ring.count; i++) { - if(adapter->rx_ring.buffer_info[i].skb) { + for(i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + if(buffer_info->skb) { pci_unmap_single(pdev, - adapter->rx_ring.buffer_info[i].dma, - adapter->rx_ring.buffer_info[i].length, + buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); - dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb); + dev_kfree_skb(buffer_info->skb); - adapter->rx_ring.buffer_info[i].skb = NULL; + buffer_info->skb = NULL; } } - size = sizeof(struct e1000_buffer) * adapter->rx_ring.count; - memset(adapter->rx_ring.buffer_info, 0, size); + size = sizeof(struct e1000_buffer) * rx_ring->count; + memset(rx_ring->buffer_info, 0, size); /* Zero out the descriptor ring */ - memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size); + memset(rx_ring->desc, 0, rx_ring->size); - adapter->rx_ring.next_to_clean = 0; - adapter->rx_ring.next_to_use = 0; + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; E1000_WRITE_REG(&adapter->hw, RDH, 0); E1000_WRITE_REG(&adapter->hw, RDT, 0); @@ -1324,7 +1319,7 @@ e1000_watchdog(unsigned long data) struct e1000_adapter *adapter = (struct e1000_adapter *) data; struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; - int i; + unsigned int i; e1000_check_for_link(&adapter->hw); @@ -1410,7 +1405,7 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb) { #ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; - int i; + unsigned int i; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; uint16_t ipcse, tucse, mss; @@ -1461,7 +1456,7 @@ static inline boolean_t e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb) { struct e1000_context_desc *context_desc; - int i; + unsigned int i; uint8_t css, cso; if(skb->ip_summed == CHECKSUM_HW) { @@ -1494,18 +1489,21 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, unsigned int first) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; - int len = skb->len, offset = 0, size, count = 0, i; + struct e1000_buffer *buffer_info; + int len = skb->len; + unsigned int offset = 0, size, count = 0, i; #ifdef NETIF_F_TSO - int tso = skb_shinfo(skb)->tso_size; + unsigned int tso = skb_shinfo(skb)->tso_size; #endif - int nr_frags = skb_shinfo(skb)->nr_frags; - int f; + unsigned int nr_frags = skb_shinfo(skb)->nr_frags; + unsigned int f; len -= skb->data_len; i = tx_ring->next_to_use; while(len) { + buffer_info = &tx_ring->buffer_info[i]; size = min(len, E1000_MAX_DATA_PER_TXD); #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs @@ -1513,13 +1511,13 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, if(tso && !nr_frags && size == len && size > 4) size -= 4; #endif - tx_ring->buffer_info[i].length = size; - tx_ring->buffer_info[i].dma = + buffer_info->length = size; + buffer_info->dma = pci_map_single(adapter->pdev, skb->data + offset, size, PCI_DMA_TODEVICE); - tx_ring->buffer_info[i].time_stamp = jiffies; + buffer_info->time_stamp = jiffies; len -= size; offset += size; @@ -1535,6 +1533,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, offset = 0; while(len) { + buffer_info = &tx_ring->buffer_info[i]; size = min(len, E1000_MAX_DATA_PER_TXD); #ifdef NETIF_F_TSO /* Workaround for premature desc write-backs @@ -1542,14 +1541,14 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, if(tso && f == (nr_frags-1) && size == len && size > 4) size -= 4; #endif - tx_ring->buffer_info[i].length = size; - tx_ring->buffer_info[i].dma = + buffer_info->length = size; + buffer_info->dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset + offset, size, PCI_DMA_TODEVICE); - tx_ring->buffer_info[i].time_stamp = jiffies; + buffer_info->time_stamp = jiffies; len -= size; offset += size; @@ -1557,7 +1556,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, if(++i == tx_ring->count) i = 0; } } - if(--i < 0) i = tx_ring->count - 1; + i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; @@ -1569,8 +1568,9 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) { struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; + struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; - int i; + unsigned int i; if(tx_flags & E1000_TX_FLAGS_TSO) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | @@ -1591,10 +1591,11 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags) i = tx_ring->next_to_use; while(count--) { + buffer_info = &tx_ring->buffer_info[i]; tx_desc = E1000_TX_DESC(*tx_ring, i); - tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); + tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); tx_desc->lower.data = - cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length); + cpu_to_le32(txd_lower | buffer_info->length); tx_desc->upper.data = cpu_to_le32(txd_upper); if(++i == tx_ring->count) i = 0; } @@ -1660,7 +1661,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev->priv; unsigned int first; - int tx_flags = 0; + unsigned int tx_flags = 0; if(skb->len <= 0) { dev_kfree_skb_any(skb); @@ -1972,7 +1973,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct e1000_adapter *adapter = netdev->priv; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); #ifndef CONFIG_E1000_NAPI - int i; + unsigned int i; #endif if(!icr) @@ -1996,7 +1997,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) } #else for(i = 0; i < E1000_MAX_INTR; i++) - if(!e1000_clean_rx_irq(adapter) && + if(!e1000_clean_rx_irq(adapter) & !e1000_clean_tx_irq(adapter)) break; #endif @@ -2044,7 +2045,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) struct pci_dev *pdev = adapter->pdev; struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; - int i, eop, cleaned = FALSE; + unsigned int i, eop; + boolean_t cleaned = FALSE; i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; @@ -2110,16 +2112,19 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; struct sk_buff *skb; unsigned long flags; uint32_t length; uint8_t last_byte; - int i, cleaned = FALSE; + unsigned int i; + boolean_t cleaned = FALSE; i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); while(rx_desc->status & E1000_RXD_STAT_DD) { + buffer_info = &rx_ring->buffer_info[i]; #ifdef CONFIG_E1000_NAPI if(*work_done >= work_to_do) @@ -2131,11 +2136,11 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) cleaned = TRUE; pci_unmap_single(pdev, - rx_ring->buffer_info[i].dma, - rx_ring->buffer_info[i].length, + buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); - skb = rx_ring->buffer_info[i].skb; + skb = buffer_info->skb; length = le16_to_cpu(rx_desc->length); if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { @@ -2146,7 +2151,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) dev_kfree_skb_irq(skb); rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; + buffer_info->skb = NULL; if(++i == rx_ring->count) i = 0; @@ -2174,7 +2179,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) dev_kfree_skb_irq(skb); rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; + buffer_info->skb = NULL; if(++i == rx_ring->count) i = 0; @@ -2193,14 +2198,16 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { vlan_hwaccel_receive_skb(skb, adapter->vlgrp, - (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special & + E1000_RXD_SPC_VLAN_MASK)); } else { netif_receive_skb(skb); } #else /* CONFIG_E1000_NAPI */ if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { vlan_hwaccel_rx(skb, adapter->vlgrp, - (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); + le16_to_cpu(rx_desc->special & + E1000_RXD_SPC_VLAN_MASK)); } else { netif_rx(skb); } @@ -2208,7 +2215,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter) netdev->last_rx = jiffies; rx_desc->status = 0; - rx_ring->buffer_info[i].skb = NULL; + buffer_info->skb = NULL; if(++i == rx_ring->count) i = 0; @@ -2234,13 +2241,15 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; + struct e1000_buffer *buffer_info; struct sk_buff *skb; int reserve_len = 2; - int i; + unsigned int i; i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; - while(!rx_ring->buffer_info[i].skb) { + while(!buffer_info->skb) { rx_desc = E1000_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len); @@ -2258,15 +2267,15 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) skb->dev = netdev; - rx_ring->buffer_info[i].skb = skb; - rx_ring->buffer_info[i].length = adapter->rx_buffer_len; - rx_ring->buffer_info[i].dma = + buffer_info->skb = skb; + buffer_info->length = adapter->rx_buffer_len; + buffer_info->dma = pci_map_single(pdev, skb->data, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); - rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); + rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma); if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { /* Force memory writes to complete before letting h/w @@ -2279,6 +2288,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter) } if(++i == rx_ring->count) i = 0; + buffer_info = &rx_ring->buffer_info[i]; } rx_ring->next_to_use = i; diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index a2d387ced05..99d7afc609b 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -212,13 +212,6 @@ static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) /* called from sir_dev when there is more data to send * context is either netdev->hard_xmit or some transmit-completion bh * i.e. we are under spinlock here and must not sleep. - * - * Note: as of 2.5.44 the usb-serial driver calls down() on a semaphore - * hence we are hitting the might_sleep bugcatcher. IMHO the whole tty-api - * would be pretty pointless if write_room/write would be allowed to sleep. - * Furthermore other tty ldiscs (like ppp) do also require the driver not - * to sleep there. Hence this is considered a current limitation of - * usb-serial. */ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len) @@ -269,16 +262,15 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, struct sirtty_cb *priv = tty->disc_data; int i; - if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) - return; - /* Please use ASSERT - Fix ASSERT as needed - Jean II */ + ASSERT(priv != NULL, return;); + ASSERT(priv->magic == IRTTY_MAGIC, return;); if (unlikely(count==0)) /* yes, this happens */ return; dev = priv->dev; if (!dev) { - printk(KERN_ERR "%s(), not ready yet!\n", __FUNCTION__); + WARNING("%s(), not ready yet!\n", __FUNCTION__); return; } @@ -306,8 +298,8 @@ static int irtty_receive_room(struct tty_struct *tty) { struct sirtty_cb *priv = tty->disc_data; - if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) - return 0; + ASSERT(priv != NULL, return 0;); + ASSERT(priv->magic == IRTTY_MAGIC, return 0;); return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -323,8 +315,8 @@ static void irtty_write_wakeup(struct tty_struct *tty) { struct sirtty_cb *priv = tty->disc_data; - if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) - return; + ASSERT(priv != NULL, return;); + ASSERT(priv->magic == IRTTY_MAGIC, return;); tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); @@ -559,7 +551,7 @@ static int irtty_open(struct tty_struct *tty) up(&irtty_sem); - printk(KERN_INFO "%s - done\n", __FUNCTION__); + IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name); return 0; @@ -580,8 +572,8 @@ static void irtty_close(struct tty_struct *tty) { struct sirtty_cb *priv = tty->disc_data; - if (!priv || priv->magic != IRTTY_MAGIC) - return; + ASSERT(priv != NULL, return;); + ASSERT(priv->magic == IRTTY_MAGIC, return;); /* Hm, with a dongle attached the dongle driver wants * to close the dongle - which requires the use of @@ -610,6 +602,8 @@ static void irtty_close(struct tty_struct *tty) tty->driver->stop(tty); kfree(priv); + + IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __FUNCTION__, tty->name); } /* ------------------------------------------------------- */ diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index d0af0c633be..6572d11bbc1 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -201,14 +201,12 @@ void sirdev_write_complete(struct sir_dev *dev) int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) { if (!dev || !dev->netdev) { - IRDA_DEBUG(0, "%s(), not ready yet!\n", __FUNCTION__); - /* Use WARNING instead of IRDA_DEBUG */ + WARNING("%s(), not ready yet!\n", __FUNCTION__); return -1; } if (!dev->irlap) { - IRDA_DEBUG(0, "%s - too early: %p / %d!\n", __FUNCTION__, cp, count); - /* Use WARNING instead of IRDA_DEBUG */ + WARNING("%s - too early: %p / %d!\n", __FUNCTION__, cp, count); return -1; } @@ -218,7 +216,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) */ irda_device_set_media_busy(dev->netdev, TRUE); dev->stats.rx_dropped++; - printk(KERN_INFO "%s; rx-drop: %d\n", __FUNCTION__, count); + IRDA_DEBUG(0, "%s; rx-drop: %d\n", __FUNCTION__, count); return 0; } @@ -431,7 +429,6 @@ static int sirdev_alloc_buffers(struct sir_dev *dev) return -ENOMEM; skb_reserve(dev->rx_buff.skb, 1); dev->rx_buff.head = dev->rx_buff.skb->data; - /* No need to memset the buffer, unless you are really pedantic */ dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL); if (dev->tx_buff.head == NULL) { @@ -439,8 +436,6 @@ static int sirdev_alloc_buffers(struct sir_dev *dev) dev->rx_buff.skb = NULL; dev->rx_buff.head = NULL; return -ENOMEM; - /* Hu ??? This should not be here, Martin ? */ - memset(dev->tx_buff.head, 0, dev->tx_buff.truesize); } dev->tx_buff.data = dev->tx_buff.head; @@ -492,7 +487,7 @@ static int sirdev_open(struct net_device *ndev) netif_wake_queue(ndev); - printk(KERN_INFO "%s - done, speed = %d\n", __FUNCTION__, dev->speed); + IRDA_DEBUG(2, "%s - done, speed = %d\n", __FUNCTION__, dev->speed); return 0; @@ -512,7 +507,7 @@ static int sirdev_close(struct net_device *ndev) struct sir_dev *dev = ndev->priv; const struct sir_driver *drv; - printk(KERN_INFO "%s\n", __FUNCTION__); +// IRDA_DEBUG(0, "%s\n", __FUNCTION__); netif_stop_queue(ndev); @@ -570,7 +565,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n struct net_device *ndev; struct sir_dev *dev; - printk(KERN_INFO "%s - %s\n", __FUNCTION__, name); + IRDA_DEBUG(0, "%s - %s\n", __FUNCTION__, name); /* instead of adding tests to protect against drv->do_write==NULL * at several places we refuse to create a sir_dev instance for @@ -584,8 +579,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n */ dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - printk(KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + ERROR("%s - Can't allocate memory for IrDA control block!\n", __FUNCTION__); goto out; } memset(dev, 0, sizeof(*dev)); @@ -638,7 +632,7 @@ int sirdev_put_instance(struct sir_dev *dev) { int err = 0; - printk(KERN_INFO "%s\n", __FUNCTION__); + IRDA_DEBUG(0, "%s\n", __FUNCTION__); atomic_set(&dev->enable_rx, 0); diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c index cc38b8809b1..5e7f455432c 100644 --- a/drivers/net/irda/sir_kthread.c +++ b/drivers/net/irda/sir_kthread.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -107,44 +108,12 @@ static void run_irda_queue(void) spin_unlock_irqrestore(&irda_rq_queue.lock, flags); } -static int irda_rt_prio = 0; /* MODULE_PARM? */ - static int irda_thread(void *startup) { DECLARE_WAITQUEUE(wait, current); daemonize("kIrDAd"); - set_fs(KERNEL_DS); - - if (irda_rt_prio > 0) { -#if 0 /* works but requires EXPORT_SYMBOL(setscheduler) */ - struct sched_param param; - - param.sched_priority = irda_rt_prio; - setscheduler(0, SCHED_FIFO, ¶m); -#endif - -#if 0 /* doesn't work - has some tendency to trigger instant reboot! - * looks like we would have to deactivate current on the - * runqueue - which is only possible inside of kernel/sched.h - */ - - /* runqueues are per-cpu and we are current on this cpu. Hence - * The tasklist_lock with irq-off protects our runqueue too - * and we don't have to lock it (which would be impossible, - * because it is private in kernel/sched.c) - */ - - read_lock_irq(&tasklist_lock); - current->rt_priority = (irda_rt_priopolicy = SCHED_FIFO; - current->prio = MAX_USER_RT_PRIO-1 - irda_rt_prio; - read_unlock_irq(&tasklist_lock); -#endif - } - irda_rq_queue.thread = current; complete((struct completion *)startup); @@ -166,6 +135,10 @@ static int irda_thread(void *startup) set_task_state(current, TASK_RUNNING); remove_wait_queue(&irda_rq_queue.kick, &wait); + /* make swsusp happy with our thread */ + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); + run_irda_queue(); } @@ -442,7 +415,6 @@ static void irda_config_fsm(void *data) case SIRDEV_STATE_COMPLETE: /* config change finished, so we are not busy any longer */ sirdev_enable_rx(dev); - printk(KERN_INFO "%s - up\n", __FUNCTION__); up(&fsm->sem); return; } @@ -462,9 +434,7 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par struct sir_fsm *fsm = &dev->fsm; int xmit_was_down; -// IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); - - printk(KERN_INFO "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); + IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param); if (in_interrupt()) { if (down_trylock(&fsm->sem)) { @@ -474,12 +444,10 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par } else down(&fsm->sem); - printk(KERN_INFO "%s - down\n", __FUNCTION__); if (fsm->state == SIRDEV_STATE_DEAD) { /* race with sirdev_close should never happen */ ERROR("%s(), instance staled!\n", __FUNCTION__); - printk(KERN_INFO "%s - up\n", __FUNCTION__); up(&fsm->sem); return -ESTALE; /* or better EPIPE? */ } @@ -501,7 +469,6 @@ int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned par atomic_set(&dev->enable_rx, 1); if (!xmit_was_down) netif_wake_queue(dev->netdev); - printk(KERN_INFO "%s - up\n", __FUNCTION__); up(&fsm->sem); return -EAGAIN; } diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index b6cebddaa17..606d7bf9842 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -844,7 +844,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) if (ns == 0) goto outf; skb_reserve(ns, dev->hard_header_len); - memcpy(skb_put(ns, skb->len), skb->data, skb->len); + skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); kfree_skb(skb); skb = ns; } @@ -1455,7 +1455,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) goto err; } skb_reserve(ns, 2); - memcpy(skb_put(ns, skb->len), skb->data, skb->len); + skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); kfree_skb(skb); skb = ns; } @@ -1826,7 +1826,7 @@ ppp_mp_reconstruct(struct ppp *ppp) if (head != tail) /* copy to a single skb */ for (p = head; p != tail->next; p = p->next) - memcpy(skb_put(skb, p->len), p->data, p->len); + skb_copy_bits(p, 0, skb_put(skb, p->len), p->len); ppp->nextseq = tail->sequence + 1; head = tail->next; } diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index d1c75c350f7..9bc570c04fc 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1521,6 +1521,12 @@ static int happy_meal_init(struct happy_meal *hp) hme_write32(hp, bregs + BMAC_IGAP1, DEFAULT_IPG1); hme_write32(hp, bregs + BMAC_IGAP2, DEFAULT_IPG2); + /* Make sure we can handle VLAN frames. */ + hme_write32(hp, bregs + BMAC_TXMAX, + ETH_DATA_LEN + ETH_HLEN + 8); + hme_write32(hp, bregs + BMAC_RXMAX, + ETH_DATA_LEN + ETH_HLEN + 8); + /* Load up the MAC address and random seed. */ HMD(("rseed/macaddr, ")); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 4226efcc5f0..3c3a2d620bc 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -2,6 +2,8 @@ /* Written 1998-2001 by Donald Becker. + Current Maintainer: Roger Luethi + This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this code fall under the GPL and must @@ -9,8 +11,9 @@ a complete program and may only be used when the entire operating system is licensed under the GPL. - This driver is designed for the VIA VT86C100A Rhine-I. - It also works with the 6102 Rhine-II, and 6105/6105M Rhine-III. + This driver is designed for the VIA VT86C100A Rhine-I. + It also works with the Rhine-II (6102) and Rhine-III (6105/6105L/6105LOM + and management NIC 6105M). The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation @@ -115,11 +118,15 @@ - Force flushing for PCI posted writes - More reset code changes + LK1.1.18 (Roger Luethi) + - No filtering multicast in promisc mode (Edward Peng) + - Fix for Rhine-I Tx timeouts + */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.1.17" -#define DRV_RELDATE "March-1-2003" +#define DRV_VERSION "1.1.18-2.5" +#define DRV_RELDATE "July-4-2003" /* A few user-configurable values. @@ -386,17 +393,17 @@ static struct via_rhine_chip_info via_rhine_chip_info[] __devinitdata = { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, { "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256, - CanHaveMII | HasWOL }, + CanHaveMII | HasWOL }, }; static struct pci_device_id via_rhine_pci_tbl[] __devinitdata = { {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A}, {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102}, - {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, - {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, + {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, /* 6105{,L,LOM} */ + {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M}, {0,} /* terminate list */ }; MODULE_DEVICE_TABLE(pci, via_rhine_pci_tbl); @@ -441,7 +448,7 @@ enum intr_status_bits { IntrRxWakeUp=0x8000, IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, IntrTxDescRace=0x080000, /* mapped from IntrStatus2 */ - IntrTxErrSummary=0x082210, + IntrTxErrSummary=0x082218, }; /* The Rx and Tx buffer descriptors. */ @@ -1655,11 +1662,18 @@ static void via_rhine_error(struct net_device *dev, int intr_status) printk(KERN_INFO "%s: Tx descriptor write-back race.\n", dev->name); } - if (intr_status & ( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace )) + if ((intr_status & IntrTxError) && ~( IntrTxAborted | IntrTxUnderrun | + IntrTxDescRace )) { + if (debug > 2) + printk(KERN_INFO "%s: Unspecified error.\n", + dev->name); + } + if (intr_status & ( IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | + IntrTxError )) via_rhine_restart_tx(dev); if (intr_status & ~( IntrLinkChange | IntrStatsMax | IntrTxUnderrun | - IntrTxError | IntrTxAborted | IntrNormalSummary | + IntrTxError | IntrTxAborted | IntrNormalSummary | IntrTxDescRace )) { if (debug > 1) printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n", diff --git a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c index 1039bf85ea0..8cd73bc9a3d 100644 --- a/drivers/net/wan/comx.c +++ b/drivers/net/wan/comx.c @@ -86,7 +86,7 @@ static struct comx_protocol *comx_lines = NULL; static int comx_mkdir(struct inode *, struct dentry *, int); static int comx_rmdir(struct inode *, struct dentry *); -static struct dentry *comx_lookup(struct inode *, struct dentry *); +static struct dentry *comx_lookup(struct inode *, struct dentry *, struct nameidata *); static struct inode_operations comx_root_inode_ops = { .lookup = comx_lookup, @@ -922,7 +922,7 @@ static int comx_rmdir(struct inode *dir, struct dentry *dentry) return 0; } -static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct proc_dir_entry *de; struct inode *inode = NULL; diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index f003d03844d..fd0b3dfeeb1 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c @@ -177,11 +177,8 @@ EXPORT_SYMBOL(unregister_hdlc_device); struct packet_type hdlc_packet_type= { - __constant_htons(ETH_P_HDLC), - NULL, - hdlc_rcv, - NULL, - NULL + .type = __constant_htons(ETH_P_HDLC), + .func = hdlc_rcv, }; diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 547ef6adffe..92959266a02 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -378,19 +378,21 @@ static int __devinit eisa_probe(struct parisc_device *dev) } } eisa_eeprom_init(eisa_dev.eeprom_addr); - eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space); + result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space); init_eisa_pic(); - /* FIXME : Get the number of slots from the enumerator, not a - * hadcoded value. Also don't enumerate the bus twice. */ - eisa_dev.root.dev = &dev->dev; - dev->dev.driver_data = &eisa_dev.root; - eisa_dev.root.bus_base_addr = 0; - eisa_dev.root.res = &eisa_dev.hba.io_space; - eisa_dev.root.slots = EISA_MAX_SLOTS; - if (eisa_root_register (&eisa_dev.root)) { - printk(KERN_ERR "EISA: Failed to register EISA root\n"); - return -1; + if (result >= 0) { + /* FIXME : Don't enumerate the bus twice. */ + eisa_dev.root.dev = &dev->dev; + dev->dev.driver_data = &eisa_dev.root; + eisa_dev.root.bus_base_addr = 0; + eisa_dev.root.res = &eisa_dev.hba.io_space; + eisa_dev.root.slots = result; + eisa_dev.root.dma_mask = 0xffffffff; /* wild guess */ + if (eisa_root_register (&eisa_dev.root)) { + printk(KERN_ERR "EISA: Failed to register EISA root\n"); + return -1; + } } return 0; diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c index ebd15f128ff..6d8aae003f6 100644 --- a/drivers/parisc/eisa_enumerator.c +++ b/drivers/parisc/eisa_enumerator.c @@ -438,6 +438,10 @@ static int init_slot(int slot, struct eeprom_eisa_slot_info *es) id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI)); if (0xffffffff == id) { + /* Maybe we didn't expect a card to be here... */ + if (es->eisa_slot_id == 0xffffffff) + return -1; + /* this board is not here or it does not * support readid */ @@ -499,8 +503,7 @@ int eisa_enumerator(unsigned long eeprom_addr, (&eeprom_buf[HPEE_SLOT_INFO(i)]); if (-1==init_slot(i+1, es)) { - return -1; - + continue; } if (es->config_data_offset < HPEE_MAX_LENGTH) { @@ -513,6 +516,6 @@ int eisa_enumerator(unsigned long eeprom_addr, return -1; } } - return 0; + return eh->num_slots; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 3af6ad4adbe..4e8ddf18434 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -385,7 +385,7 @@ static void add_host_bridge (acpi_handle *handle, int seg, int bus) bridge->seg = seg; bridge->bus = bus; - bridge->pci_bus = pci_find_bus(bus); + bridge->pci_bus = pci_find_bus(seg, bus); bridge->res_lock = SPIN_LOCK_UNLOCKED; diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 8ffe245a1ca..88bc69c5053 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -395,7 +395,7 @@ static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) /* Scan behind bridge */ n = pci_scan_bridge(bus, dev, max, 2); - child = pci_find_bus(max + 1); + child = pci_find_bus(0, max + 1); if (!child) return -ENODEV; pci_proc_attach_bus(child); diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index 1e44444e628..1f0fa666cf8 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -774,7 +774,7 @@ static u8 bus_structure_fixup (u8 busno) struct pci_dev *dev; u16 l; - if (pci_find_bus(busno) || !(ibmphp_find_same_bus_num (busno))) + if (pci_find_bus(0, busno) || !(ibmphp_find_same_bus_num (busno))) return 1; bus = kmalloc (sizeof (*bus), GFP_KERNEL); @@ -819,7 +819,7 @@ static int ibm_configure_device (struct pci_func *func) func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { - struct pci_bus *bus = pci_find_bus(func->busno); + struct pci_bus *bus = pci_find_bus(0, func->busno); if (!bus) return 0; @@ -1335,7 +1335,7 @@ static int __init ibmphp_init (void) goto exit; } - bus = pci_find_bus(0); + bus = pci_find_bus(0, 0); if (!bus) { err ("Can't find the root pci bus, can not continue\n"); rc = -ENODEV; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 4e13d7141b7..dc560bf7742 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -3,6 +3,8 @@ * * (C) Copyright 2002 Greg Kroah-Hartman * (C) Copyright 2002 IBM Corp. + * (C) Copyright 2003 Matthew Wilcox + * (C) Copyright 2003 Hewlett-Packard * * File attributes for PCI devices * @@ -60,6 +62,108 @@ pci_show_resources(struct device * dev, char * buf) static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL); +static ssize_t +pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); + unsigned int size = 64; + + /* Several chips lock up trying to read undefined config space */ + if (capable(CAP_SYS_ADMIN)) { + size = 256; + } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + size = 128; + } + + if (off > size) + return 0; + if (off + count > size) { + size -= off; + count = size; + } else { + size = count; + } + + while (off & 3) { + unsigned char val; + pci_read_config_byte(dev, off, &val); + buf[off] = val; + off++; + if (--size == 0) + break; + } + + while (size > 3) { + unsigned int val; + pci_read_config_dword(dev, off, &val); + buf[off] = val & 0xff; + buf[off + 1] = (val >> 8) & 0xff; + buf[off + 2] = (val >> 16) & 0xff; + buf[off + 3] = (val >> 24) & 0xff; + off += 4; + size -= 4; + } + + while (size > 0) { + unsigned char val; + pci_read_config_byte(dev, off, &val); + buf[off] = val; + off++; + --size; + } + + return count; +} + +static ssize_t +pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj)); + unsigned int size = count; + + if (off > 256) + return 0; + if (off + count > 256) { + size = 256 - off; + count = size; + } + + while (off & 3) { + pci_write_config_byte(dev, off, buf[off]); + off++; + if (--size == 0) + break; + } + + while (size > 3) { + unsigned int val = buf[off]; + val |= (unsigned int) buf[off + 1] << 8; + val |= (unsigned int) buf[off + 2] << 16; + val |= (unsigned int) buf[off + 3] << 24; + pci_write_config_dword(dev, off, val); + off += 4; + size -= 4; + } + + while (size > 0) { + pci_write_config_byte(dev, off, buf[off]); + off++; + --size; + } + + return count; +} + +static struct bin_attribute pci_config_attr = { + .attr = { + .name = "config", + .mode = S_IRUGO | S_IWUSR, + }, + .size = 256, + .read = pci_read_config, + .write = pci_write_config, +}; + void pci_create_sysfs_dev_files (struct pci_dev *pdev) { struct device *dev = &pdev->dev; @@ -72,4 +176,5 @@ void pci_create_sysfs_dev_files (struct pci_dev *pdev) device_create_file (dev, &dev_attr_class); device_create_file (dev, &dev_attr_irq); device_create_file (dev, &dev_attr_resource); + sysfs_create_bin_file(&dev->kobj, &pci_config_attr); } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 3288e401d91..2ad19d3f928 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -29,7 +29,6 @@ extern int pci_remove_device_safe(struct pci_dev *dev); extern unsigned char pci_max_busnr(void); extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); -extern struct pci_bus *pci_find_bus(unsigned char busnr); struct pci_dev_wrapped { struct pci_dev *dev; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0894f4aed33..ccd50ca202f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -633,27 +633,10 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) return max; } -int __devinit pci_bus_exists(const struct list_head *list, int nr) -{ - const struct pci_bus *b; - - list_for_each_entry(b, list, node) { - if (b->number == nr || pci_bus_exists(&b->children, nr)) - return 1; - } - return 0; -} - struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; - if (pci_bus_exists(&pci_root_buses, bus)) { - /* If we already got to this bus through a different bridge, ignore it */ - DBG("PCI: Bus %02x already known\n", bus); - return NULL; - } - b = pci_alloc_bus(); if (!b) return NULL; @@ -667,6 +650,14 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, b->sysdata = sysdata; b->ops = ops; + if (pci_find_bus(pci_domain_nr(b), bus)) { + /* If we already got to this bus through a different bridge, ignore it */ + DBG("PCI: Bus %02x already known\n", bus); + kfree(b->dev); + kfree(b); + return NULL; + } + list_add_tail(&b->node, &pci_root_buses); memset(b->dev,0,sizeof(*(b->dev))); diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 85c74126ee6..366f1f16fb2 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -7,12 +7,14 @@ * Copyright 2003 -- Greg Kroah-Hartman */ +#include #include #include +#include spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED; -static struct pci_bus * +static struct pci_bus * __devinit pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) { struct pci_bus* child; @@ -30,22 +32,24 @@ pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) } /** - * pci_find_bus - locate PCI bus from a given bus number + * pci_find_bus - locate PCI bus from a given domain and bus number + * @domain: number of PCI domain to search * @busnr: number of desired PCI bus * - * Given a PCI bus number, the desired PCI bus is located in system - * global list of PCI buses. If the bus is found, a pointer to its + * Given a PCI bus number and domain number, the desired PCI bus is located + * in the global list of PCI buses. If the bus is found, a pointer to its * data structure is returned. If no bus is found, %NULL is returned. */ -struct pci_bus * -pci_find_bus(unsigned char busnr) +struct pci_bus * __devinit pci_find_bus(int domain, int busnr) { - struct pci_bus* bus = NULL; - struct pci_bus* tmp_bus; + struct pci_bus *bus = NULL; + struct pci_bus *tmp_bus; while ((bus = pci_find_next_bus(bus)) != NULL) { + if (pci_domain_nr(bus) != domain) + continue; tmp_bus = pci_do_find_bus(bus, busnr); - if(tmp_bus) + if (tmp_bus) return tmp_bus; } return NULL; @@ -66,7 +70,7 @@ pci_find_next_bus(const struct pci_bus *from) struct list_head *n; struct pci_bus *b = NULL; - WARN_ON(irqs_disabled()); + WARN_ON(in_interrupt()); spin_lock(&pci_bus_lock); n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) @@ -125,7 +129,7 @@ pci_find_subsys(unsigned int vendor, unsigned int device, struct list_head *n; struct pci_dev *dev; - WARN_ON(irqs_disabled()); + WARN_ON(in_interrupt()); spin_lock(&pci_bus_lock); n = from ? from->global_list.next : pci_devices.next; @@ -190,7 +194,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, struct list_head *n; struct pci_dev *dev; - WARN_ON(irqs_disabled()); + WARN_ON(in_interrupt()); spin_lock(&pci_bus_lock); n = from ? from->global_list.next : pci_devices.next; @@ -256,7 +260,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p struct list_head *n; struct pci_dev *dev; - WARN_ON(irqs_disabled()); + WARN_ON(in_interrupt()); spin_lock(&pci_bus_lock); n = from ? from->global_list.prev : pci_devices.prev; diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index eb2094bf72d..e2b7388f7ec 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -259,7 +259,10 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) for (i = 0; i < PNP_MAX_PORT; i++) { if (pnp_port_valid(dev, i)) { pnp_printf(buffer,"io"); - pnp_printf(buffer," 0x%lx-0x%lx \n", + if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED) + pnp_printf(buffer," disabled\n"); + else + pnp_printf(buffer," 0x%lx-0x%lx\n", pnp_port_start(dev, i), pnp_port_end(dev, i)); } @@ -267,7 +270,10 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) for (i = 0; i < PNP_MAX_MEM; i++) { if (pnp_mem_valid(dev, i)) { pnp_printf(buffer,"mem"); - pnp_printf(buffer," 0x%lx-0x%lx \n", + if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED) + pnp_printf(buffer," disabled\n"); + else + pnp_printf(buffer," 0x%lx-0x%lx\n", pnp_mem_start(dev, i), pnp_mem_end(dev, i)); } @@ -275,13 +281,21 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) for (i = 0; i < PNP_MAX_IRQ; i++) { if (pnp_irq_valid(dev, i)) { pnp_printf(buffer,"irq"); - pnp_printf(buffer," %ld \n", pnp_irq(dev, i)); + if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED) + pnp_printf(buffer," disabled\n"); + else + pnp_printf(buffer," %ld\n", + pnp_irq(dev, i)); } } for (i = 0; i < PNP_MAX_DMA; i++) { if (pnp_dma_valid(dev, i)) { pnp_printf(buffer,"dma"); - pnp_printf(buffer," %ld \n", pnp_dma(dev, i)); + if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED) + pnp_printf(buffer," disabled\n"); + else + pnp_printf(buffer," %ld\n", + pnp_dma(dev, i)); } } ret = (buffer->curr - buf); diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index a56dfac58b3..d902dfc4716 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -45,9 +45,15 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) flags = &dev->res.port_resource[idx].flags; /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_IO; + + if (!rule->size) { + *flags |= IORESOURCE_DISABLED; + return 1; /* skip disabled resource requests */ + } + *start = rule->min; *end = *start + rule->size - 1; - *flags = *flags | rule->flags | IORESOURCE_IO; /* run through until pnp_check_port is happy */ while (!pnp_check_port(dev, idx)) { @@ -81,8 +87,6 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) flags = &dev->res.mem_resource[idx].flags; /* set the initial values */ - *start = rule->min; - *end = *start + rule->size -1; *flags = *flags | rule->flags | IORESOURCE_MEM; /* convert pnp flags to standard Linux flags */ @@ -95,6 +99,14 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) if (rule->flags & IORESOURCE_MEM_SHADOWABLE) *flags |= IORESOURCE_SHADOWABLE; + if (!rule->size) { + *flags |= IORESOURCE_DISABLED; + return 1; /* skip disabled resource requests */ + } + + *start = rule->min; + *end = *start + rule->size -1; + /* run through until pnp_check_mem is happy */ while (!pnp_check_mem(dev, idx)) { *start += rule->align; @@ -135,6 +147,11 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx) /* set the initial values */ *flags = *flags | rule->flags | IORESOURCE_IRQ; + if (!rule->map) { + *flags |= IORESOURCE_DISABLED; + return 1; /* skip disabled resource requests */ + } + for (i = 0; i < 16; i++) { if(rule->map & (1<flags | IORESOURCE_DMA; + if (!rule->map) { + *flags |= IORESOURCE_DISABLED; + return 1; /* skip disabled resource requests */ + } + for (i = 0; i < 8; i++) { if(rule->map & (1<res = *res; if (!(mode & PNP_CONFIG_FORCE)) { for (i = 0; i < PNP_MAX_PORT; i++) { - if(pnp_check_port(dev,i)) + if(!pnp_check_port(dev,i)) goto fail; } for (i = 0; i < PNP_MAX_MEM; i++) { - if(pnp_check_mem(dev,i)) + if(!pnp_check_mem(dev,i)) goto fail; } for (i = 0; i < PNP_MAX_IRQ; i++) { - if(pnp_check_irq(dev,i)) + if(!pnp_check_irq(dev,i)) goto fail; } for (i = 0; i < PNP_MAX_DMA; i++) { - if(pnp_check_dma(dev,i)) + if(!pnp_check_dma(dev,i)) goto fail; } } up(&pnp_res_mutex); - pnp_auto_config_dev(dev); kfree(bak); return 0; diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 978decf7504..c7c664a3035 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -286,6 +286,8 @@ int pnp_check_port(struct pnp_dev * dev, int idx) continue; for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { + if (pnp_port_flags(dev, tmp) & IORESOURCE_DISABLED) + continue; tport = &tdev->res.port_resource[tmp].start; tend = &tdev->res.port_resource[tmp].end; if (ranged_conflict(port,end,tport,tend)) @@ -340,6 +342,8 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) continue; for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { + if (pnp_mem_flags(dev, tmp) & IORESOURCE_DISABLED) + continue; taddr = &tdev->res.mem_resource[tmp].start; tend = &tdev->res.mem_resource[tmp].end; if (ranged_conflict(addr,end,taddr,tend)) @@ -409,6 +413,8 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) continue; for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { + if (pnp_irq_flags(dev, tmp) & IORESOURCE_DISABLED) + continue; if ((tdev->res.irq_resource[tmp].start == *irq)) return 0; } @@ -462,6 +468,8 @@ int pnp_check_dma(struct pnp_dev * dev, int idx) continue; for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { + if (pnp_dma_flags(dev, tmp) & IORESOURCE_DISABLED) + continue; if ((tdev->res.dma_resource[tmp].start == *dma)) return 0; } diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index af359e092ed..375aa217223 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -68,9 +68,13 @@ static void current_irqresource(struct pnp_resource_table * res, int irq) int i = 0; while ((res->irq_resource[i].flags & IORESOURCE_IRQ) && i < PNP_MAX_IRQ) i++; if (i < PNP_MAX_IRQ) { + res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag + if (irq == -1) { + res->irq_resource[i].flags |= IORESOURCE_DISABLED; + return; + } res->irq_resource[i].start = res->irq_resource[i].end = (unsigned long) irq; - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag } } @@ -79,9 +83,13 @@ static void current_dmaresource(struct pnp_resource_table * res, int dma) int i = 0; while ((res->dma_resource[i].flags & IORESOURCE_DMA) && i < PNP_MAX_DMA) i++; if (i < PNP_MAX_DMA) { + res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag + if (dma == -1) { + res->dma_resource[i].flags |= IORESOURCE_DISABLED; + return; + } res->dma_resource[i].start = res->dma_resource[i].end = (unsigned long) dma; - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag } } @@ -90,9 +98,13 @@ static void current_ioresource(struct pnp_resource_table * res, int io, int len) int i = 0; while ((res->port_resource[i].flags & IORESOURCE_IO) && i < PNP_MAX_PORT) i++; if (i < PNP_MAX_PORT) { + res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag + if (len <= 0 || (io + len -1) >= 0x10003) { + res->port_resource[i].flags |= IORESOURCE_DISABLED; + return; + } res->port_resource[i].start = (unsigned long) io; res->port_resource[i].end = (unsigned long)(io + len - 1); - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag } } @@ -101,9 +113,13 @@ static void current_memresource(struct pnp_resource_table * res, int mem, int le int i = 0; while ((res->mem_resource[i].flags & IORESOURCE_MEM) && i < PNP_MAX_MEM) i++; if (i < PNP_MAX_MEM) { + res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag + if (len <= 0) { + res->mem_resource[i].flags |= IORESOURCE_DISABLED; + return; + } res->mem_resource[i].start = (unsigned long) mem; res->mem_resource[i].end = (unsigned long)(mem + len - 1); - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag } } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index af35f91fe3b..633c9a028e2 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -582,7 +582,7 @@ void scsi_done(struct scsi_cmnd *cmd) local_irq_save(flags); cpu = smp_processor_id(); list_add_tail(&cmd->eh_entry, &done_q[cpu]); - cpu_raise_softirq(cpu, SCSI_SOFTIRQ); + raise_softirq_irqoff(SCSI_SOFTIRQ); local_irq_restore(flags); } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 5f9307658f4..6720dd216fd 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -646,7 +646,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED; sdev->use_10_for_rw = 1; - sdev->use_10_for_ms = 1; + sdev->use_10_for_ms = 0; if(sdev->host->hostt->slave_configure) sdev->host->hostt->slave_configure(sdev); diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 7ff8ff5dbec..f212ae0992d 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -1533,7 +1533,6 @@ void unregister_serial(int line) } module_init(rs68328_init); -/* DAVIDM module_exit(rs68328_fini); */ diff --git a/drivers/serial/8250_cs.c b/drivers/serial/8250_cs.c index b1e012cb5d3..a70c3ddfadf 100644 --- a/drivers/serial/8250_cs.c +++ b/drivers/serial/8250_cs.c @@ -133,7 +133,7 @@ static dev_link_t *dev_list = NULL; static void serial_remove(dev_link_t *link) { struct serial_info *info = link->priv; - int i, ret; + int i; link->state &= ~DEV_PRESENT; diff --git a/drivers/serial/core.c b/drivers/serial/core.c index 27fbb5348cc..17c43594f9c 100644 --- a/drivers/serial/core.c +++ b/drivers/serial/core.c @@ -1490,8 +1490,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) return -ERESTARTSYS; if (!info->tty || tty_hung_up_p(filp)) - return (port->flags & UPF_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; + return -EAGAIN; return 0; } @@ -1596,8 +1595,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp) * If the port is in the middle of closing, bail out now. */ if (tty_hung_up_p(filp)) { - retval = (state->port->flags & UPF_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; + retval = -EAGAIN; state->count--; up(&state->sem); goto fail; diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 38bcb876545..c6b7caa224d 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -1643,7 +1643,6 @@ mcfrs_init(void) } module_init(mcfrs_init); -/* DAVIDM module_exit(mcfrs_fini); */ /****************************************************************************/ /* Serial Console */ diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index f4fde1c2310..6e4a1b3a4e1 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h @@ -88,7 +88,7 @@ void __adfs_error(struct super_block *sb, const char *function, #define adfs_error(sb, fmt...) __adfs_error(sb, __FUNCTION__, fmt) /* namei.c */ -extern struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry); +extern struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); /* super.c */ diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index df29ce99c6e..aae5b4e066d 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -269,7 +269,7 @@ struct dentry_operations adfs_dentry_operations = { .d_compare = adfs_compare, }; -struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry) +struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct object_info obj; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 01defe3d0ff..f2cbba3b757 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -210,7 +210,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry) } struct dentry * -affs_lookup(struct inode *dir, struct dentry *dentry) +affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; @@ -256,7 +256,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry) } int -affs_create(struct inode *dir, struct dentry *dentry, int mode) +affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct inode *inode; diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 12effcc6f89..a63e3e9679f 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -23,10 +23,10 @@ #include "super.h" #include "internal.h" -static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry); +static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); static int afs_dir_open(struct inode *inode, struct file *file); static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir); -static int afs_d_revalidate(struct dentry *dentry, int flags); +static int afs_d_revalidate(struct dentry *dentry, struct nameidata *); static int afs_d_delete(struct dentry *dentry); static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos, ino_t ino, unsigned dtype); @@ -414,7 +414,7 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, lof /* * look up an entry in a directory */ -static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct afs_dir_lookup_cookie cookie; struct afs_super_info *as; @@ -487,7 +487,7 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry) * - NOTE! the hit can be a negative hit too, so we can't assume we have an inode * (derived from nfs_lookup_revalidate) */ -static int afs_d_revalidate(struct dentry *dentry, int flags) +static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { struct afs_dir_lookup_cookie cookie; struct dentry *parent; @@ -495,7 +495,7 @@ static int afs_d_revalidate(struct dentry *dentry, int flags) unsigned fpos; int ret; - _enter("%s,%x",dentry->d_name.name,flags); + _enter("%s,%p",dentry->d_name.name,nd); parent = dget_parent(dentry); dir = parent->d_inode; diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 0279fcbf832..d22887d47f3 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -21,7 +21,7 @@ #include "internal.h" -static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry); +static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); static int afs_mntpt_open(struct inode *inode, struct file *file); struct file_operations afs_mntpt_file_operations = { @@ -93,7 +93,7 @@ int afs_mntpt_check_symlink(afs_vnode_t *vnode) /* * no valid lookup procedure on this sort of dir */ -static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { return ERR_PTR(-EREMOTE); } /* end afs_mntpt_lookup() */ diff --git a/fs/aio.c b/fs/aio.c index d27596565a9..92ab49c1bce 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -551,7 +551,7 @@ static void unuse_mm(struct mm_struct *mm) { current->mm = NULL; /* active_mm is still 'mm' */ - enter_lazy_tlb(mm, current, smp_processor_id()); + enter_lazy_tlb(mm, current); } /* Run on kevent's context. FIXME: needs to be per-cpu and warn if an diff --git a/fs/attr.c b/fs/attr.c index 0d9e778fb5d..2048b99a112 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -22,8 +22,6 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; - lock_kernel(); - /* If force is set do it anyway. */ if (ia_valid & ATTR_FORCE) goto fine; @@ -58,7 +56,6 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) fine: retval = 0; error: - unlock_kernel(); return retval; } diff --git a/fs/autofs/root.c b/fs/autofs/root.c index e6e3b0c468d..546ac2f9af8 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -18,7 +18,7 @@ #include "autofs_i.h" static int autofs_root_readdir(struct file *,void *,filldir_t); -static struct dentry *autofs_root_lookup(struct inode *,struct dentry *); +static struct dentry *autofs_root_lookup(struct inode *,struct dentry *, struct nameidata *); static int autofs_root_symlink(struct inode *,struct dentry *,const char *); static int autofs_root_unlink(struct inode *,struct dentry *); static int autofs_root_rmdir(struct inode *,struct dentry *); @@ -144,7 +144,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str * yet completely filled in, and revalidate has to delay such * lookups.. */ -static int autofs_revalidate(struct dentry * dentry, int flags) +static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) { struct inode * dir; struct autofs_sb_info *sbi; @@ -195,7 +195,7 @@ static struct dentry_operations autofs_dentry_operations = { .d_revalidate = autofs_revalidate, }; -static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi; int oz_mode; @@ -230,7 +230,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr d_add(dentry, NULL); up(&dir->i_sem); - autofs_revalidate(dentry, 0); + autofs_revalidate(dentry, nd); down(&dir->i_sem); /* diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index de61c25779c..49f9f4d3b40 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -18,13 +18,13 @@ #include #include "autofs_i.h" -static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *); +static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *, struct nameidata *); static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); static int autofs4_dir_unlink(struct inode *,struct dentry *); static int autofs4_dir_rmdir(struct inode *,struct dentry *); static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); -static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *); +static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *, struct nameidata *); struct file_operations autofs4_root_operations = { .open = dcache_dir_open, @@ -143,7 +143,7 @@ static int try_to_fill_dentry(struct dentry *dentry, * yet completely filled in, and revalidate has to delay such * lookups.. */ -static int autofs4_root_revalidate(struct dentry * dentry, int flags) +static int autofs4_root_revalidate(struct dentry * dentry, struct nameidata *nd) { struct inode * dir = dentry->d_parent->d_inode; struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); @@ -183,7 +183,7 @@ static int autofs4_root_revalidate(struct dentry * dentry, int flags) return 1; } -static int autofs4_revalidate(struct dentry *dentry, int flags) +static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); @@ -225,7 +225,7 @@ static struct dentry_operations autofs4_dentry_operations = { /* Lookups in non-root dirs never find anything - if it's there, it's already in the dcache */ /* SMP-safe */ -static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { #if 0 DPRINTK(("autofs_dir_lookup: ignoring lookup of %.*s/%.*s\n", @@ -239,7 +239,7 @@ static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentr } /* Lookups in the root directory */ -static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi; int oz_mode; @@ -276,7 +276,7 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent if (dentry->d_op && dentry->d_op->d_revalidate) { up(&dir->i_sem); - (dentry->d_op->d_revalidate)(dentry, 0); + (dentry->d_op->d_revalidate)(dentry, nd); down(&dir->i_sem); } diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 4fb5a163e50..d7846d65b36 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -33,7 +33,7 @@ static int befs_readdir(struct file *, void *, filldir_t); static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int); static int befs_readpage(struct file *file, struct page *page); static sector_t befs_bmap(struct address_space *mapping, sector_t block); -static struct dentry *befs_lookup(struct inode *, struct dentry *); +static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *); static void befs_read_inode(struct inode *ino); static struct inode *befs_alloc_inode(struct super_block *sb); static void befs_destroy_inode(struct inode *inode); @@ -163,7 +163,7 @@ befs_get_block(struct inode *inode, sector_t block, } static struct dentry * -befs_lookup(struct inode *dir, struct dentry *dentry) +befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct super_block *sb = dir->i_sb; diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 386f5fff4a7..7e5b4781eb2 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -78,7 +78,8 @@ struct file_operations bfs_dir_operations = { extern void dump_imap(const char *, struct super_block *); -static int bfs_create(struct inode * dir, struct dentry * dentry, int mode) +static int bfs_create(struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) { int err; struct inode * inode; @@ -127,7 +128,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode) return 0; } -static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry) +static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { struct inode * inode = NULL; struct buffer_head * bh; diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 1c7699cea91..4cdc1b8c502 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -1,15 +1,17 @@ +/****************************************************************************/ /* * linux/fs/binfmt_flat.c * - * Copyright (C) 2000, 2001 Lineo, by David McCullough + * Copyright (C) 2000-2003 David McCullough * Copyright (C) 2002 Greg Ungerer - * + * Copyright (C) 2002 SnapGear, by Paul Dale + * Copyright (C) 2000, 2001 Lineo, by David McCullough * based heavily on: * * linux/fs/binfmt_aout.c: * Copyright (C) 1991, 1992, 1996 Linus Torvalds * linux/fs/binfmt_flat.c for 2.0 kernel - * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1998 Kenneth Albanowski * JAN/99 -- coded full program relocation (gerg@snapgear.com) */ @@ -42,27 +44,69 @@ #include #include -#undef DEBUG +/****************************************************************************/ + +#if 0 +#define DEBUG 1 +#endif + #ifdef DEBUG -#define DBG_FLT(a...) printk(##a) +#define DBG_FLT(a...) printk(a) #else #define DBG_FLT(a...) #endif +#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ +#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ + +struct lib_info { + struct { + unsigned long start_code; /* Start of text segment */ + unsigned long start_data; /* Start of data segment */ + unsigned long start_brk; /* End of data segment */ + unsigned long text_len; /* Length of text segment */ + unsigned long entry; /* Start address for this module */ + unsigned long build_date; /* When this one was compiled */ + short loaded; /* Has this library been loaded? */ + } lib_list[MAX_SHARED_LIBS]; +}; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +static int load_flat_shared_library(int id, struct lib_info *p); +#endif + static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs); -static int load_flat_library(struct file*); +static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file); + extern void dump_thread(struct pt_regs *, struct user *); static struct linux_binfmt flat_format = { - NULL, THIS_MODULE, load_flat_binary, load_flat_library, NULL, PAGE_SIZE + .module = THIS_MODULE, + .load_binary = load_flat_binary, + .core_dump = flat_core_dump, + .min_coredump = PAGE_SIZE }; +/****************************************************************************/ +/* + * Routine writes a core dump image in the current directory. + * Currently only a stub-function. + */ + +static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file) +{ + printk("Process %s:%d received signr %d and should have core dumped\n", + current->comm, current->pid, (int) signr); + return(1); +} +/****************************************************************************/ /* * create_flat_tables() parses the env- and arg-strings in new user * memory and creates the pointer tables from them, and puts their * addresses on the "stack", returning the new stack pointer value. */ + static unsigned long create_flat_tables( unsigned long pp, struct linux_binprm * bprm) @@ -80,10 +124,13 @@ static unsigned long create_flat_tables( envp = sp; sp -= argc+1; argv = sp; + + flat_stack_align(sp); if (flat_argvp_envp_on_stack()) { - put_user((unsigned long) envp, --sp); - put_user((unsigned long) argv, --sp); + --sp; put_user((unsigned long) envp, sp); + --sp; put_user((unsigned long) argv, sp); } + put_user(argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { @@ -105,6 +152,7 @@ static unsigned long create_flat_tables( return (unsigned long)sp; } +/****************************************************************************/ #ifdef CONFIG_BINFMT_ZFLAT @@ -183,7 +231,7 @@ static int decompress_exec( if (buf[3] & EXTRA_FIELD) { ret += 2 + buf[10] + (buf[11] << 8); if (unlikely(LBUFSIZE == ret)) { - DBG_FLAT("binfmt_flat: buffer overflow (EXTRA)?\n"); + DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n"); return -ENOEXEC; } } @@ -191,7 +239,7 @@ static int decompress_exec( for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) ; if (unlikely(LBUFSIZE == ret)) { - DBG_FLAT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); + DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); return -ENOEXEC; } } @@ -199,7 +247,7 @@ static int decompress_exec( for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) ; if (unlikely(LBUFSIZE == ret)) { - DBG_FLAT("binfmt_flat: buffer overflow (COMMENT)?\n"); + DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n"); return -ENOEXEC; } } @@ -243,48 +291,78 @@ static int decompress_exec( #endif /* CONFIG_BINFMT_ZFLAT */ +/****************************************************************************/ static unsigned long -calc_reloc(unsigned long r, unsigned long text_len) +calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) { unsigned long addr; - - if (r > current->mm->start_brk - current->mm->start_data + text_len) { - printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x), killing!\n", - (int) r,(int)(current->mm->start_brk-current->mm->start_code)); - send_sig(SIGSEGV, current, 0); - return(current->mm->start_brk); /* return something safe to write to */ + int id; + unsigned long start_brk; + unsigned long start_data; + unsigned long text_len; + unsigned long start_code; + +#ifdef CONFIG_BINFMT_SHARED_FLAT + if (r == 0) + id = curid; /* Relocs of 0 are always self referring */ + else { + id = (r >> 24) & 0xff; /* Find ID for this reloc */ + r &= 0x00ffffff; /* Trim ID off here */ + } + if (id >= MAX_SHARED_LIBS) { + printk("BINFMT_FLAT: reference 0x%x to shared library %d", + (unsigned) r, id); + goto failed; + } + if (curid != id) { + if (internalp) { + printk("BINFMT_FLAT: reloc address 0x%x not in same module " + "(%d != %d)", (unsigned) r, curid, id); + goto failed; + } else if ( ! p->lib_list[id].loaded && + load_flat_shared_library(id, p) > (unsigned long) -4096) { + printk("BINFMT_FLAT: failed to load library %d", id); + goto failed; + } + /* Check versioning information (i.e. time stamps) */ + if (p->lib_list[id].build_date && p->lib_list[curid].build_date && + p->lib_list[curid].build_date < p->lib_list[id].build_date) { + printk("BINFMT_FLAT: library %d is younger than %d", id, curid); + goto failed; + } } +#else + id = 0; +#endif - if (r < text_len) { - /* In text segment */ - return r + current->mm->start_code; + start_brk = p->lib_list[id].start_brk; + start_data = p->lib_list[id].start_data; + start_code = p->lib_list[id].start_code; + text_len = p->lib_list[id].text_len; + + if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { + printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)", + (int) r,(int)(start_brk-start_code),(int)text_len); + goto failed; } - /* - * we allow inclusive ranges here so that programs may do things - * like reference the end of data (_end) without failing these tests - */ - addr = r - text_len + current->mm->start_data; - if (addr >= current->mm->start_code && - addr <= current->mm->start_code + text_len) - return(addr); - - if (addr >= current->mm->start_data && - addr <= current->mm->start_brk) - return(addr); - - printk("BINFMT_FLAT: reloc addr outside text/data 0x%x " - "code(0x%x - 0x%x) data(0x%x - 0x%x) killing\n", (int) addr, - (int) current->mm->start_code, - (int) (current->mm->start_code + text_len), - (int) current->mm->start_data, - (int) current->mm->start_brk); + if (r < text_len) /* In text segment */ + addr = r + start_code; + else /* In data segment */ + addr = r - text_len + start_data; + + /* Range checked already above so doing the range tests is redundant...*/ + return(addr); + +failed: + printk(", killing %s!\n", current->comm); send_sig(SIGSEGV, current, 0); - return(current->mm->start_brk); /* return something safe to write to */ + return RELOC_FAILED; } +/****************************************************************************/ void old_reloc(unsigned long rl) { @@ -327,26 +405,22 @@ void old_reloc(unsigned long rl) #endif } +/****************************************************************************/ -/* - * These are the functions used to load flat style executables and shared - * libraries. There is no binary dependent code anywhere else. - */ - -static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) +static int load_flat_file(struct linux_binprm * bprm, + struct lib_info *libinfo, int id, unsigned long *extra_stack) { struct flat_hdr * hdr; unsigned long textpos = 0, datapos = 0, result; + unsigned long realdatastart = 0; unsigned long text_len, data_len, bss_len, stack_len, flags; - unsigned long memp = 0, memkasked = 0; /* for finding the brk area */ + unsigned long memp = 0; /* for finding the brk area */ unsigned long extra, rlim; - unsigned long p = bprm->p; unsigned long *reloc = 0, *rp; struct inode *inode; int i, rev, relocs = 0; loff_t fpos; - - DBG_FLT("BINFMT_FLAT: Loading file: %x\n", bprm->file); + unsigned long start_code, end_code; hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ inode = bprm->file->f_dentry->d_inode; @@ -355,41 +429,42 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); stack_len = ntohl(hdr->stack_size); + if (extra_stack) { + stack_len += *extra_stack; + *extra_stack = stack_len; + } relocs = ntohl(hdr->reloc_count); flags = ntohl(hdr->flags); rev = ntohl(hdr->rev); - /* - * We have to add the size of our arguments to our stack size - * otherwise it's too easy for users to create stack overflows - * by passing in a huge argument list. And yes, we have to be - * pedantic and include space for the argv/envp array as it may have - * a lot of entries. - */ - #define TOP_OF_ARGS (PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *)) - stack_len += TOP_OF_ARGS - bprm->p; /* the strings */ - stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ - stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ + if (flags & FLAT_FLAG_KTRACE) + printk("BINFMT_FLAT: Loading file: %s\n", bprm->filename); if (strncmp(hdr->magic, "bFLT", 4) || (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION)) { /* * because a lot of people do not manage to produce good * flat binaries, we leave this printk to help them realise - * the problem. We only print the error if it's - * not a script file. + * the problem. We only print the error if its not a script file */ if (strncmp(hdr->magic, "#!", 2)) printk("BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n", rev, (int) FLAT_VERSION); return -ENOEXEC; } + + /* Don't allow old format executables to use shared libraries */ + if (rev == OLD_FLAT_VERSION && id != 0) { + printk("BINFMT_FLAT: shared libraries are not available before rev 0x%x\n", + (int) FLAT_VERSION); + return -ENOEXEC; + } /* * fix up the flags for the older format, there were all kinds * of endian hacks, this only works for the simple cases */ - if (rev == OLD_FLAT_VERSION && flags) + if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags)) flags = FLAT_FLAG_RAM; #ifndef CONFIG_BINFMT_ZFLAT @@ -411,15 +486,22 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) return -ENOMEM; /* Flush all traces of the currently running executable */ - result = flush_old_exec(bprm); - if (result) - return result; + if (id == 0) { + result = flush_old_exec(bprm); + if (result) + return result; + + /* OK, This is the point of no return */ + set_personality(PER_LINUX); + } - /* OK, This is the point of no return */ - set_personality(PER_LINUX); + /* + * calculate the extra space we need to map in + */ + extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)); /* - * there are a couple of cases here, the separate code/data + * there are a couple of cases here, the seperate code/data * case, and then the fully copied to RAM case which lumps * it all together. */ @@ -437,26 +519,27 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (!textpos) textpos = (unsigned long) -ENOMEM; printk("Unable to mmap process text, errno %d\n", (int)-textpos); + return(textpos); } - extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)), - down_write(¤t->mm->mmap_sem); - datapos = do_mmap(0, 0, data_len + extra, + realdatastart = do_mmap(0, 0, data_len + extra + + MAX_SHARED_LIBS * sizeof(unsigned long), PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0); up_write(¤t->mm->mmap_sem); - if (datapos == 0 || datapos >= (unsigned long)-4096) { - if (!datapos) - datapos = (unsigned long) -ENOMEM; + if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { + if (!realdatastart) + realdatastart = (unsigned long) -ENOMEM; printk("Unable to allocate RAM for process data, errno %d\n", (int)-datapos); do_munmap(current->mm, textpos, text_len); - return datapos; + return realdatastart; } + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long); DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", - data_len + bss_len + stack_len, datapos); + (int)(data_len + bss_len + stack_len), (int)datapos); fpos = ntohl(hdr->data_start); #ifdef CONFIG_BINFMT_ZFLAT @@ -466,30 +549,24 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) } else #endif { - result = bprm->file->f_op->read(bprm->file, - (char *) datapos, data_len + extra, &fpos); + result = bprm->file->f_op->read(bprm->file, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), &fpos); } if (result >= (unsigned long)-4096) { printk("Unable to read data+bss, errno %d\n", (int)-result); do_munmap(current->mm, textpos, text_len); - do_munmap(current->mm, datapos, data_len + extra); + do_munmap(current->mm, realdatastart, data_len + extra); return result; } reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len)); - memp = datapos; - memkasked = data_len + extra; + memp = realdatastart; } else { - /* - * calculate the extra space we need to map in - */ - - extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)), - down_write(¤t->mm->mmap_sem); - textpos = do_mmap(0, 0, text_len + data_len + extra, + textpos = do_mmap(0, 0, text_len + data_len + extra + + MAX_SHARED_LIBS * sizeof(unsigned long), PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0); up_write(¤t->mm->mmap_sem); if (!textpos || textpos >= (unsigned long) -4096) { @@ -497,12 +574,14 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) textpos = (unsigned long) -ENOMEM; printk("Unable to allocate RAM for process text/data, errno %d\n", (int)-textpos); + return(textpos); } - datapos = textpos + ntohl (hdr->data_start); - reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start)); + realdatastart = textpos + ntohl(hdr->data_start); + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long); + reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start) + + MAX_SHARED_LIBS * sizeof(unsigned long)); memp = textpos; - memkasked = text_len + data_len + extra; #ifdef CONFIG_BINFMT_ZFLAT /* @@ -514,6 +593,8 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) (text_len + data_len + (relocs * sizeof(unsigned long)) - sizeof (struct flat_hdr)), 0); + memmove((void *) datapos, (void *) realdatastart, + data_len + (relocs * sizeof(unsigned long))); } else if (flags & FLAT_FLAG_GZDATA) { fpos = 0; result = bprm->file->f_op->read(bprm->file, @@ -527,40 +608,64 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) { fpos = 0; result = bprm->file->f_op->read(bprm->file, - (char *) textpos, text_len + data_len + extra, &fpos); + (char *) textpos, text_len, &fpos); + if (result < (unsigned long) -4096) { + fpos = ntohl(hdr->data_start); + result = bprm->file->f_op->read(bprm->file, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), &fpos); + } } if (result >= (unsigned long)-4096) { printk("Unable to read code+data+bss, errno %d\n",(int)-result); - do_munmap(current->mm, textpos, text_len + data_len + extra); + do_munmap(current->mm, textpos, text_len + data_len + extra + + MAX_SHARED_LIBS * sizeof(unsigned long)); return result; } } - DBG_FLT("Mapping is %x, Entry point is %x, data_start is %x\n", - textpos, ntohl(hdr->entry), ntohl(hdr->data_start)); - - current->mm->start_code = textpos + sizeof (struct flat_hdr); - current->mm->end_code = textpos + text_len; - current->mm->start_data = datapos; - current->mm->end_data = datapos + data_len; - /* - * set up the brk stuff (uses any slack left in data/bss/stack allocation - * We put the brk after the bss (between the bss and stack) like other - * platforms. - */ - current->mm->start_brk = datapos + data_len + bss_len; - current->mm->brk = (current->mm->start_brk + 3) & ~3; - current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; - current->mm->rss = 0; + if (flags & FLAT_FLAG_KTRACE) + printk("Mapping is %x, Entry point is %x, data_start is %x\n", + (int)textpos, 0x00ffffff&ntohl(hdr->entry), ntohl(hdr->data_start)); + + /* The main program needs a little extra setup in the task structure */ + start_code = textpos + sizeof (struct flat_hdr); + end_code = textpos + text_len; + if (id == 0) { + current->mm->start_code = start_code; + current->mm->end_code = end_code; + current->mm->start_data = datapos; + current->mm->end_data = datapos + data_len; + /* + * set up the brk stuff, uses any slack left in data/bss/stack + * allocation. We put the brk after the bss (between the bss + * and stack) like other platforms. + */ + current->mm->start_brk = datapos + data_len + bss_len; + current->mm->brk = (current->mm->start_brk + 3) & ~3; + current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; + current->mm->rss = 0; + } - DBG_FLT("Load %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", - bprm->filename, - (int) current->mm->start_code, (int) current->mm->end_code, - (int) current->mm->start_data, (int) current->mm->end_data, - (int) current->mm->end_data, (int) current->mm->brk); + if (flags & FLAT_FLAG_KTRACE) + printk("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", + id ? "Lib" : "Load", bprm->filename, + (int) start_code, (int) end_code, + (int) datapos, + (int) (datapos + data_len), + (int) (datapos + data_len), + (int) (((datapos + data_len + bss_len) + 3) & ~3)); text_len -= sizeof(struct flat_hdr); /* the real code len */ + /* Store the current module values into the global library structure */ + libinfo->lib_list[id].start_code = start_code; + libinfo->lib_list[id].start_data = datapos; + libinfo->lib_list[id].start_brk = datapos + data_len + bss_len; + libinfo->lib_list[id].text_len = text_len; + libinfo->lib_list[id].loaded = 1; + libinfo->lib_list[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; + libinfo->lib_list[id].build_date = ntohl(hdr->build_date); + /* * We just load the allocations into some temporary memory to * help simplify all this mumbo jumbo @@ -573,10 +678,16 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) * really an offset into the image which contains an offset into the * image. */ - if (flags & FLAT_FLAG_GOTPIC) { - for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) - *rp = calc_reloc(*rp, text_len); + for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) { + unsigned long addr; + if (*rp) { + addr = calc_reloc(*rp, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + *rp = addr; + } + } } /* @@ -590,63 +701,172 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) * reference to be statically initialised to _stext (I've moved * __start to address 4 so that is okay). */ - if (rev > OLD_FLAT_VERSION) { for (i=0; i < relocs; i++) { - unsigned long addr; + unsigned long addr, relval; /* Get the address of the pointer to be relocated (of course, the address has to be relocated first). */ - rp = (unsigned long *) calc_reloc(ntohl(reloc[i]), text_len); + relval = ntohl(reloc[i]); + addr = flat_get_relocate_addr(relval); + rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1); + if (rp == (unsigned long *)RELOC_FAILED) + return -ENOEXEC; /* Get the pointer's value. */ - addr = get_unaligned (rp); - + addr = flat_get_addr_from_rp(rp, relval); if (addr != 0) { /* * Do the relocation. PIC relocs in the data section are * already in target order */ - addr = calc_reloc( - (flags & FLAT_FLAG_GOTPIC) ? addr : ntohl(addr), - text_len); + if ((flags & FLAT_FLAG_GOTPIC) == 0) + addr = ntohl(addr); + addr = calc_reloc(addr, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + /* Write back the relocated pointer. */ - put_unaligned (addr, rp); + flat_put_addr_at_rp(rp, addr, relval); } } } else { for (i=0; i < relocs; i++) old_reloc(ntohl(reloc[i])); } + + flush_icache_range(start_code, end_code); /* zero the BSS, BRK and stack areas */ memset((void*)(datapos + data_len), 0, bss_len + - (current->mm->context.end_brk - current->mm->start_brk) + + (memp + ksize((void *) memp) - stack_len - /* end brk */ + libinfo->lib_list[id].start_brk) + /* start brk */ stack_len); + return 0; +} + + +/****************************************************************************/ +#ifdef CONFIG_BINFMT_SHARED_FLAT + +/* + * Load a shared library into memory. The library gets its own data + * segment (including bss) but not argv/argc/environ. + */ + +static int load_flat_shared_library(int id, struct lib_info *libs) +{ + struct linux_binprm bprm; + int res; + char buf[16]; + + /* Create the file name */ + sprintf(buf, "/lib/lib%d.so", id); + + /* Open the file up */ + bprm.filename = buf; + bprm.file = open_exec(bprm.filename); + res = PTR_ERR(bprm.file); + if (IS_ERR(bprm.file)) + return res; + + res = prepare_binprm(&bprm); + + if (res <= (unsigned long)-4096) + res = load_flat_file(&bprm, libs, id, NULL); + if (bprm.file) { + allow_write_access(bprm.file); + fput(bprm.file); + bprm.file = NULL; + } + return(res); +} + +#endif /* CONFIG_BINFMT_SHARED_FLAT */ +/****************************************************************************/ + +/* + * These are the functions used to load flat style executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + struct lib_info libinfo; + unsigned long p = bprm->p; + unsigned long stack_len; + unsigned long start_addr; + unsigned long *sp; + int res; + int i, j; + + memset(&libinfo, 0, sizeof(libinfo)); + /* + * We have to add the size of our arguments to our stack size + * otherwise it's too easy for users to create stack overflows + * by passing in a huge argument list. And yes, we have to be + * pedantic and include space for the argv/envp array as it may have + * a lot of entries. + */ +#define TOP_OF_ARGS (PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) + stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ + stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ + stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ + + + res = load_flat_file(bprm, &libinfo, 0, &stack_len); + if (res > (unsigned long)-4096) + return res; + + /* Update data segment pointers for all libraries */ + for (i=0; iflags &= ~PF_FORKNOEXEC; - flush_icache_range(current->mm->start_code, current->mm->end_code); - set_binfmt(&flat_format); p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; - DBG_FLT("p=%x\n", p); + DBG_FLT("p=%x\n", (int)p); /* copy the arg pages onto the stack, this could be more efficient :-) */ for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--) * (char *) --p = ((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE]; - current->mm->start_stack = (unsigned long) create_flat_tables(p, bprm); + sp = (unsigned long *) create_flat_tables(p, bprm); + + /* Fake some return addresses to ensure the call chain will + * initialise library in order for us. We are required to call + * lib 1 first, then 2, ... and finally the main program (id 0). + */ + start_addr = libinfo.lib_list[0].entry; + +#ifdef CONFIG_BINFMT_SHARED_FLAT + for (i = MAX_SHARED_LIBS-1; i>0; i--) { + if (libinfo.lib_list[i].loaded) { + /* Push previos first to call address */ + --sp; put_user(start_addr, sp); + start_addr = libinfo.lib_list[i].entry; + } + } +#endif + + /* Stash our initial stack pointer into the mm structure */ + current->mm->start_stack = (unsigned long )sp; + DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n", - regs, textpos + ntohl(hdr->entry), current->mm->start_stack); - start_thread(regs, - textpos + ntohl(hdr->entry), - current->mm->start_stack); + (int)regs, (int)start_addr, (int)current->mm->start_stack); + + start_thread(regs, start_addr, current->mm->start_stack); if (current->ptrace & PT_PTRACED) send_sig(SIGTRAP, current, 0); @@ -654,10 +874,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) return 0; } -static int load_flat_library(struct file *file) -{ - return(-ENOEXEC); -} +/****************************************************************************/ static int __init init_flat_binfmt(void) { @@ -669,5 +886,9 @@ static void __exit exit_flat_binfmt(void) unregister_binfmt(&flat_format); } +/****************************************************************************/ + module_init(init_flat_binfmt); module_exit(exit_flat_binfmt); + +/****************************************************************************/ diff --git a/fs/block_dev.c b/fs/block_dev.c index 52e95645531..74db58a4002 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -155,11 +155,13 @@ static int blkdev_commit_write(struct file *file, struct page *page, unsigned fr */ static loff_t block_llseek(struct file *file, loff_t offset, int origin) { - /* ewww */ - loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size; + struct inode *bd_inode; + loff_t size; loff_t retval; - lock_kernel(); + bd_inode = file->f_dentry->d_inode->i_bdev->bd_inode; + down(&bd_inode->i_sem); + size = bd_inode->i_size; switch (origin) { case 2: @@ -175,7 +177,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) } retval = offset; } - unlock_kernel(); + up(&bd_inode->i_sem); return retval; } diff --git a/fs/buffer.c b/fs/buffer.c index 56c9f4e03bd..d3fbedea7a1 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -319,6 +319,7 @@ asmlinkage long sys_fsync(unsigned int fd) /* We need to protect against concurrent writers.. */ down(&inode->i_sem); + current->flags |= PF_SYNCWRITE; ret = filemap_fdatawrite(inode->i_mapping); err = file->f_op->fsync(file, dentry, 0); if (!ret) @@ -326,6 +327,7 @@ asmlinkage long sys_fsync(unsigned int fd) err = filemap_fdatawait(inode->i_mapping); if (!ret) ret = err; + current->flags &= ~PF_SYNCWRITE; up(&inode->i_sem); out_putf: @@ -354,6 +356,7 @@ asmlinkage long sys_fdatasync(unsigned int fd) goto out_putf; down(&inode->i_sem); + current->flags |= PF_SYNCWRITE; ret = filemap_fdatawrite(inode->i_mapping); err = file->f_op->fsync(file, dentry, 1); if (!ret) @@ -361,6 +364,7 @@ asmlinkage long sys_fdatasync(unsigned int fd) err = filemap_fdatawait(inode->i_mapping); if (!ret) ret = err; + current->flags &= ~PF_SYNCWRITE; up(&inode->i_sem); out_putf: @@ -1447,6 +1451,17 @@ __getblk(struct block_device *bdev, sector_t block, int size) } EXPORT_SYMBOL(__getblk); +/* + * Do async read-ahead on a buffer.. + */ +void __breadahead(struct block_device *bdev, sector_t block, int size) +{ + struct buffer_head *bh = __getblk(bdev, block, size); + ll_rw_block(READA, 1, &bh); + brelse(bh); +} +EXPORT_SYMBOL(__breadahead); + /** * __bread() - reads a specified block and returns the bh * @block: number of block diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 03af9fb3514..a7aa89abfd5 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,13 @@ +Version 0.81 +------------ +Finish up CIFS packet digital signing for the default +NTLM security case. This should help Windows 2003 +network interoperability since it is common for +packet signing to be required now. Fix statfs (stat -f) +which recently started returning errors due to +invalid value (-1 instead of 0) being set in the +struct kstatfs f_ffiles field. + Version 0.80 ----------- Fix oops on stopping oplock thread when removing cifs when diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 1295411affd..94fd2b73c45 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o diff --git a/fs/cifs/README b/fs/cifs/README index 20626fb1aca..12d93b7fadd 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -1,5 +1,5 @@ -This is the CIFS VFS support for Linux. It supports many advanced network filesystem -features such as heirarchical dfs like filesystem, hardlinks, locking and more. +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. It was designed to comply with the SNIA CIFS Technical Reference (which supersedes the 1992 X/Open SMB Standard) as well as to perform best practice practical interoperability with Windows 2000, Windows XP, Samba and equivalent @@ -9,43 +9,65 @@ For questions or bug reports please contact sfrench@samba.org (sfrench@us.ibm.co Build instructions: ================== -Get the kernel source e.g. http://linux.bkbits.net/linux-2.5 or http://www.kernel.org -http://cifs.bkbits.net/linux-2.4 -make menuconfig (or make xconfig) -select cifs from within the network filesystem choices -save and exit -make dep -make modules (or "make" if you did not select CIFS VFS to be built as a module) +For Linux 2.4: +1a) Get the linux kernel source with cifs vfs already in it +from bitkeeper via bk://cifs.bkbits.net/linux-2.4 +or +1b) Get the kernel source (e.g.from http://www.kernel.org) +and download the cifs vfs source (see the project page +at http://us1.samba.org/samba/Linux_CIFS_client.html) +and change directory into the top of the kernel directory +then patch the kernel (e.g. "patch -p1 < cifs_24.patch") +to add the cifs vfs to your kernel configure options if +it has not already been added (e.g. current SuSE and UL +users do not need to do not need that patch since the cifs vfs is +already in the kernel configure menu) and then +mkdir linux/fs/cifs and then copy the current cifs vfs files from +the cifs download to your kernel build directory e.g. + cp /fs/cifs/* to /fs/cifs +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make dep +6) make modules (or "make" if CIFS VFS not to be built as a module) + +For Linux 2.5: +1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper +at bk://linux.bkbits.net/linux-2.5) and change directory into the top +of the kernel directory tree (e.g. /usr/src/linux-2.5.73) +2) make menuconfig (or make xconfig) +3) select cifs from within the network filesystem choices +4) save and exit +5) make + Installation instructions: ========================= -If you have built the CIFS vfs as module (successfully)you -simply type "make modules_install" (or if you prefer manually copy the file to +If you have built the CIFS vfs as module (successfully) simply +type "make modules_install" (or if you prefer, manually copy the file to the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). If you have built the CIFS vfs into the kernel itself, follow the instructions for your distribution on how to install a new kernel (usually you would simply type "make install"). -If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the -CIFS VFS web site) copy it to the directory /sbin (or the same directory in which -mount.smbfs resides). Although no helper software is required, the installation -of mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" +If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on +the CIFS VFS web site) copy it to the same directory in which mount.smbfs and +similar files reside (usually /sbin). Although the helper software is required, +mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" may also be helpful since it may someday provide easier mount syntax for users used to Windows e.g. net use -and there will likely be other helper programs available ala smbmount to provide -additional optional function in the future. Note that running Winbind on all -of your Linux clients is useful in mapping Uids and Gids consistently to the -proper network user. +Note that running Winbind on all of your Linux clients is useful in +in mapping Uids and Gids consistently to the proper network user. Samba Considerations ==================== To get the maximum benefit from the CIFS VFS, we recommend using a server that -supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or Samba 3.0) -but the CIFS vfs works fine with a wide variety of CIFS servers. Note that the -uid, gid and file permissions will display default values if you do not have -a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or later). To enable the Unix CIFS Extensions in the Samba server, add the line: unix extensions = yes to your smb.conf file on the server. Note that the following smb.conf settings are @@ -81,15 +103,79 @@ either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support fo "Netbios-Over-TCP/IP." Neither of these is likely to be a problem as most servers support this. IPv6 support is planned for the future. +CIFS VFS Mount Options +====================== +A partial list of the supported mount options follows: + user The user name to use when trying to establish + the CIFS session. + password The user password. If the mount helper is + installed, the user will be prompted for password + if it is not supplied. + ip The ip address of the target server + unc The target server Universal Network Name (export) to + mount. + domain Set the SMB/CIFS workgroup name prepended to the + username during CIFS session establishment + uid If CIFS Unix extensions are not supported by the server + this overrides the default uid for inodes. + gid If CIFS Unix extensions are not supported by the server + this overrides the default gid for inodes. + file_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for file inodes. + dir_mode If CIFS Unix extensions are not supported by the server + this overrides the default mode for directory inodes. + port attempt to contact the server on this tcp port, before + trying the usual ports (port 445, then 139). + rsize default read size + wsize default write size + rw mount the network share read-write (note that the + server may still consider the share read-only) + ro mount network share read-only + version used to distinguish different versions of the + mount helper utility (not typically needed) + Misc /proc/fs/cifs Flags and Debug Info ======================================= -Various experimental features and tracing can be enabled by changing flags in /proc/fs/cifs (after -the cifs module has been installed or built into the kernel, e.g. insmod cifs). To enable -a feature you can set it to 1 e.g. to enable tracing to the kernel message log you can do -"echo 1 > /proc/fs/cifs/cifsFYI" and "echo 1 > /proc/fs/cifs/traceSMB" -Also note that "cat /proc/fs/cifs/DebugData" will display some information about the currently -active sessions and the shares that are mounted. Currently the ntlmv2 enablement and packet -signing will not work since they the implementation is not quite complete, so do not enable +Informational pseudo-files: + DebugData Displays information about active CIFS sessions + SimultaneousOps Counter which holds maximum number of + simultaneous outstanding SMB/CIFS requests. + Stats Lists summary resource usage information + +Configuration pseudo-files: + MultiuserMount If set to one, more than one CIFS session to + the same server ip address can be established + if more than one uid accesses the same mount + point and if the uids user/password mapping + information is available. (default is 0) + PacketSigningEnabled If set to one, cifs packet signing is enabled + (default 0) + cifsFYI If set to one, additional debug information is + logged to the system error log. (default 0) + ExtendedSecurity If set to one, SPNEGO session establishment + is allowed which enables more advanced + secure CIFS session establishment (default 0) + NTLMV2Enabled If set to one, more secure password hashes + are used when the server supports them and + when kerberos is not negotiated (default 0) + traceSMB If set to one, debug information is logged to the + system error log with the start of smb requests + and responses (default 0) + LookupCacheEnable If set to one, inode information is kept cached + for one second improving performance of lookups + (default 1) + OplockEnabled If set to one, safe distributed caching enabled. + +These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs +(after the cifs module has been installed or built into the kernel, e.g. insmod cifs). +To enable a feature set it to 1 e.g. to enable tracing to the kernel message log +type: + echo 1 > /proc/fs/cifs/cifsFYI +and for more extensive tracing including the start of smb requests and responses + echo 1 > /proc/fs/cifs/traceSMB +Also note that "cat /proc/fs/cifs/DebugData" will display some information about the +active sessions and the shares that are mounted. NTLMv2 enablement and packet +signing will not work since they the implementation is not quite complete. Do not enable these flags unless you are doing specific testing. Enabling extended security works to Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which diff --git a/fs/cifs/TODO b/fs/cifs/TODO index e47e28db4f2..28a2c85fb92 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 0.6.5 February 15, 2003 +version 0.8.1 July 4th, 2003 A Partial List of Known Problems and Missing Features ===================================================== @@ -19,10 +19,9 @@ d) Kerberos/SPNEGO session setup support - (started) e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented) signing necessary for some Windows 2003 servers in domain - controller mode. + mode. -f) oplock support (ie safe CIFS distributed file caching) is not quite complete. -In addition Directory entry caching relies on a 1 second timer, rather than +f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) g) There may be a few additional changes that could be done to take advantage @@ -47,15 +46,16 @@ m) finish support for IPv6 n) send oplock break response when sent (oplock currently disabled in /proc/fs/cifs) -o) remove calls to set end of file by name when we already have file open -(use the existing handle since some servers only support that and it -reduces the oplock breaks coming from windows). Piggyback identical +o) reduces the oplock breaks coming from windows). Piggyback identical file opens on top of each other by incrementing reference count rather than resending (helps reduce server resource utilization and avoid spurious oplock breaks). +p) Improve performance of readpages by sending more than one read +at a time when 8 pages or more are requested. -KNOWN BUGS (updated May 16, 2003) + +KNOWN BUGS (updated July 4th, 2003) ==================================== 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that @@ -74,8 +74,8 @@ Misc testing to do 1) check out max path names and max path name components against various server types. -2) Run dbench +2) Run dbench. Modify file portion of ltp so it can run against a mounted network +share and run it against cifs vfs. -3) Finish high stress fsx testing on SMP clients +3) Additional performance testing and optimization using iozone and similar tools. -4) Additional performance testing and optimization diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 78425d07e5b..e8a97a8949e 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -34,7 +34,7 @@ void toUpper(const struct nls_table *n, char *mixed_string) { - int i; + unsigned int i; char temp; for (i = 0; i < strlen(mixed_string); i++) { diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c new file mode 100644 index 00000000000..db3226e6272 --- /dev/null +++ b/fs/cifs/cifsencrypt.c @@ -0,0 +1,140 @@ +/* + * fs/cifs/cifsencrypt.c + * + * Copyright (c) International Business Machines Corp., 2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifs_debug.h" +#include "md5.h" + +/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ +/* the 16 byte signature must be allocated by the caller */ +/* Note we only use the 1st eight bytes */ +/* Note that the smb header signature field on input contains the + sequence number before this function is called */ + +extern void mdfour(unsigned char *out, unsigned char *in, int n); +extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); + +static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) +{ + struct MD5Context context; + + if((cifs_pdu == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); + MD5Final(signature,&context); + return 0; +} + +int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + + /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ + /* BB remember to add code to save expected sequence number in midQ entry BB */ + + if((cifs_pdu == NULL) || (ses == NULL)) + return -EINVAL; + + if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + write_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = ses->sequence_number++; + ses->sequence_number++; + write_unlock(&GlobalMid_Lock); + + rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; +} + +int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, + __u32 expected_sequence_number) +{ + unsigned int rc; + char server_response_sig[8]; + char what_we_think_sig_should_be[20]; + + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; + + if (cifs_pdu->Command == SMB_COM_NEGOTIATE) + return 0; + + /* BB what if signatures are supposed to be on for session but server does not + send one? BB */ + /* BB also do not verify oplock breaks for signature */ + + /* Do not need to verify session setups with signature "BSRSPYL " */ + if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) + cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); + + expected_sequence_number = cpu_to_le32(expected_sequence_number); + + /* save off the origiginal signature so we can modify the smb and check + its signature against what the server sent */ + memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); + + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; + + rc = cifs_calculate_signature(cifs_pdu, mac_key, + what_we_think_sig_should_be); + + if(rc) + return rc; + + +/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ + + if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) + return -EACCES; + else + return 0; + +} + +/* We fill in key by putting in 40 byte array which was allocated by caller */ +int cifs_calculate_mac_key(char * key, const char * rn, const char * password) +{ + char temp_key[16]; + if ((key == NULL) || (rn == NULL) || (password == NULL)) + return -EINVAL; + + E_md4hash(password, temp_key); /* BB may have to do another md4 of it */ + mdfour(key,temp_key,16); + memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); + return 0; +} diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1b3c43949f3..60e4629b1d6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -165,7 +165,7 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) able to support more than this, but best to be safe since Win2k and others can not handle very long filenames */ buf->f_files = 0; /* undefined */ - buf->f_ffree = -1; /* unlimited */ + buf->f_ffree = 0; /* unlimited */ rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); @@ -178,7 +178,7 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) return 0; /* always return success? what if volume is no longer available? */ } -static int cifs_permission(struct inode * inode, int mask) +static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) { /* the server does permission checks, we do not need to do it here */ return 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 2776f7c0b7c..0c0d756c53a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -46,8 +46,8 @@ extern void cifs_delete_inode(struct inode *); /* Functions related to inodes */ extern struct inode_operations cifs_dir_inode_ops; -extern int cifs_create(struct inode *, struct dentry *, int); -extern struct dentry *cifs_lookup(struct inode *, struct dentry *); +extern int cifs_create(struct inode *, struct dentry *, int, struct nameidata *); +extern struct dentry *cifs_lookup(struct inode *, struct dentry *, struct nameidata *); extern int cifs_unlink(struct inode *, struct dentry *); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); extern int cifs_mkdir(struct inode *, struct dentry *, int); @@ -88,5 +88,9 @@ extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen); extern int cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname); - +extern int cifs_removexattr(struct dentry *, const char *); +extern int cifs_setxattr(struct dentry *, const char *, const void *, + size_t, int); +extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); #endif /* _CIFSSMB_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ae3e49d1de4..5b0ae3bc20c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -149,7 +149,9 @@ struct cifsSesInfo { struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of CURRENT users of this ses */ enum statusEnum status; + __u32 sequence_number; /* needed for CIFS PDU signature */ __u16 ipc_tid; /* special tid for connection to IPC share */ + char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; char *serverOS; /* name of operating system underlying the server */ char *serverNOS; /* name of network operating system that the server is running */ char *serverDomain; /* security realm of server */ @@ -249,6 +251,7 @@ struct mid_q_entry { struct list_head qhead; /* mids waiting on reply from this server */ __u16 mid; /* multiplex id */ __u16 pid; /* process id */ + __u32 sequence_number; /* for CIFS signing */ __u16 command; /* smb command code */ struct timeval when_sent; /* time when smb sent */ struct cifsSesInfo *ses; /* smb was sent to this server */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 1e6be805412..bd9e6183deb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -307,7 +307,13 @@ struct smb_hdr { __u8 Flags; __u16 Flags2; /* note: le */ __u16 PidHigh; /* note: le */ - __u8 SecuritySignature[8]; /* note le */ + union { + struct { + __u32 SequenceNumber; /* le */ + __u32 Reserved; /* zero */ + } Sequence; + __u8 SecuritySignature[8]; /* le */ + } Signature; __u8 pad[2]; __u16 Tid; __u16 Pid; /* note: le */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e557442f61f..5b9dded835e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -79,8 +79,7 @@ extern int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *session_key, char *ntlm_session_key, - const struct nls_table *); + char *ntlm_session_key, const struct nls_table *); extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *SecurityBlob,int SecurityBlobLength, const struct nls_table *); @@ -226,6 +225,11 @@ extern void tconInfoFree(struct cifsTconInfo *); extern int cifs_demultiplex_thread(struct TCP_Server_Info *); extern int cifs_reconnect(struct TCP_Server_Info *server); +extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); +extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, + __u32 expected_sequence_number); +extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); + /* BB routines below not implemented yet BB */ extern int CIFSBuildServerList(int xid, char *serverBufferList, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 1d2d347e3ad..5761b834929 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -106,9 +106,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; if (extended_security) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - if (sign_CIFS_PDUs) { - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - } pSMB->ByteCount = strlen(protocols[0].name) + 1; strncpy(pSMB->DialectsArray, protocols[0].name, 30); @@ -260,10 +257,13 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) up(&ses->sesSem); return -EBUSY; } - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */, (void **) &pSMB, (void **) &smb_buffer_response); + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if (rc) { up(&ses->sesSem); return rc; @@ -1657,8 +1657,6 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, if (ses->capabilities & CAP_DFS) { pSMB->hdr.Flags2 |= SMBFLG2_DFS; } - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index add558cc01a..f861fd7c5e4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -200,7 +200,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; } pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); - cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); /* BB */ + cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); temp = (char *) smb_buffer; if (length > 3) { @@ -332,8 +332,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) kfree(server); } else /* BB need to more gracefully handle the rare negative session response case because response will be still outstanding */ - cERROR(1, ("There are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ -/* BB Need to fix bug in error path above - perhaps wait until smb requests + cERROR(1, ("Active MIDs in queue while exiting - can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); + /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ + /* BB Need to fix bug in error path above - perhaps wait until smb requests time out and then free the tcp per server struct BB */ read_unlock(&GlobalSMBSeslock); @@ -641,6 +642,7 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ rc = CIFSSMBNegotiate(xid, pSesInfo); pSesInfo->capabilities = pSesInfo->server->capabilities; + pSesInfo->sequence_number = 0; if (!rc) { cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", pSesInfo->server->secMode, @@ -671,6 +673,8 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab SMBNTencrypt(pSesInfo->password_with_pad, pSesInfo->server->cryptKey,ntlm_session_key); + /* BB add call to save MAC key here BB */ + /* for better security the weaker lanman hash not sent in AuthSessSetup so why bother calculating it */ /* toUpper(nls_info, @@ -689,10 +693,10 @@ int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_tab SMBNTencrypt(pSesInfo->password_with_pad, pSesInfo->server->cryptKey, ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, ntlm_session_key, pSesInfo->password_with_pad); rc = CIFSSessSetup(xid, pSesInfo, - session_key, - ntlm_session_key, - nls_info); + ntlm_session_key, nls_info); } if (rc) { cERROR(1,("Send error in SessSetup = %d",rc)); @@ -1024,7 +1028,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char session_key[CIFS_SESSION_KEY_SIZE], - char session_key2[CIFS_SESSION_KEY_SIZE], const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -1081,9 +1084,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - /* memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); + /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; */ - memcpy(bcc_ptr, (char *) session_key2, CIFS_SESSION_KEY_SIZE); + memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); bcc_ptr += CIFS_SESSION_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { @@ -1094,7 +1097,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(user == NULL) bytes_returned = 0; /* skill null user */ else - bytes_returned = + bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 123639718e9..69c4b70e6b4 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -119,7 +119,8 @@ build_wildcard_path_from_dentry(struct dentry *direntry) /* Inode operations in similar order to how they appear in the Linux file fs.h */ int -cifs_create(struct inode *inode, struct dentry *direntry, int mode) +cifs_create(struct inode *inode, struct dentry *direntry, int mode, + struct nameidata *nd) { int rc = -ENOENT; int xid; @@ -178,7 +179,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) } struct dentry * -cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) +cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd) { int rc, xid; struct cifs_sb_info *cifs_sb; @@ -262,7 +263,7 @@ cifs_dir_open(struct inode *inode, struct file *file) } static int -cifs_d_revalidate(struct dentry *direntry, int flags) +cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) { int isValid = 1; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 19b4bd43dca..3d78ae445e3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -635,9 +635,9 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) struct cifsFileInfo *open_file = NULL; FILE_BASIC_INFO time_buf; int set_time = FALSE; - __u64 mode = 0xFFFFFFFFFFFFFFFF; - __u64 uid = 0xFFFFFFFFFFFFFFFF; - __u64 gid = 0xFFFFFFFFFFFFFFFF; + __u64 mode = 0xFFFFFFFFFFFFFFFFULL; + __u64 uid = 0xFFFFFFFFFFFFFFFFULL; + __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; xid = GetXid(); diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 79cbdc7feef..82e27cac1c5 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -399,7 +399,7 @@ SamOEMhash(unsigned char *data, unsigned char *key, int val) s_box[ind] = s_box[j]; s_box[j] = tc; } - for (ind = 0; ind < (val ? 516 : 16); ind++) { + for (ind = 0; ind < val; ind++) { unsigned char tc; unsigned char t; diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 2e84b92c010..9c810c517cf 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -5,7 +5,8 @@ Copyright (C) Andrew Tridgell 1992-2000 Copyright (C) Luke Kenneth Casson Leighton 1996-2000 Modified by Jeremy Allison 1995. - Modified by Steve French (sfrench@us.ibm.com) 2002 + Copyright (C) Andrew Bartlett 2002-2003 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -97,13 +98,15 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) E_P16(p14, p21); SMBOWFencrypt(p21, c8, p24); - + #ifdef DEBUG_PASSWORD DEBUG(100, ("SMBencrypt: lm#, challenge, response\n")); dump_data(100, (char *) p21, 16); dump_data(100, (char *) c8, 8); dump_data(100, (char *) p24, 24); #endif + memset(p14,0,15); + memset(p21,0,21); } /* Routines for Windows NT MD4 Hash functions. */ @@ -161,6 +164,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) len = _my_wcslen(wpwd) * sizeof (__u16); mdfour(p16, (unsigned char *) wpwd, len); + memset(wpwd,0,129 * 2); } /* Does both the NT and LM owfs of a user's password */ @@ -222,7 +226,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n, /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ - /* do not think it is supposed to be uppercased */ + /* BB user and domain may need to be uppercased */ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); @@ -297,8 +301,52 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) #endif } -int -make_oem_passwd_hash(char data[516], const char *passwd, +/* Does the md5 encryption from the NT hash for NTLMv2. */ +void +SMBOWFencrypt_ntv2(const unsigned char kr[16], + const struct data_blob * srv_chal, + const struct data_blob * cli_chal, unsigned char resp_buf[16]) +{ + struct HMACMD5Context ctx; + + hmac_md5_init_limK_to_64(kr, 16, &ctx); + hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); + hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); + hmac_md5_final(resp_buf, &ctx); + +#ifdef DEBUG_PASSWORD + DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); + dump_data(100, srv_chal->data, srv_chal->length); + dump_data(100, cli_chal->data, cli_chal->length); + dump_data(100, resp_buf, 16); +#endif +} + +static struct data_blob LMv2_generate_response(const unsigned char ntlm_v2_hash[16], + const struct data_blob * server_chal) +{ + unsigned char lmv2_response[16]; + struct data_blob lmv2_client_data/* = data_blob(NULL, 8)*/; /* BB Fix BB */ + struct data_blob final_response /* = data_blob(NULL, 24)*/; /* BB Fix BB */ + + /* LMv2 */ + /* client-supplied random data */ + get_random_bytes(lmv2_client_data.data, lmv2_client_data.length); + /* Given that data, and the challenge from the server, generate a response */ + SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response); + memcpy(final_response.data, lmv2_response, sizeof(lmv2_response)); + + /* after the first 16 bytes is the random data we generated above, + so the server can verify us with it */ + memcpy(final_response.data+sizeof(lmv2_response), + lmv2_client_data.data, lmv2_client_data.length); + +/* data_blob_free(&lmv2_client_data); */ /* BB fix BB */ + + return final_response; +} + +int make_oem_passwd_hash(char data[516], const char *passwd, unsigned char old_pw_hash[16], int unicode) { int new_pw_len = strlen(passwd) * (unicode ? 2 : 1); @@ -333,32 +381,11 @@ make_oem_passwd_hash(char data[516], const char *passwd, DEBUG(100, ("make_oem_passwd_hash\n")); dump_data(100, data, 516); #endif - SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, TRUE); + SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, 516); return TRUE; } -/* Does the md5 encryption from the NT hash for NTLMv2. */ -void -SMBOWFencrypt_ntv2(const unsigned char kr[16], - const struct data_blob srv_chal, - const struct data_blob cli_chal, unsigned char resp_buf[16]) -{ - struct HMACMD5Context ctx; - - hmac_md5_init_limK_to_64(kr, 16, &ctx); - hmac_md5_update(srv_chal.data, srv_chal.length, &ctx); - hmac_md5_update(cli_chal.data, cli_chal.length, &ctx); - hmac_md5_final(resp_buf, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); - dump_data(100, srv_chal.data, srv_chal.length); - dump_data(100, cli_chal.data, cli_chal.length); - dump_data(100, resp_buf, 16); -#endif -} - void SMBsesskeygen_ntv2(const unsigned char kr[16], const unsigned char *nt_resp, __u8 sess_key[16]) @@ -407,6 +434,44 @@ encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length) return TRUE; } +int SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, + const struct data_blob *server_chal, + const struct data_blob *names_blob, + struct data_blob *lm_response, struct data_blob *nt_response, + struct data_blob *nt_session_key,struct nls_table * nls_codepage) +{ + unsigned char nt_hash[16]; + unsigned char ntlm_v2_hash[16]; + E_md4hash(password, nt_hash); + + /* We don't use the NT# directly. Instead we use it mashed up with + the username and domain. + This prevents username swapping during the auth exchange + */ + ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash,nls_codepage); + + if (nt_response) { +/* *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, + names_blob); */ /* BB fix BB */ + if (nt_session_key) { +/* *nt_session_key = data_blob(NULL, 16); */ /* BB fix BB */ + + /* The NTLMv2 calculations also provide a session key, for signing etc later */ + /* use only the first 16 bytes of nt_response for session key */ + SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data); + } + } + + /* LMv2 */ + + if (lm_response) { + *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal); + } + + return TRUE; +} + + /*********************************************************** SMB signing - setup the MAC key. ************************************************************/ @@ -455,7 +520,7 @@ cli_caclulate_sign_mac(struct smb_hdr *outbuf, __u8 * mac_key, be32_to_cpu(outbuf->smb_buf_length)); MD5Final(calc_md5_mac, &md5_ctx); - memcpy(outbuf->SecuritySignature, calc_md5_mac, 8); + memcpy(outbuf->Signature.SecuritySignature, calc_md5_mac, 8); (*send_seq_num)++; *reply_seq_num = *send_seq_num; (*send_seq_num)++; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 4705a16d9ef..5d976743f72 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -154,12 +154,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, /* smb header is converted in header_assemble. bcc and rest of SMB word area, and byte area if necessary, is converted to littleendian in - cifssmb.c and RFC1001 len is converted to bigendian in smb_send */ - if (smb_buf_length > 12) - smb_buffer->Flags2 = cpu_to_le16(smb_buffer->Flags2); - - /* if(smb_buffer->Flags2 & SMBFLG2_SECURITY_SIGNATURE) - sign_smb(smb_buffer); */ /* BB enable when signing tested more */ + cifssmb.c and RFC1001 len is converted to bigendian in smb_send + Flags2 is converted in SendReceive */ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); cFYI(1, ("Sending smb of length %d ", smb_buf_length)); @@ -200,6 +196,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, DeleteMidQEntry(midQ); return -EIO; } + + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->sockAddr)); @@ -247,11 +249,18 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, memcpy(out_buf, midQ->resp_buf, receive_len + 4 /* include 4 byte RFC1001 header */ ); - /* convert the length back to a form that we can use */ dump_smb(out_buf, 92); + /* convert the length into a more usable form */ out_buf->smb_buf_length = be32_to_cpu(out_buf->smb_buf_length); + if((out_buf->smb_buf_length > 24) && + (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { + rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ + if(rc) + cFYI(1,("Unexpected signature received from server")); + } + if (out_buf->smb_buf_length > 12) out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); if (out_buf->smb_buf_length > 28) diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c new file mode 100644 index 00000000000..e377fa0247f --- /dev/null +++ b/fs/cifs/xattr.c @@ -0,0 +1,56 @@ +/* + * fs/cifs/xattr.c + * + * Copyright (c) International Business Machines Corp., 2003 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +int cifs_removexattr(struct dentry * direntry, const char * name) +{ + int rc = -EOPNOTSUPP; + return rc; +} + +int cifs_setxattr(struct dentry * direntry, const char * name, + const void * value, size_t size, int flags) +{ + int rc = -EOPNOTSUPP; + return rc; +} + +ssize_t cifs_getxattr(struct dentry * direntry, const char * name, + void * value, size_t size) +{ + ssize_t rc = -EOPNOTSUPP; + return rc; +} + +ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) +{ + ssize_t rc = -EOPNOTSUPP; + + /* return dosattributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ + + /* if proc/fs/cifs/streamstoxattr is set then + search server for EAs or streams to + returns as xattrs */ + + return rc; +} diff --git a/fs/coda/dir.c b/fs/coda/dir.c index a7952879bd8..2917ab9f497 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -28,9 +28,9 @@ #include /* dir inode-ops */ -static int coda_create(struct inode *dir, struct dentry *new, int mode); +static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd); static int coda_mknod(struct inode *dir, struct dentry *new, int mode, dev_t rdev); -static struct dentry *coda_lookup(struct inode *dir, struct dentry *target); +static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd); static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry); static int coda_unlink(struct inode *dir_inode, struct dentry *entry); @@ -45,7 +45,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); /* dentry ops */ -static int coda_dentry_revalidate(struct dentry *de, int); +static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); static int coda_dentry_delete(struct dentry *); /* support routines */ @@ -90,7 +90,7 @@ struct file_operations coda_dir_operations = { /* inode operations for directories */ /* access routines: lookup, readlink, permission */ -static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) +static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct inode *res_inode = NULL; struct ViceFid resfid = {0,0,0}; @@ -147,7 +147,7 @@ exit: } -int coda_permission(struct inode *inode, int mask) +int coda_permission(struct inode *inode, int mask, struct nameidata *nd) { int error = 0; @@ -190,7 +190,7 @@ static inline void coda_dir_changed(struct inode *dir, int link) } /* creation routines: create, mknod, mkdir, link, symlink */ -static int coda_create(struct inode *dir, struct dentry *de, int mode) +static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd) { int error=0; const char *name=de->d_name.name; @@ -627,7 +627,7 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir, } /* called when a cache lookup succeeds */ -static int coda_dentry_revalidate(struct dentry *de, int flags) +static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) { struct inode *inode = de->d_inode; struct coda_inode_info *cii; diff --git a/fs/coda/file.c b/fs/coda/file.c index 486ca3af939..8d4865cbc91 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -153,19 +153,22 @@ int coda_flush(struct file *coda_file) struct inode *coda_inode; int err = 0, fcnt; + lock_kernel(); + coda_vfs_stat.flush++; /* last close semantics */ fcnt = file_count(coda_file); - if (fcnt > 1) return 0; + if (fcnt > 1) + goto out; /* No need to make an upcall when we have not made any modifications * to the file */ if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY) - return 0; + goto out; if (use_coda_close) - return 0; + goto out; cfi = CODA_FTOC(coda_file); BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); @@ -180,6 +183,8 @@ int coda_flush(struct file *coda_file) err = 0; } +out: + unlock_kernel(); return err; } diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 67228f3c212..e10ac76438c 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -24,7 +24,8 @@ #include /* pioctl ops */ -static int coda_ioctl_permission(struct inode *inode, int mask); +static int coda_ioctl_permission(struct inode *inode, int mask, + struct nameidata *nd); static int coda_pioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long user_data); @@ -41,7 +42,8 @@ struct file_operations coda_ioctl_operations = { }; /* the coda pioctl inode ops */ -static int coda_ioctl_permission(struct inode *inode, int mask) +static int coda_ioctl_permission(struct inode *inode, int mask, + struct nameidata *nd) { return 0; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index c6d6844796b..b6a83ad7b32 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -342,7 +342,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) /* * Lookup and fill in the inode data.. */ -static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned int offset = 0; int sorted; diff --git a/fs/devfs/base.c b/fs/devfs/base.c index c632affe5da..5c787aaa490 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2175,7 +2175,7 @@ static struct dentry_operations devfs_dops = .d_iput = devfs_d_iput, }; -static int devfs_d_revalidate_wait (struct dentry *dentry, int flags); +static int devfs_d_revalidate_wait (struct dentry *dentry, struct nameidata *); static struct dentry_operations devfs_wait_dops = { @@ -2212,7 +2212,7 @@ struct devfs_lookup_struct /* XXX: this doesn't handle the case where we got a negative dentry but a devfs entry has been registered in the meanwhile */ -static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) +static int devfs_d_revalidate_wait (struct dentry *dentry, struct nameidata *nd) { struct inode *dir = dentry->d_parent->d_inode; struct fs_info *fs_info = dir->i_sb->s_fs_info; @@ -2265,7 +2265,7 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) /* Inode operations for device entries follow */ -static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) +static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */ struct devfs_lookup_struct lookup_info; diff --git a/fs/dquot.c b/fs/dquot.c index 34f9417ed71..9b3a6aae6c5 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -74,6 +74,7 @@ #include #include #include +#include #include @@ -96,6 +97,7 @@ spinlock_t dq_data_lock = SPIN_LOCK_UNLOCKED; static char *quotatypes[] = INITQFNAMES; static struct quota_format_type *quota_formats; /* List of registered formats */ +static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES; int register_quota_format(struct quota_format_type *fmt) { @@ -123,8 +125,19 @@ static struct quota_format_type *find_quota_format(int id) spin_lock(&dq_list_lock); for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); - if (actqf && !try_module_get(actqf->qf_owner)) - actqf = NULL; + if (!actqf || !try_module_get(actqf->qf_owner)) { + int qm; + + for (qm = 0; module_names[qm].qm_fmt_id && module_names[qm].qm_fmt_id != id; qm++); + if (!module_names[qm].qm_fmt_id || request_module(module_names[qm].qm_mod_name)) { + actqf = NULL; + goto out; + } + for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next); + if (actqf && !try_module_get(actqf->qf_owner)) + actqf = NULL; + } +out: spin_unlock(&dq_list_lock); return actqf; } diff --git a/fs/efs/namei.c b/fs/efs/namei.c index 086630cc435..e6c7210f0a6 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c @@ -57,7 +57,7 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) return(0); } -struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry) { +struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { efs_ino_t inodenum; struct inode * inode = NULL; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index b17cdae0109..d6fef13ef5e 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -443,29 +443,17 @@ void eventpoll_init_file(struct file *file) /* - * This is called from inside fs/file_table.c:__fput() to unlink files - * from the eventpoll interface. We need to have this facility to cleanup - * correctly files that are closed without being removed from the eventpoll - * interface. + * This is called from eventpoll_release() to unlink files from the eventpoll + * interface. We need to have this facility to cleanup correctly files that are + * closed without being removed from the eventpoll interface. */ -void eventpoll_release(struct file *file) +void eventpoll_release_file(struct file *file) { struct list_head *lsthead = &file->f_ep_links; struct eventpoll *ep; struct epitem *epi; /* - * Fast check to avoid the get/release of the semaphore. Since - * we're doing this outside the semaphore lock, it might return - * false negatives, but we don't care. It'll help in 99.99% of cases - * to avoid the semaphore lock. False positives simply cannot happen - * because the file in on the way to be removed and nobody ( but - * eventpoll ) has still a reference to this file. - */ - if (list_empty(lsthead)) - return; - - /* * We don't want to get "file->f_ep_lock" because it is not * necessary. It is not necessary because we're in the "struct file" * cleanup path, and this means that noone is using this file anymore. @@ -541,7 +529,7 @@ eexit_1: /* * The following function implement the controller interface for the eventpoll * file that enable the insertion/removal/change of file descriptors inside - * the interest set. It rapresents the kernel part of the user spcae epoll_ctl(2). + * the interest set. It rapresents the kernel part of the user space epoll_ctl(2). */ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) { @@ -551,8 +539,8 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event *even struct epitem *epi; struct epoll_event epds; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u)\n", - current, epfd, op, fd, event->events)); + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n", + current, epfd, op, fd, event)); error = -EFAULT; if (copy_from_user(&epds, event, sizeof(struct epoll_event))) @@ -633,8 +621,8 @@ eexit_3: eexit_2: fput(file); eexit_1: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n", - current, epfd, op, fd, event->events, error)); + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n", + current, epfd, op, fd, event, error)); return error; } diff --git a/fs/exec.c b/fs/exec.c index 204d0a3a156..36a11c0eddd 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -117,7 +117,8 @@ asmlinkage long sys_uselib(const char __user * library) struct nameidata nd; int error; - error = user_path_walk(library, &nd); + nd.intent.open.flags = O_RDONLY; + error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); if (error) goto out; @@ -125,7 +126,7 @@ asmlinkage long sys_uselib(const char __user * library) if (!S_ISREG(nd.dentry->d_inode->i_mode)) goto exit; - error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC); + error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC, &nd); if (error) goto exit; @@ -392,7 +393,7 @@ int setup_arg_pages(struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; - if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { + if (security_vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { kmem_cache_free(vm_area_cachep, mpnt); return -ENOMEM; } @@ -441,9 +442,9 @@ static inline void free_arg_pages(struct linux_binprm *bprm) { int i; - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + for (i = 0; i < MAX_ARG_PAGES; i++) { if (bprm->page[i]) - __free_page(bprm->page[i]); + __free_page(bprm->page[i]); bprm->page[i] = NULL; } } @@ -461,7 +462,7 @@ struct file *open_exec(const char *name) file = ERR_PTR(-EACCES); if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && S_ISREG(inode->i_mode)) { - int err = permission(inode, MAY_EXEC); + int err = permission(inode, MAY_EXEC, &nd); if (!err && !(inode->i_mode & 0111)) err = -EACCES; file = ERR_PTR(err); @@ -758,12 +759,6 @@ int flush_old_exec(struct linux_binprm * bprm) char * name; int i, ch, retval; - /* - * Release all of the old mmap stuff - */ - retval = exec_mmap(bprm->mm); - if (retval) - goto out; /* * Make sure we have a private signal table and that * we are unassociated from the previous thread group. @@ -772,6 +767,15 @@ int flush_old_exec(struct linux_binprm * bprm) if (retval) goto out; + /* + * Release all of the old mmap stuff + */ + retval = exec_mmap(bprm->mm); + if (retval) + goto out; + + bprm->mm = NULL; /* We're using it now */ + /* This is the point of no return */ current->sas_ss_sp = current->sas_ss_size = 0; @@ -791,7 +795,7 @@ int flush_old_exec(struct linux_binprm * bprm) flush_thread(); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->file->f_dentry->d_inode,MAY_READ)) + permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL)) current->mm->dumpable = 0; /* An exec changes our domain. We are no longer part of the thread @@ -999,7 +1003,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) } read_lock(&binfmt_lock); put_binfmt(fmt); - if (retval != -ENOEXEC) + if (retval != -ENOEXEC || bprm->mm == NULL) break; if (!bprm->file) { read_unlock(&binfmt_lock); @@ -1007,7 +1011,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) } } read_unlock(&binfmt_lock); - if (retval != -ENOEXEC) { + if (retval != -ENOEXEC || bprm->mm == NULL) { break; #ifdef CONFIG_KMOD }else{ @@ -1035,7 +1039,6 @@ int do_execve(char * filename, struct linux_binprm bprm; struct file *file; int retval; - int i; sched_balance_exec(); @@ -1103,17 +1106,14 @@ int do_execve(char * filename, out: /* Something went wrong, return the inode and free the argument pages*/ - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - struct page * page = bprm.page[i]; - if (page) - __free_page(page); - } + free_arg_pages(&bprm); if (bprm.security) security_bprm_free(&bprm); out_mm: - mmdrop(bprm.mm); + if (bprm.mm) + mmdrop(bprm.mm); out_file: if (bprm.file) { @@ -1256,10 +1256,21 @@ void format_corename(char *corename, const char *pattern, long signr) static void zap_threads (struct mm_struct *mm) { struct task_struct *g, *p; + struct task_struct *tsk = current; + struct completion *vfork_done = tsk->vfork_done; + + /* + * Make sure nobody is waiting for us to release the VM, + * otherwise we can deadlock when we wait on each other + */ + if (vfork_done) { + tsk->vfork_done = NULL; + complete(vfork_done); + } read_lock(&tasklist_lock); do_each_thread(g,p) - if (mm == p->mm && p != current) { + if (mm == p->mm && p != tsk) { force_sig_specific(SIGKILL, p); mm->core_waiters++; } diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 9367f43f4ac..0df165f8ee0 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -1,7 +1,7 @@ /* * linux/fs/ext2/acl.c * - * Copyright (C) 2001 by Andreas Gruenbacher, + * Copyright (C) 2001-2003 Andreas Gruenbacher, */ #include @@ -19,7 +19,7 @@ static struct posix_acl * ext2_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; - int n, count; + size_t n, count; struct posix_acl *acl; if (!value) @@ -85,7 +85,7 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) { ext2_acl_header *ext_acl; char *e; - int n; + size_t n; *size = ext2_acl_size(acl->a_count); ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) + @@ -124,16 +124,41 @@ fail: return ERR_PTR(-EINVAL); } +static inline struct posix_acl * +ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl) +{ + struct posix_acl *acl = EXT2_ACL_NOT_CACHED; + + spin_lock(&inode->i_lock); + if (*i_acl != EXT2_ACL_NOT_CACHED) + acl = posix_acl_dup(*i_acl); + spin_unlock(&inode->i_lock); + + return acl; +} + +static inline void +ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl, + struct posix_acl *acl) +{ + spin_lock(&inode->i_lock); + if (*i_acl != EXT2_ACL_NOT_CACHED) + posix_acl_release(*i_acl); + *i_acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); +} + /* - * inode->i_sem: down + * inode->i_sem: don't care */ static struct posix_acl * ext2_get_acl(struct inode *inode, int type) { + const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES); + struct ext2_inode_info *ei = EXT2_I(inode); int name_index; char *value; - struct posix_acl *acl, **p_acl; - const size_t size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES); + struct posix_acl *acl; int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) @@ -141,36 +166,45 @@ ext2_get_acl(struct inode *inode, int type) switch(type) { case ACL_TYPE_ACCESS: - p_acl = &EXT2_I(inode)->i_acl; + acl = ext2_iget_acl(inode, &ei->i_acl); + if (acl != EXT2_ACL_NOT_CACHED) + return acl; name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: - p_acl = &EXT2_I(inode)->i_default_acl; + acl = ext2_iget_acl(inode, &ei->i_default_acl); + if (acl != EXT2_ACL_NOT_CACHED) + return acl; name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } - if (*p_acl != EXT2_ACL_NOT_CACHED) - return posix_acl_dup(*p_acl); - value = kmalloc(size, GFP_KERNEL); + value = kmalloc(max_size, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); - retval = ext2_xattr_get(inode, name_index, "", value, size); - - if (retval == -ENODATA || retval == -ENOSYS) - *p_acl = acl = NULL; - else if (retval < 0) - acl = ERR_PTR(retval); - else { + retval = ext2_xattr_get(inode, name_index, "", value, max_size); + acl = ERR_PTR(retval); + if (retval >= 0) acl = ext2_acl_from_disk(value, retval); - if (!IS_ERR(acl)) - *p_acl = posix_acl_dup(acl); - } + else if (retval == -ENODATA || retval == -ENOSYS) + acl = NULL; kfree(value); + + if (!IS_ERR(acl)) { + switch(type) { + case ACL_TYPE_ACCESS: + ext2_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext2_iset_acl(inode, &ei->i_default_acl, acl); + break; + } + } return acl; } @@ -180,9 +214,9 @@ ext2_get_acl(struct inode *inode, int type) static int ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { + struct ext2_inode_info *ei = EXT2_I(inode); int name_index; void *value = NULL; - struct posix_acl **p_acl; size_t size; int error; @@ -194,7 +228,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) switch(type) { case ACL_TYPE_ACCESS: name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; - p_acl = &EXT2_I(inode)->i_acl; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); @@ -211,7 +244,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) case ACL_TYPE_DEFAULT: name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; - p_acl = &EXT2_I(inode)->i_default_acl; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; @@ -232,15 +264,26 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) if (value) kfree(value); if (!error) { - if (*p_acl && *p_acl != EXT2_ACL_NOT_CACHED) - posix_acl_release(*p_acl); - *p_acl = posix_acl_dup(acl); + switch(type) { + case ACL_TYPE_ACCESS: + ext2_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext2_iset_acl(inode, &ei->i_default_acl, acl); + break; + } } return error; } -static int -__ext2_permission(struct inode *inode, int mask, int lock) +/* + * Inode operation permission(). + * + * inode->i_sem: don't care + */ +int +ext2_permission(struct inode *inode, int mask, struct nameidata *nd) { int mode = inode->i_mode; @@ -254,29 +297,16 @@ __ext2_permission(struct inode *inode, int mask, int lock) if (current->fsuid == inode->i_uid) { mode >>= 6; } else if (test_opt(inode->i_sb, POSIX_ACL)) { - /* ACL can't contain additional permissions if - the ACL_MASK entry is 0 */ - if (!(mode & S_IRWXG)) - goto check_groups; - if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) { - struct posix_acl *acl; - - if (lock) { - down(&inode->i_sem); - acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); - up(&inode->i_sem); - } else - acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); + struct posix_acl *acl; - if (IS_ERR(acl)) - return PTR_ERR(acl); + /* The access ACL cannot grant access if the group class + permission bits don't contain all requested permissions. */ + if (((mode >> 3) & mask & S_IRWXO) != mask) + goto check_groups; + acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); + if (acl) { + int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); - if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) - return -EIO; - } - if (EXT2_I(inode)->i_acl) { - int error = posix_acl_permission(inode, - EXT2_I(inode)->i_acl, mask); if (error == -EACCES) goto check_capabilities; return error; @@ -303,32 +333,10 @@ check_capabilities: } /* - * Inode operation permission(). - * - * inode->i_sem: up - * BKL held [before 2.5.x] - */ -int -ext2_permission(struct inode *inode, int mask) -{ - return __ext2_permission(inode, mask, 1); -} - -/* - * Used internally if i_sem is already down. - */ -int -ext2_permission_locked(struct inode *inode, int mask) -{ - return __ext2_permission(inode, mask, 0); -} - -/* * Initialize the ACLs of a new inode. Called from ext2_new_inode. * * dir->i_sem: down * inode->i_sem: up (access to inode is still exclusive) - * BKL held [before 2.5.x] */ int ext2_init_acl(struct inode *inode, struct inode *dir) @@ -388,7 +396,6 @@ cleanup: * file mode. * * inode->i_sem: down - * BKL held [before 2.5.x] */ int ext2_acl_chmod(struct inode *inode) diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index 0cfbf4d1029..01937daf116 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h @@ -59,8 +59,7 @@ static inline int ext2_acl_count(size_t size) #define EXT2_ACL_NOT_CACHED ((void *)-1) /* acl.c */ -extern int ext2_permission (struct inode *, int); -extern int ext2_permission_locked (struct inode *, int); +extern int ext2_permission (struct inode *, int, struct nameidata *); extern int ext2_acl_chmod (struct inode *); extern int ext2_init_acl (struct inode *, struct inode *); diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 61069528984..67f704ab125 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -41,6 +41,16 @@ struct ext2_inode_info { __u32 i_prealloc_block; __u32 i_prealloc_count; __u32 i_dir_start_lookup; +#ifdef CONFIG_EXT2_FS_XATTR + /* + * Extended attributes can be read independently of the main file + * data. Taking i_sem even when reading would cause contention + * between readers of EAs and writers of regular file data, so + * instead we synchronize on xattr_sem when reading or changing + * EAs. + */ + struct rw_semaphore xattr_sem; +#endif #ifdef CONFIG_EXT2_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index af48364bcab..107ff87b720 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -489,17 +489,18 @@ found: return group; } -struct inode * ext2_new_inode(struct inode * dir, int mode) +struct inode *ext2_new_inode(struct inode *dir, int mode) { struct super_block *sb; struct buffer_head *bitmap_bh = NULL; struct buffer_head *bh2; int group, i; - ino_t ino; + ino_t ino = 0; struct inode * inode; - struct ext2_group_desc * desc; - struct ext2_super_block * es; + struct ext2_group_desc *gdp; + struct ext2_super_block *es; struct ext2_inode_info *ei; + struct ext2_sb_info *sbi; int err; sb = dir->i_sb; @@ -508,36 +509,62 @@ struct inode * ext2_new_inode(struct inode * dir, int mode) return ERR_PTR(-ENOMEM); ei = EXT2_I(inode); - es = EXT2_SB(sb)->s_es; + sbi = EXT2_SB(sb); + es = sbi->s_es; repeat: if (S_ISDIR(mode)) { - if (test_opt (sb, OLDALLOC)) + if (test_opt(sb, OLDALLOC)) group = find_group_dir(sb, dir); else group = find_group_orlov(sb, dir); } else group = find_group_other(sb, dir); - err = -ENOSPC; - if (group == -1) + if (group == -1) { + err = -ENOSPC; goto fail; + } - err = -EIO; - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) - goto fail2; - - i = ext2_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, - EXT2_INODES_PER_GROUP(sb)); - if (i >= EXT2_INODES_PER_GROUP(sb)) - goto bad_count; - if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), - i, (void *) bitmap_bh->b_data)) { + for (i = 0; i < sbi->s_groups_count; i++) { + gdp = ext2_get_group_desc(sb, group, &bh2); brelse(bitmap_bh); - ext2_release_inode(sb, group, S_ISDIR(mode)); - goto repeat; + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) { + err = -EIO; + goto fail2; + } + + i = ext2_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, + EXT2_INODES_PER_GROUP(sb)); + if (i >= EXT2_INODES_PER_GROUP(sb)) { + /* + * Rare race: find_group_xx() decided that there were + * free inodes in this group, but by the time we tried + * to allocate one, they're all gone. This can also + * occur because the counters which find_group_orlov() + * uses are approximate. So just go and search the + * next block group. + */ + if (++group == sbi->s_groups_count) + group = 0; + continue; + } + if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), + i, bitmap_bh->b_data)) { + brelse(bitmap_bh); + bitmap_bh = NULL; + ext2_release_inode(sb, group, S_ISDIR(mode)); + goto repeat; + } + goto got; } + /* + * Scanned all blockgroups. + */ + err = -ENOSPC; + goto fail2; +got: mark_buffer_dirty(bitmap_bh); if (sb->s_flags & MS_SYNCHRONOUS) sync_dirty_buffer(bitmap_bh); @@ -605,8 +632,9 @@ repeat: inode->i_generation = EXT2_SB(sb)->s_next_generation++; insert_inode_hash(inode); - if(DQUOT_ALLOC_INODE(inode)) { + if (DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); + err = -ENOSPC; goto fail3; } err = ext2_init_acl(inode, dir); @@ -631,21 +659,6 @@ fail: make_bad_inode(inode); iput(inode); return ERR_PTR(err); - -bad_count: - brelse(bitmap_bh); - ext2_error (sb, "ext2_new_inode", - "Free inodes count corrupted in group %d", - group); - /* Is it really ENOSPC? */ - err = -ENOSPC; - if (sb->s_flags & MS_RDONLY) - goto fail; - - desc = ext2_get_group_desc (sb, group, &bh2); - desc->bg_free_inodes_count = 0; - mark_buffer_dirty(bh2); - goto repeat; } unsigned long ext2_count_free_inodes (struct super_block * sb) diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 04489df5a2e..52fb0eb666b 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -66,7 +66,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) * Methods themselves. */ -static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; ino_t ino; @@ -120,7 +120,7 @@ struct dentry *ext2_get_parent(struct dentry *child) * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext2_create (struct inode * dir, struct dentry * dentry, int mode) +static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { struct inode * inode = ext2_new_inode (dir, mode); int err = PTR_ERR(inode); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index c4604187f18..14b8cca4727 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -177,6 +177,9 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { rwlock_init(&ei->i_meta_lock); +#ifdef CONFIG_EXT2_FS_XATTR + init_rwsem(&ei->xattr_sem); +#endif inode_init_once(&ei->vfs_inode); } } diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index ed2d1d4e667..f1334adc62e 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -1,7 +1,7 @@ /* * linux/fs/ext2/xattr.c * - * Copyright (C) 2001 by Andreas Gruenbacher, + * Copyright (C) 2001-2003 Andreas Gruenbacher * * Fix by Harrison Xing . * Extended attributes for symlinks and special files added per @@ -42,13 +42,12 @@ * * Locking strategy * ---------------- - * The VFS already holds the BKL and the inode->i_sem semaphore when any of - * the xattr inode operations are called, so we are guaranteed that only one - * processes accesses extended attributes of an inode at any time. - * - * For writing we also grab the ext2_xattr_sem semaphore. This ensures that - * only a single process is modifying an extended attribute block, even - * if the block is shared among inodes. + * EXT2_I(inode)->i_file_acl is protected by EXT2_I(inode)->xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count will change. Multiple writers to an EA block are synchronized + * by the bh lock. No more than a single bh lock is held at any time + * to avoid deadlocks. */ #include @@ -57,7 +56,7 @@ #include #include #include -#include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -83,8 +82,9 @@ EXPORT_SYMBOL(ext2_xattr_set); } while (0) # define ea_bdebug(bh, f...) do { \ char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%ld: ", \ - bdevname(bh->b_bdev, b), bh->b_blocknr); \ + printk(KERN_DEBUG "block %s:%lu: ", \ + bdevname(bh->b_bdev, b), \ + (unsigned long) bh->b_blocknr); \ printk(f); \ printk("\n"); \ } while (0) @@ -104,15 +104,6 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *, struct ext2_xattr_entry *); static struct mb_cache *ext2_xattr_cache; - -/* - * If a file system does not share extended attributes among inodes, - * we should not need the ext2_xattr_sem semaphore. However, the - * filesystem may still contain shared blocks, so we always take - * the lock. - */ - -static DECLARE_MUTEX(ext2_xattr_sem); static struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX]; static rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED; @@ -195,8 +186,7 @@ ext2_xattr_handler(int name_index) /* * Inode operation getxattr() * - * dentry->d_inode->i_sem down - * BKL held [before 2.5.x] + * dentry->d_inode->i_sem: don't care */ ssize_t ext2_getxattr(struct dentry *dentry, const char *name, @@ -214,8 +204,7 @@ ext2_getxattr(struct dentry *dentry, const char *name, /* * Inode operation listxattr() * - * dentry->d_inode->i_sem down - * BKL held [before 2.5.x] + * dentry->d_inode->i_sem: don't care */ ssize_t ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -226,8 +215,7 @@ ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) /* * Inode operation setxattr() * - * dentry->d_inode->i_sem down - * BKL held [before 2.5.x] + * dentry->d_inode->i_sem: down */ int ext2_setxattr(struct dentry *dentry, const char *name, @@ -247,8 +235,7 @@ ext2_setxattr(struct dentry *dentry, const char *name, /* * Inode operation removexattr() * - * dentry->d_inode->i_sem down - * BKL held [before 2.5.x] + * dentry->d_inode->i_sem: down */ int ext2_removexattr(struct dentry *dentry, const char *name) @@ -278,21 +265,24 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name, { struct buffer_head *bh = NULL; struct ext2_xattr_entry *entry; - unsigned int size; + size_t name_len, size; char *end; - int name_len, error; + int error; ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", name_index, name, buffer, (long)buffer_size); if (name == NULL) return -EINVAL; + down_read(&EXT2_I(inode)->xattr_sem); + error = -ENODATA; if (!EXT2_I(inode)->i_file_acl) - return -ENODATA; + goto cleanup; ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + error = -EIO; if (!bh) - return -EIO; + goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); end = bh->b_data + bh->b_size; @@ -357,6 +347,7 @@ found: cleanup: brelse(bh); + up_read(&EXT2_I(inode)->xattr_sem); return error; } @@ -376,19 +367,22 @@ ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; struct ext2_xattr_entry *entry; - unsigned int size = 0; + size_t size = 0; char *buf, *end; int error; ea_idebug(inode, "buffer=%p, buffer_size=%ld", buffer, (long)buffer_size); + down_read(&EXT2_I(inode)->xattr_sem); + error = 0; if (!EXT2_I(inode)->i_file_acl) - return 0; + goto cleanup; ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + error = -EIO; if (!bh) - return -EIO; + goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); end = bh->b_data + bh->b_size; @@ -441,6 +435,7 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", cleanup: brelse(bh); + up_read(&EXT2_I(inode)->xattr_sem); return error; } @@ -482,8 +477,8 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name, struct buffer_head *bh = NULL; struct ext2_xattr_header *header = NULL; struct ext2_xattr_entry *here, *last; - unsigned int name_len; - int min_offs = sb->s_blocksize, not_found = 1, free, error; + size_t name_len, free, min_offs = sb->s_blocksize; + int not_found = 1, error; char *end; /* @@ -512,8 +507,7 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name, name_len = strlen(name); if (name_len > 255 || value_len > sb->s_blocksize) return -ERANGE; - down(&ext2_xattr_sem); - + down_write(&EXT2_I(inode)->xattr_sem); if (EXT2_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); @@ -540,7 +534,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", if ((char *)next >= end) goto bad_block; if (!here->e_value_block && here->e_value_size) { - int offs = le16_to_cpu(here->e_value_offs); + size_t offs = le16_to_cpu(here->e_value_offs); if (offs < min_offs) min_offs = offs; } @@ -560,7 +554,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", if ((char *)next >= end) goto bad_block; if (!last->e_value_block && last->e_value_size) { - int offs = le16_to_cpu(last->e_value_offs); + size_t offs = le16_to_cpu(last->e_value_offs); if (offs < min_offs) min_offs = offs; } @@ -584,36 +578,38 @@ bad_block: ext2_error(sb, "ext2_xattr_set", error = 0; if (value == NULL) goto cleanup; - else - free -= EXT2_XATTR_LEN(name_len); } else { /* Request to create an existing attribute? */ error = -EEXIST; if (flags & XATTR_CREATE) goto cleanup; if (!here->e_value_block && here->e_value_size) { - unsigned int size = le32_to_cpu(here->e_value_size); + size_t size = le32_to_cpu(here->e_value_size); if (le16_to_cpu(here->e_value_offs) + size > sb->s_blocksize || size > sb->s_blocksize) goto bad_block; free += EXT2_XATTR_SIZE(size); } + free += EXT2_XATTR_LEN(name_len); } - free -= EXT2_XATTR_SIZE(value_len); error = -ENOSPC; - if (free < 0) + if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len)) goto cleanup; /* Here we know that we can set the new attribute. */ if (header) { + /* assert(header == HDR(bh)); */ + lock_buffer(bh); if (header->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "modifying in-place"); ext2_xattr_cache_remove(bh); + /* keep the buffer locked while modifying it. */ } else { int offset; + unlock_buffer(bh); ea_bdebug(bh, "cloning"); header = kmalloc(bh->b_size, GFP_KERNEL); error = -ENOMEM; @@ -638,23 +634,36 @@ bad_block: ext2_error(sb, "ext2_xattr_set", last = here = ENTRY(header+1); } + /* Iff we are modifying the block in-place, bh is locked here. */ + if (not_found) { /* Insert the new name. */ - int size = EXT2_XATTR_LEN(name_len); - int rest = (char *)last - (char *)here; + size_t size = EXT2_XATTR_LEN(name_len); + size_t rest = (char *)last - (char *)here; memmove((char *)here + size, here, rest); memset(here, 0, size); here->e_name_index = name_index; here->e_name_len = name_len; memcpy(here->e_name, name, name_len); } else { - /* Remove the old value. */ if (!here->e_value_block && here->e_value_size) { char *first_val = (char *)header + min_offs; - int offs = le16_to_cpu(here->e_value_offs); + size_t offs = le16_to_cpu(here->e_value_offs); char *val = (char *)header + offs; size_t size = EXT2_XATTR_SIZE( le32_to_cpu(here->e_value_size)); + + if (size == EXT2_XATTR_SIZE(value_len)) { + /* The old and the new value have the same + size. Just replace. */ + here->e_value_size = cpu_to_le32(value_len); + memset(val + size - EXT2_XATTR_PAD, 0, + EXT2_XATTR_PAD); /* Clear pad bytes. */ + memcpy(val, value, value_len); + goto skip_replace; + } + + /* Remove the old value. */ memmove(first_val + size, first_val, val - first_val); memset(first_val, 0, size); here->e_value_offs = 0; @@ -663,7 +672,7 @@ bad_block: ext2_error(sb, "ext2_xattr_set", /* Adjust all value offsets. */ last = ENTRY(header+1); while (!IS_LAST_ENTRY(last)) { - int o = le16_to_cpu(last->e_value_offs); + size_t o = le16_to_cpu(last->e_value_offs); if (!last->e_value_block && o < offs) last->e_value_offs = cpu_to_le16(o + size); @@ -671,19 +680,12 @@ bad_block: ext2_error(sb, "ext2_xattr_set", } } if (value == NULL) { - /* Remove this attribute. */ - if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) { - /* This block is now empty. */ - error = ext2_xattr_set2(inode, bh, NULL); - goto cleanup; - } else { - /* Remove the old name. */ - int size = EXT2_XATTR_LEN(name_len); - last = ENTRY((char *)last - size); - memmove(here, (char*)here + size, - (char*)last - (char*)here); - memset(last, 0, size); - } + /* Remove the old name. */ + size_t size = EXT2_XATTR_LEN(name_len); + last = ENTRY((char *)last - size); + memmove(here, (char*)here + size, + (char*)last - (char*)here); + memset(last, 0, size); } } @@ -700,15 +702,25 @@ bad_block: ext2_error(sb, "ext2_xattr_set", memcpy(val, value, value_len); } } - ext2_xattr_rehash(header, here); - error = ext2_xattr_set2(inode, bh, header); +skip_replace: + if (IS_LAST_ENTRY(ENTRY(header+1))) { + /* This block is now empty. */ + if (bh && header == HDR(bh)) + unlock_buffer(bh); /* we were modifying in-place. */ + error = ext2_xattr_set2(inode, bh, NULL); + } else { + ext2_xattr_rehash(header, here); + if (bh && header == HDR(bh)) + unlock_buffer(bh); /* we were modifying in-place. */ + error = ext2_xattr_set2(inode, bh, header); + } cleanup: brelse(bh); if (!(bh && header == HDR(bh))) kfree(header); - up(&ext2_xattr_sem); + up_write(&EXT2_I(inode)->xattr_sem); return error; } @@ -728,31 +740,37 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, new_bh = ext2_xattr_cache_find(inode, header); if (new_bh) { /* - * We found an identical block in the cache. - * The old block will be released after updating - * the inode. + * We found an identical block in the cache. The + * block returned is locked. The old block will + * be released after updating the inode. */ - ea_bdebug(new_bh, "%s block %ld", + ea_bdebug(new_bh, "%s block %lu", (old_bh == new_bh) ? "keeping" : "reusing", - new_bh->b_blocknr); + (unsigned long) new_bh->b_blocknr); error = -EDQUOT; - if (DQUOT_ALLOC_BLOCK(inode, 1)) + if (DQUOT_ALLOC_BLOCK(inode, 1)) { + unlock_buffer(new_bh); goto cleanup; + } HDR(new_bh)->h_refcount = cpu_to_le32( le32_to_cpu(HDR(new_bh)->h_refcount) + 1); ea_bdebug(new_bh, "refcount now=%d", le32_to_cpu(HDR(new_bh)->h_refcount)); + unlock_buffer(new_bh); } else if (old_bh && header == HDR(old_bh)) { - /* Keep this block. */ + /* Keep this block. No need to lock the block as we + don't need to change the reference count. */ new_bh = old_bh; get_bh(new_bh); ext2_xattr_cache_insert(new_bh); } else { /* We need to allocate a new block */ - int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) + - EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); + int goal = le32_to_cpu(EXT2_SB(sb)->s_es-> + s_first_data_block) + + EXT2_I(inode)->i_block_group * + EXT2_BLOCKS_PER_GROUP(sb); int block = ext2_new_block(inode, goal, 0, 0, &error); if (error) goto cleanup; @@ -794,12 +812,11 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, error = 0; if (old_bh && old_bh != new_bh) { /* - * If there was an old block, and we are not still using it, - * we now release the old block. - */ - unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); - - if (refcount == 1) { + * If there was an old block and we are no longer using it, + * release the old block. + */ + lock_buffer(old_bh); + if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { /* Free the old block. */ ea_bdebug(old_bh, "freeing"); ext2_free_blocks(inode, old_bh->b_blocknr, 1); @@ -809,12 +826,14 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, bforget(old_bh); } else { /* Decrement the refcount only. */ - refcount--; - HDR(old_bh)->h_refcount = cpu_to_le32(refcount); + HDR(old_bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(old_bh)->h_refcount) - 1); DQUOT_FREE_BLOCK(inode, 1); mark_buffer_dirty(old_bh); - ea_bdebug(old_bh, "refcount now=%d", refcount); + ea_bdebug(old_bh, "refcount now=%d", + le32_to_cpu(HDR(old_bh)->h_refcount)); } + unlock_buffer(old_bh); } cleanup: @@ -832,12 +851,11 @@ cleanup: void ext2_xattr_delete_inode(struct inode *inode) { - struct buffer_head *bh; + struct buffer_head *bh = NULL; + down_write(&EXT2_I(inode)->xattr_sem); if (!EXT2_I(inode)->i_file_acl) - return; - down(&ext2_xattr_sem); - + goto cleanup; bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); if (!bh) { ext2_error(inode->i_sb, "ext2_xattr_delete_inode", @@ -853,12 +871,12 @@ ext2_xattr_delete_inode(struct inode *inode) EXT2_I(inode)->i_file_acl); goto cleanup; } - ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + lock_buffer(bh); if (HDR(bh)->h_refcount == cpu_to_le32(1)) { ext2_xattr_cache_remove(bh); ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); + get_bh(bh); bforget(bh); - bh = NULL; } else { HDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(HDR(bh)->h_refcount) - 1); @@ -867,11 +885,13 @@ ext2_xattr_delete_inode(struct inode *inode) sync_dirty_buffer(bh); DQUOT_FREE_BLOCK(inode, 1); } + ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + unlock_buffer(bh); EXT2_I(inode)->i_file_acl = 0; cleanup: brelse(bh); - up(&ext2_xattr_sem); + up_write(&EXT2_I(inode)->xattr_sem); } /* @@ -964,8 +984,8 @@ ext2_xattr_cmp(struct ext2_xattr_header *header1, * * Find an identical extended attribute block. * - * Returns a pointer to the block found, or NULL if such a block was - * not found or an error occurred. + * Returns a locked buffer head to the block found, or NULL if such + * a block was not found or an error occurred. */ static struct buffer_head * ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) @@ -976,7 +996,8 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) if (!header->h_hash) return NULL; /* never share */ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); - ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_bdev, hash); + ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, + inode->i_sb->s_bdev, hash); while (ce) { struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); @@ -984,19 +1005,24 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) ext2_error(inode->i_sb, "ext2_xattr_cache_find", "inode %ld: block %ld read error", inode->i_ino, (unsigned long) ce->e_block); - } else if (le32_to_cpu(HDR(bh)->h_refcount) > - EXT2_XATTR_REFCOUNT_MAX) { - ea_idebug(inode, "block %ld refcount %d>%d", - (unsigned long) ce->e_block, - le32_to_cpu(HDR(bh)->h_refcount), - EXT2_XATTR_REFCOUNT_MAX); - } else if (!ext2_xattr_cmp(header, HDR(bh))) { - ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); - mb_cache_entry_release(ce); - return bh; + } else { + lock_buffer(bh); + if (le32_to_cpu(HDR(bh)->h_refcount) > + EXT2_XATTR_REFCOUNT_MAX) { + ea_idebug(inode, "block %ld refcount %d>%d", + (unsigned long) ce->e_block, + le32_to_cpu(HDR(bh)->h_refcount), + EXT2_XATTR_REFCOUNT_MAX); + } else if (!ext2_xattr_cmp(header, HDR(bh))) { + ea_bdebug(bh, "b_count=%d", + atomic_read(&(bh->b_count))); + mb_cache_entry_release(ce); + return bh; + } + unlock_buffer(bh); + brelse(bh); } - brelse(bh); - ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash); + ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); } return NULL; } diff --git a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c index 027beb89c7e..be155876106 100644 --- a/fs/ext2/xattr_user.c +++ b/fs/ext2/xattr_user.c @@ -11,10 +11,6 @@ #include "ext2.h" #include "xattr.h" -#ifdef CONFIG_EXT2_FS_POSIX_ACL -# include "acl.h" -#endif - #define XATTR_USER_PREFIX "user." static size_t @@ -44,11 +40,7 @@ ext2_xattr_user_get(struct inode *inode, const char *name, return -EINVAL; if (!test_opt(inode->i_sb, XATTR_USER)) return -EOPNOTSUPP; -#ifdef CONFIG_EXT2_FS_POSIX_ACL - error = ext2_permission_locked(inode, MAY_READ); -#else - error = permission(inode, MAY_READ); -#endif + error = permission(inode, MAY_READ, NULL); if (error) return error; @@ -68,11 +60,7 @@ ext2_xattr_user_set(struct inode *inode, const char *name, if ( !S_ISREG(inode->i_mode) && (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) return -EPERM; -#ifdef CONFIG_EXT2_FS_POSIX_ACL - error = ext2_permission_locked(inode, MAY_WRITE); -#else - error = permission(inode, MAY_WRITE); -#endif + error = permission(inode, MAY_WRITE, NULL); if (error) return error; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 9313430093c..2416e214280 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -1,7 +1,7 @@ /* * linux/fs/ext3/acl.c * - * Copyright (C) 2001 by Andreas Gruenbacher, + * Copyright (C) 2001-2003 Andreas Gruenbacher, */ #include @@ -20,7 +20,7 @@ static struct posix_acl * ext3_acl_from_disk(const void *value, size_t size) { const char *end = (char *)value + size; - int n, count; + size_t n, count; struct posix_acl *acl; if (!value) @@ -86,7 +86,7 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) { ext3_acl_header *ext_acl; char *e; - int n; + size_t n; *size = ext3_acl_size(acl->a_count); ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) + @@ -125,18 +125,43 @@ fail: return ERR_PTR(-EINVAL); } +static inline struct posix_acl * +ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) +{ + struct posix_acl *acl = EXT3_ACL_NOT_CACHED; + + spin_lock(&inode->i_lock); + if (*i_acl != EXT3_ACL_NOT_CACHED) + acl = posix_acl_dup(*i_acl); + spin_unlock(&inode->i_lock); + + return acl; +} + +static inline void +ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, + struct posix_acl *acl) +{ + spin_lock(&inode->i_lock); + if (*i_acl != EXT3_ACL_NOT_CACHED) + posix_acl_release(*i_acl); + *i_acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); +} + /* * Inode operation get_posix_acl(). * - * inode->i_sem: down + * inode->i_sem: don't care */ static struct posix_acl * ext3_get_acl(struct inode *inode, int type) { + const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES); + struct ext3_inode_info *ei = EXT3_I(inode); int name_index; char *value; - struct posix_acl *acl, **p_acl; - const size_t size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES); + struct posix_acl *acl; int retval; if (!test_opt(inode->i_sb, POSIX_ACL)) @@ -144,36 +169,45 @@ ext3_get_acl(struct inode *inode, int type) switch(type) { case ACL_TYPE_ACCESS: - p_acl = &EXT3_I(inode)->i_acl; + acl = ext3_iget_acl(inode, &ei->i_acl); + if (acl != EXT3_ACL_NOT_CACHED) + return acl; name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: - p_acl = &EXT3_I(inode)->i_default_acl; + acl = ext3_iget_acl(inode, &ei->i_default_acl); + if (acl != EXT3_ACL_NOT_CACHED) + return acl; name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } - if (*p_acl != EXT3_ACL_NOT_CACHED) - return posix_acl_dup(*p_acl); - value = kmalloc(size, GFP_KERNEL); + value = kmalloc(max_size, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); - retval = ext3_xattr_get(inode, name_index, "", value, size); - - if (retval == -ENODATA || retval == -ENOSYS) - *p_acl = acl = NULL; - else if (retval < 0) - acl = ERR_PTR(retval); - else { + retval = ext3_xattr_get(inode, name_index, "", value, max_size); + acl = ERR_PTR(retval); + if (retval > 0) acl = ext3_acl_from_disk(value, retval); - if (!IS_ERR(acl)) - *p_acl = posix_acl_dup(acl); - } + else if (retval == -ENODATA || retval == -ENOSYS) + acl = NULL; kfree(value); + + if (!IS_ERR(acl)) { + switch(type) { + case ACL_TYPE_ACCESS: + ext3_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext3_iset_acl(inode, &ei->i_default_acl, acl); + break; + } + } return acl; } @@ -186,9 +220,9 @@ static int ext3_set_acl(handle_t *handle, struct inode *inode, int type, struct posix_acl *acl) { + struct ext3_inode_info *ei = EXT3_I(inode); int name_index; void *value = NULL; - struct posix_acl **p_acl; size_t size; int error; @@ -198,7 +232,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, switch(type) { case ACL_TYPE_ACCESS: name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; - p_acl = &EXT3_I(inode)->i_acl; if (acl) { mode_t mode = inode->i_mode; error = posix_acl_equiv_mode(acl, &mode); @@ -215,7 +248,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, case ACL_TYPE_DEFAULT: name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; - p_acl = &EXT3_I(inode)->i_default_acl; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; @@ -231,20 +263,32 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, return (int)PTR_ERR(value); } - error = ext3_xattr_set_handle(handle, inode, name_index, "", value, size, 0); + error = ext3_xattr_set_handle(handle, inode, name_index, "", + value, size, 0); if (value) kfree(value); if (!error) { - if (*p_acl && *p_acl != EXT3_ACL_NOT_CACHED) - posix_acl_release(*p_acl); - *p_acl = posix_acl_dup(acl); + switch(type) { + case ACL_TYPE_ACCESS: + ext3_iset_acl(inode, &ei->i_acl, acl); + break; + + case ACL_TYPE_DEFAULT: + ext3_iset_acl(inode, &ei->i_default_acl, acl); + break; + } } return error; } -static int -__ext3_permission(struct inode *inode, int mask, int lock) +/* + * Inode operation permission(). + * + * inode->i_sem: don't care + */ +int +ext3_permission(struct inode *inode, int mask, struct nameidata *nd) { int mode = inode->i_mode; @@ -258,29 +302,16 @@ __ext3_permission(struct inode *inode, int mask, int lock) if (current->fsuid == inode->i_uid) { mode >>= 6; } else if (test_opt(inode->i_sb, POSIX_ACL)) { - /* ACL can't contain additional permissions if - the ACL_MASK entry is 0 */ - if (!(mode & S_IRWXG)) - goto check_groups; - if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) { - struct posix_acl *acl; - - if (lock) { - down(&inode->i_sem); - acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); - up(&inode->i_sem); - } else - acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + struct posix_acl *acl; - if (IS_ERR(acl)) - return PTR_ERR(acl); + /* The access ACL cannot grant access if the group class + permission bits don't contain all requested permissions. */ + if (((mode >> 3) & mask & S_IRWXO) != mask) + goto check_groups; + acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + if (acl) { + int error = posix_acl_permission(inode, acl, mask); posix_acl_release(acl); - if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) - return -EIO; - } - if (EXT3_I(inode)->i_acl) { - int error = posix_acl_permission(inode, - EXT3_I(inode)->i_acl, mask); if (error == -EACCES) goto check_capabilities; return error; @@ -307,26 +338,6 @@ check_capabilities: } /* - * Inode operation permission(). - * - * inode->i_sem: up - */ -int -ext3_permission(struct inode *inode, int mask) -{ - return __ext3_permission(inode, mask, 1); -} - -/* - * Used internally if i_sem is already down. - */ -int -ext3_permission_locked(struct inode *inode, int mask) -{ - return __ext3_permission(inode, mask, 0); -} - -/* * Initialize the ACLs of a new inode. Called from ext3_new_inode. * * dir->i_sem: down diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index e0962a6c24b..9d9d9d2e4a0 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h @@ -59,8 +59,7 @@ static inline int ext3_acl_count(size_t size) #define EXT3_ACL_NOT_CACHED ((void *)-1) /* acl.c */ -extern int ext3_permission (struct inode *, int); -extern int ext3_permission_locked (struct inode *, int); +extern int ext3_permission (struct inode *, int, struct nameidata *); extern int ext3_acl_chmod (struct inode *); extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index c2b0304b185..aa632b07899 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2290,68 +2290,72 @@ out_stop: ext3_journal_stop(handle); } -/* - * ext3_get_inode_loc returns with an extra refcount against the - * inode's underlying buffer_head on success. - */ - -int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) +static unsigned long ext3_get_inode_block(struct super_block *sb, + unsigned long ino, struct ext3_iloc *iloc) { - struct buffer_head *bh = 0; - unsigned long block; - unsigned long block_group; - unsigned long group_desc; - unsigned long desc; - unsigned long offset; + unsigned long desc, group_desc, block_group; + unsigned long offset, block; + struct buffer_head *bh; struct ext3_group_desc * gdp; - if ((inode->i_ino != EXT3_ROOT_INO && - inode->i_ino != EXT3_JOURNAL_INO && - inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || - inode->i_ino > le32_to_cpu( - EXT3_SB(inode->i_sb)->s_es->s_inodes_count)) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", - "bad inode number: %lu", inode->i_ino); - goto bad_inode; + if ((ino != EXT3_ROOT_INO && + ino != EXT3_JOURNAL_INO && + ino < EXT3_FIRST_INO(sb)) || + ino > le32_to_cpu( + EXT3_SB(sb)->s_es->s_inodes_count)) { + ext3_error (sb, "ext3_get_inode_block", + "bad inode number: %lu", ino); + return 0; } - block_group = (inode->i_ino - 1) / EXT3_INODES_PER_GROUP(inode->i_sb); - if (block_group >= EXT3_SB(inode->i_sb)->s_groups_count) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + if (block_group >= EXT3_SB(sb)->s_groups_count) { + ext3_error (sb, "ext3_get_inode_block", "group >= groups count"); - goto bad_inode; + return 0; } - group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(inode->i_sb); - desc = block_group & (EXT3_DESC_PER_BLOCK(inode->i_sb) - 1); - bh = EXT3_SB(inode->i_sb)->s_group_desc[group_desc]; + group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); + desc = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); + bh = EXT3_SB(sb)->s_group_desc[group_desc]; if (!bh) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", + ext3_error (sb, "ext3_get_inode_block", "Descriptor not loaded"); - goto bad_inode; + return 0; } gdp = (struct ext3_group_desc *) bh->b_data; /* * Figure out the offset within the block group inode table */ - offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)) * - EXT3_INODE_SIZE(inode->i_sb); + offset = ((ino - 1) % EXT3_INODES_PER_GROUP(sb)) * + EXT3_INODE_SIZE(sb); block = le32_to_cpu(gdp[desc].bg_inode_table) + - (offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb)); - if (!(bh = sb_bread(inode->i_sb, block))) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", - "unable to read inode block - " - "inode=%lu, block=%lu", inode->i_ino, block); - goto bad_inode; - } - offset &= (EXT3_BLOCK_SIZE(inode->i_sb) - 1); + (offset >> EXT3_BLOCK_SIZE_BITS(sb)); - iloc->bh = bh; - iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset); iloc->block_group = block_group; + iloc->offset = offset & (EXT3_BLOCK_SIZE(sb) - 1); + return block; +} - return 0; +/* + * ext3_get_inode_loc returns with an extra refcount against the + * inode's underlying buffer_head on success. + */ + +int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) +{ + unsigned long block; - bad_inode: + block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc); + if (block) { + struct buffer_head *bh = sb_bread(inode->i_sb, block); + if (bh) { + iloc->bh = bh; + return 0; + } + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "unable to read inode block - " + "inode=%lu, block=%lu", inode->i_ino, block); + } return -EIO; } @@ -2388,7 +2392,7 @@ void ext3_read_inode(struct inode * inode) if (ext3_get_inode_loc(inode, &iloc)) goto bad_inode; bh = iloc.bh; - raw_inode = iloc.raw_inode; + raw_inode = ext3_raw_inode(&iloc); inode->i_mode = le16_to_cpu(raw_inode->i_mode); inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); @@ -2454,11 +2458,9 @@ void ext3_read_inode(struct inode * inode) * even on big-endian machines: we do NOT byteswap the block numbers! */ for (block = 0; block < EXT3_N_BLOCKS; block++) - ei->i_data[block] = iloc.raw_inode->i_block[block]; + ei->i_data[block] = raw_inode->i_block[block]; INIT_LIST_HEAD(&ei->i_orphan); - brelse (iloc.bh); - if (S_ISREG(inode->i_mode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; @@ -2476,8 +2478,9 @@ void ext3_read_inode(struct inode * inode) } else { inode->i_op = &ext3_special_inode_operations; init_special_inode(inode, inode->i_mode, - le32_to_cpu(iloc.raw_inode->i_block[0])); + le32_to_cpu(raw_inode->i_block[0])); } + brelse (iloc.bh); ext3_set_inode_flags(inode); return; @@ -2497,7 +2500,7 @@ static int ext3_do_update_inode(handle_t *handle, struct inode *inode, struct ext3_iloc *iloc) { - struct ext3_inode *raw_inode = iloc->raw_inode; + struct ext3_inode *raw_inode = ext3_raw_inode(iloc); struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh = iloc->bh; int err = 0, rc, block; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index ae995cad505..74e53bcc480 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -970,7 +970,7 @@ errout: } #endif -static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode; struct ext3_dir_entry_2 * de; @@ -1623,7 +1623,8 @@ static int ext3_add_nondir(handle_t *handle, * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ext3_create (struct inode * dir, struct dentry * dentry, int mode) +static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) { handle_t *handle; struct inode * inode; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index d84dddf2959..04f3c6d04b7 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -519,6 +519,9 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { INIT_LIST_HEAD(&ei->i_orphan); +#ifdef CONFIG_EXT3_FS_XATTR + init_rwsem(&ei->xattr_sem); +#endif init_rwsem(&ei->truncate_sem); inode_init_once(&ei->vfs_inode); } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 066316459d8..6fbda077bdb 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -1,7 +1,7 @@ /* * linux/fs/ext3/xattr.c * - * Copyright (C) 2001 by Andreas Gruenbacher, + * Copyright (C) 2001-2003 Andreas Gruenbacher, * * Fix by Harrison Xing . * Ext3 code with a lot of help from Eric Jarman . @@ -43,13 +43,12 @@ * * Locking strategy * ---------------- - * The VFS holdsinode->i_sem semaphore when any of the xattr inode - * operations are called, so we are guaranteed that only one - * processes accesses extended attributes of an inode at any time. - * - * For writing we also grab the ext3_xattr_sem semaphore. This ensures that - * only a single process is modifying an extended attribute block, even - * if the block is shared among inodes. + * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem. + * EA blocks are only changed if they are exclusive to an inode, so + * holding xattr_sem also means that nothing but the EA block's reference + * count will change. Multiple writers to an EA block are synchronized + * by the bh lock. No more than a single bh lock is held at any time + * to avoid deadlocks. */ #include @@ -59,12 +58,10 @@ #include #include #include -#include +#include #include "xattr.h" #include "acl.h" -#define EXT3_EA_USER "user." - #define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) #define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) #define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) @@ -79,8 +76,9 @@ } while (0) # define ea_bdebug(bh, f...) do { \ char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%ld: ", \ - bdevname(bh->b_bdev, b), bh->b_blocknr); \ + printk(KERN_DEBUG "block %s:%lu: ", \ + bdevname(bh->b_bdev, b), \ + (unsigned long) bh->b_blocknr); \ printk(f); \ printk("\n"); \ } while (0) @@ -94,22 +92,14 @@ static int ext3_xattr_set_handle2(handle_t *, struct inode *, struct ext3_xattr_header *); static int ext3_xattr_cache_insert(struct buffer_head *); -static struct buffer_head *ext3_xattr_cache_find(struct inode *, - struct ext3_xattr_header *); +static struct buffer_head *ext3_xattr_cache_find(handle_t *, struct inode *, + struct ext3_xattr_header *, + int *); static void ext3_xattr_cache_remove(struct buffer_head *); static void ext3_xattr_rehash(struct ext3_xattr_header *, struct ext3_xattr_entry *); static struct mb_cache *ext3_xattr_cache; - -/* - * If a file system does not share extended attributes among inodes, - * we should not need the ext3_xattr_sem semaphore. However, the - * filesystem may still contain shared blocks, so we always take - * the lock. - */ - -static DECLARE_MUTEX(ext3_xattr_sem); static struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX]; static rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED; @@ -192,7 +182,7 @@ ext3_xattr_handler(int name_index) /* * Inode operation getxattr() * - * dentry->d_inode->i_sem down + * dentry->d_inode->i_sem: don't care */ ssize_t ext3_getxattr(struct dentry *dentry, const char *name, @@ -210,7 +200,7 @@ ext3_getxattr(struct dentry *dentry, const char *name, /* * Inode operation listxattr() * - * dentry->d_inode->i_sem down + * dentry->d_inode->i_sem: don't care */ ssize_t ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) @@ -221,7 +211,7 @@ ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) /* * Inode operation setxattr() * - * dentry->d_inode->i_sem down + * dentry->d_inode->i_sem: down */ int ext3_setxattr(struct dentry *dentry, const char *name, @@ -241,7 +231,7 @@ ext3_setxattr(struct dentry *dentry, const char *name, /* * Inode operation removexattr() * - * dentry->d_inode->i_sem down + * dentry->d_inode->i_sem: down */ int ext3_removexattr(struct dentry *dentry, const char *name) @@ -271,21 +261,24 @@ ext3_xattr_get(struct inode *inode, int name_index, const char *name, { struct buffer_head *bh = NULL; struct ext3_xattr_entry *entry; - unsigned int size; + size_t name_len, size; char *end; - int name_len, error; + int error; ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", name_index, name, buffer, (long)buffer_size); if (name == NULL) return -EINVAL; + down_read(&EXT3_I(inode)->xattr_sem); + error = -ENODATA; if (!EXT3_I(inode)->i_file_acl) - return -ENODATA; + goto cleanup; ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + error = -EIO; if (!bh) - return -EIO; + goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); end = bh->b_data + bh->b_size; @@ -350,6 +343,7 @@ found: cleanup: brelse(bh); + up_read(&EXT3_I(inode)->xattr_sem); return error; } @@ -369,19 +363,22 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) { struct buffer_head *bh = NULL; struct ext3_xattr_entry *entry; - unsigned int size = 0; + size_t size = 0; char *buf, *end; int error; ea_idebug(inode, "buffer=%p, buffer_size=%ld", buffer, (long)buffer_size); + down_read(&EXT3_I(inode)->xattr_sem); + error = 0; if (!EXT3_I(inode)->i_file_acl) - return 0; + goto cleanup; ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + error = -EIO; if (!bh) - return -EIO; + goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); end = bh->b_data + bh->b_size; @@ -434,6 +431,7 @@ bad_block: ext3_error(inode->i_sb, "ext3_xattr_list", cleanup: brelse(bh); + up_read(&EXT3_I(inode)->xattr_sem); return error; } @@ -449,11 +447,12 @@ static void ext3_xattr_update_super_block(handle_t *handle, return; lock_super(sb); - ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - EXT3_SB(sb)->s_es->s_feature_compat |= - cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); - sb->s_dirt = 1; - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { + EXT3_SB(sb)->s_es->s_feature_compat |= + cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); + sb->s_dirt = 1; + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + } unlock_super(sb); } @@ -478,8 +477,8 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, struct buffer_head *bh = NULL; struct ext3_xattr_header *header = NULL; struct ext3_xattr_entry *here, *last; - unsigned int name_len; - int min_offs = sb->s_blocksize, not_found = 1, free, error; + size_t name_len, free, min_offs = sb->s_blocksize; + int not_found = 1, error; char *end; /* @@ -508,8 +507,7 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, name_len = strlen(name); if (name_len > 255 || value_len > sb->s_blocksize) return -ERANGE; - down(&ext3_xattr_sem); - + down_write(&EXT3_I(inode)->xattr_sem); if (EXT3_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); @@ -536,7 +534,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", if ((char *)next >= end) goto bad_block; if (!here->e_value_block && here->e_value_size) { - int offs = le16_to_cpu(here->e_value_offs); + size_t offs = le16_to_cpu(here->e_value_offs); if (offs < min_offs) min_offs = offs; } @@ -556,7 +554,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", if ((char *)next >= end) goto bad_block; if (!last->e_value_block && last->e_value_size) { - int offs = le16_to_cpu(last->e_value_offs); + size_t offs = le16_to_cpu(last->e_value_offs); if (offs < min_offs) min_offs = offs; } @@ -580,39 +578,50 @@ bad_block: ext3_error(sb, "ext3_xattr_set", error = 0; if (value == NULL) goto cleanup; - else - free -= EXT3_XATTR_LEN(name_len); } else { /* Request to create an existing attribute? */ error = -EEXIST; if (flags & XATTR_CREATE) goto cleanup; if (!here->e_value_block && here->e_value_size) { - unsigned int size = le32_to_cpu(here->e_value_size); + size_t size = le32_to_cpu(here->e_value_size); if (le16_to_cpu(here->e_value_offs) + size > sb->s_blocksize || size > sb->s_blocksize) goto bad_block; free += EXT3_XATTR_SIZE(size); } + free += EXT3_XATTR_LEN(name_len); } - free -= EXT3_XATTR_SIZE(value_len); error = -ENOSPC; - if (free < 0) + if (free < EXT3_XATTR_LEN(name_len) + EXT3_XATTR_SIZE(value_len)) goto cleanup; /* Here we know that we can set the new attribute. */ if (header) { + int credits = 0; + + /* assert(header == HDR(bh)); */ + if (header->h_refcount != cpu_to_le32(1)) + goto skip_get_write_access; + /* ext3_journal_get_write_access() requires an unlocked bh, + which complicates things here. */ + error = ext3_journal_get_write_access_credits(handle, bh, + &credits); + if (error) + goto cleanup; + lock_buffer(bh); if (header->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "modifying in-place"); ext3_xattr_cache_remove(bh); - error = ext3_journal_get_write_access(handle, bh); - if (error) - goto cleanup; + /* keep the buffer locked while modifying it. */ } else { int offset; + unlock_buffer(bh); + journal_release_buffer(handle, bh, credits); + skip_get_write_access: ea_bdebug(bh, "cloning"); header = kmalloc(bh->b_size, GFP_KERNEL); error = -ENOMEM; @@ -637,23 +646,36 @@ bad_block: ext3_error(sb, "ext3_xattr_set", last = here = ENTRY(header+1); } + /* Iff we are modifying the block in-place, bh is locked here. */ + if (not_found) { /* Insert the new name. */ - int size = EXT3_XATTR_LEN(name_len); - int rest = (char *)last - (char *)here; + size_t size = EXT3_XATTR_LEN(name_len); + size_t rest = (char *)last - (char *)here; memmove((char *)here + size, here, rest); memset(here, 0, size); here->e_name_index = name_index; here->e_name_len = name_len; memcpy(here->e_name, name, name_len); } else { - /* Remove the old value. */ if (!here->e_value_block && here->e_value_size) { char *first_val = (char *)header + min_offs; - int offs = le16_to_cpu(here->e_value_offs); + size_t offs = le16_to_cpu(here->e_value_offs); char *val = (char *)header + offs; size_t size = EXT3_XATTR_SIZE( le32_to_cpu(here->e_value_size)); + + if (size == EXT3_XATTR_SIZE(value_len)) { + /* The old and the new value have the same + size. Just replace. */ + here->e_value_size = cpu_to_le32(value_len); + memset(val + size - EXT3_XATTR_PAD, 0, + EXT3_XATTR_PAD); /* Clear pad bytes. */ + memcpy(val, value, value_len); + goto skip_replace; + } + + /* Remove the old value. */ memmove(first_val + size, first_val, val - first_val); memset(first_val, 0, size); here->e_value_offs = 0; @@ -662,7 +684,7 @@ bad_block: ext3_error(sb, "ext3_xattr_set", /* Adjust all value offsets. */ last = ENTRY(header+1); while (!IS_LAST_ENTRY(last)) { - int o = le16_to_cpu(last->e_value_offs); + size_t o = le16_to_cpu(last->e_value_offs); if (!last->e_value_block && o < offs) last->e_value_offs = cpu_to_le16(o + size); @@ -670,20 +692,12 @@ bad_block: ext3_error(sb, "ext3_xattr_set", } } if (value == NULL) { - /* Remove this attribute. */ - if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) { - /* This block is now empty. */ - error = ext3_xattr_set_handle2(handle, inode, - bh, NULL); - goto cleanup; - } else { - /* Remove the old name. */ - int size = EXT3_XATTR_LEN(name_len); - last = ENTRY((char *)last - size); - memmove(here, (char*)here + size, - (char*)last - (char*)here); - memset(last, 0, size); - } + /* Remove the old name. */ + size_t size = EXT3_XATTR_LEN(name_len); + last = ENTRY((char *)last - size); + memmove(here, (char*)here + size, + (char*)last - (char*)here); + memset(last, 0, size); } } @@ -700,15 +714,25 @@ bad_block: ext3_error(sb, "ext3_xattr_set", memcpy(val, value, value_len); } } - ext3_xattr_rehash(header, here); - error = ext3_xattr_set_handle2(handle, inode, bh, header); +skip_replace: + if (IS_LAST_ENTRY(ENTRY(header+1))) { + /* This block is now empty. */ + if (bh && header == HDR(bh)) + unlock_buffer(bh); /* we were modifying in-place. */ + error = ext3_xattr_set_handle2(handle, inode, bh, NULL); + } else { + ext3_xattr_rehash(header, here); + if (bh && header == HDR(bh)) + unlock_buffer(bh); /* we were modifying in-place. */ + error = ext3_xattr_set_handle2(handle, inode, bh, header); + } cleanup: brelse(bh); if (!(bh && header == HDR(bh))) kfree(header); - up(&ext3_xattr_sem); + up_write(&EXT3_I(inode)->xattr_sem); return error; } @@ -723,33 +747,34 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, { struct super_block *sb = inode->i_sb; struct buffer_head *new_bh = NULL; - int error; + int credits = 0, error; if (header) { - new_bh = ext3_xattr_cache_find(inode, header); + new_bh = ext3_xattr_cache_find(handle, inode, header, &credits); if (new_bh) { /* - * We found an identical block in the cache. - * The old block will be released after updating - * the inode. + * We found an identical block in the cache. The + * block returned is locked. The old block will + * be released after updating the inode. */ - ea_bdebug(new_bh, "%s block %ld", + ea_bdebug(new_bh, "%s block %lu", (old_bh == new_bh) ? "keeping" : "reusing", - new_bh->b_blocknr); + (unsigned long) new_bh->b_blocknr); error = -EDQUOT; - if (DQUOT_ALLOC_BLOCK(inode, 1)) - goto cleanup; - - error = ext3_journal_get_write_access(handle, new_bh); - if (error) + if (DQUOT_ALLOC_BLOCK(inode, 1)) { + unlock_buffer(new_bh); + journal_release_buffer(handle, new_bh, credits); goto cleanup; + } HDR(new_bh)->h_refcount = cpu_to_le32( le32_to_cpu(HDR(new_bh)->h_refcount) + 1); ea_bdebug(new_bh, "refcount now=%d", le32_to_cpu(HDR(new_bh)->h_refcount)); + unlock_buffer(new_bh); } else if (old_bh && header == HDR(old_bh)) { - /* Keep this block. */ + /* Keep this block. No need to lock the block as we + * don't need to change the reference count. */ new_bh = old_bh; get_bh(new_bh); ext3_xattr_cache_insert(new_bh); @@ -759,7 +784,7 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, EXT3_SB(sb)->s_es->s_first_data_block) + EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb); - int block = ext3_new_block(handle, + int block = ext3_new_block(handle, inode, goal, 0, 0, &error); if (error) goto cleanup; @@ -800,15 +825,14 @@ getblk_failed: error = 0; if (old_bh && old_bh != new_bh) { /* - * If there was an old block, and we are not still using it, - * we now release the old block. + * If there was an old block, and we are no longer using it, + * release the old block. */ - unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); - error = ext3_journal_get_write_access(handle, old_bh); if (error) goto cleanup; - if (refcount == 1) { + lock_buffer(old_bh); + if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { /* Free the old block. */ ea_bdebug(old_bh, "freeing"); ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1); @@ -820,12 +844,14 @@ getblk_failed: ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr); } else { /* Decrement the refcount only. */ - refcount--; - HDR(old_bh)->h_refcount = cpu_to_le32(refcount); + HDR(old_bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(old_bh)->h_refcount) - 1); DQUOT_FREE_BLOCK(inode, 1); ext3_journal_dirty_metadata(handle, old_bh); - ea_bdebug(old_bh, "refcount now=%d", refcount); + ea_bdebug(old_bh, "refcount now=%d", + le32_to_cpu(HDR(old_bh)->h_refcount)); } + unlock_buffer(old_bh); } cleanup: @@ -869,12 +895,11 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, void ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) { - struct buffer_head *bh; + struct buffer_head *bh = NULL; + down_write(&EXT3_I(inode)->xattr_sem); if (!EXT3_I(inode)->i_file_acl) - return; - down(&ext3_xattr_sem); - + goto cleanup; bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); if (!bh) { ext3_error(inode->i_sb, "ext3_xattr_delete_inode", @@ -882,7 +907,6 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) EXT3_I(inode)->i_file_acl); goto cleanup; } - ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || HDR(bh)->h_blocks != cpu_to_le32(1)) { ext3_error(inode->i_sb, "ext3_xattr_delete_inode", @@ -890,13 +914,14 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) EXT3_I(inode)->i_file_acl); goto cleanup; } - ext3_journal_get_write_access(handle, bh); - ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + if (ext3_journal_get_write_access(handle, bh) != 0) + goto cleanup; + lock_buffer(bh); if (HDR(bh)->h_refcount == cpu_to_le32(1)) { ext3_xattr_cache_remove(bh); ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1); + get_bh(bh); ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl); - bh = NULL; } else { HDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(HDR(bh)->h_refcount) - 1); @@ -905,11 +930,13 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) handle->h_sync = 1; DQUOT_FREE_BLOCK(inode, 1); } + ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + unlock_buffer(bh); EXT3_I(inode)->i_file_acl = 0; cleanup: brelse(bh); - up(&ext3_xattr_sem); + up_write(&EXT3_I(inode)->xattr_sem); } /* @@ -1005,7 +1032,8 @@ ext3_xattr_cmp(struct ext3_xattr_header *header1, * not found or an error occurred. */ static struct buffer_head * -ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header) +ext3_xattr_cache_find(handle_t *handle, struct inode *inode, + struct ext3_xattr_header *header, int *credits) { __u32 hash = le32_to_cpu(header->h_hash); struct mb_cache_entry *ce; @@ -1013,7 +1041,8 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header) if (!header->h_hash) return NULL; /* never share */ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); - ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_bdev, hash); + ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, + inode->i_sb->s_bdev, hash); while (ce) { struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); @@ -1021,19 +1050,29 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header) ext3_error(inode->i_sb, "ext3_xattr_cache_find", "inode %ld: block %ld read error", inode->i_ino, (unsigned long) ce->e_block); - } else if (le32_to_cpu(HDR(bh)->h_refcount) > - EXT3_XATTR_REFCOUNT_MAX) { - ea_idebug(inode, "block %ld refcount %d>%d", - (unsigned long) ce->e_block, - le32_to_cpu(HDR(bh)->h_refcount), - EXT3_XATTR_REFCOUNT_MAX); - } else if (!ext3_xattr_cmp(header, HDR(bh))) { - ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); - mb_cache_entry_release(ce); - return bh; + } else { + /* ext3_journal_get_write_access() requires an unlocked + * bh, which complicates things here. */ + if (ext3_journal_get_write_access_credits(handle, bh, + credits) != 0) + return NULL; + lock_buffer(bh); + if (le32_to_cpu(HDR(bh)->h_refcount) > + EXT3_XATTR_REFCOUNT_MAX) { + ea_idebug(inode, "block %ld refcount %d>%d", + (unsigned long) ce->e_block, + le32_to_cpu(HDR(bh)->h_refcount), + EXT3_XATTR_REFCOUNT_MAX); + } else if (!ext3_xattr_cmp(header, HDR(bh))) { + mb_cache_entry_release(ce); + /* buffer will be unlocked by caller */ + return bh; + } + unlock_buffer(bh); + journal_release_buffer(handle, bh, *credits); + brelse(bh); } - brelse(bh); - ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash); + ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); } return NULL; } diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c index b93a74ded76..84877afff67 100644 --- a/fs/ext3/xattr_user.c +++ b/fs/ext3/xattr_user.c @@ -13,10 +13,6 @@ #include #include "xattr.h" -#ifdef CONFIG_EXT3_FS_POSIX_ACL -# include "acl.h" -#endif - #define XATTR_USER_PREFIX "user." static size_t @@ -46,11 +42,7 @@ ext3_xattr_user_get(struct inode *inode, const char *name, return -EINVAL; if (!test_opt(inode->i_sb, XATTR_USER)) return -EOPNOTSUPP; -#ifdef CONFIG_EXT3_FS_POSIX_ACL - error = ext3_permission_locked(inode, MAY_READ); -#else - error = permission(inode, MAY_READ); -#endif + error = permission(inode, MAY_READ, NULL); if (error) return error; @@ -70,11 +62,7 @@ ext3_xattr_user_set(struct inode *inode, const char *name, if ( !S_ISREG(inode->i_mode) && (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) return -EPERM; -#ifdef CONFIG_EXT3_FS_POSIX_ACL - error = ext3_permission_locked(inode, MAY_WRITE); -#else - error = permission(inode, MAY_WRITE); -#endif + error = permission(inode, MAY_WRITE, NULL); if (error) return error; diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c index 1f2c91676ee..9c7f99f7bd0 100644 --- a/fs/freevxfs/vxfs_lookup.c +++ b/fs/freevxfs/vxfs_lookup.c @@ -51,7 +51,7 @@ #define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_CACHE_SIZE / (sbp)->s_blocksize)) -static struct dentry * vxfs_lookup(struct inode *, struct dentry *); +static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *); static int vxfs_readdir(struct file *, void *, filldir_t); struct inode_operations vxfs_dir_inode_ops = { @@ -193,6 +193,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp) * vxfs_lookup - lookup pathname component * @dip: dir in which we lookup * @dp: dentry we lookup + * @nd: lookup nameidata * * Description: * vxfs_lookup tries to lookup the pathname component described @@ -203,7 +204,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp) * in the return pointer. */ static struct dentry * -vxfs_lookup(struct inode *dip, struct dentry *dp) +vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd) { struct inode *ip = NULL; ino_t ino; diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 92682b02ff1..8732f30faa2 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -516,6 +516,7 @@ int generic_osync_inode(struct inode *inode, int what) int need_write_inode_now = 0; int err2; + current->flags |= PF_SYNCWRITE; if (what & OSYNC_DATA) err = filemap_fdatawrite(inode->i_mapping); if (what & (OSYNC_METADATA|OSYNC_DATA)) { @@ -528,6 +529,7 @@ int generic_osync_inode(struct inode *inode, int what) if (!err) err = err2; } + current->flags &= ~PF_SYNCWRITE; spin_lock(&inode_lock); if ((inode->i_state & I_DIRTY) && diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index fe696c097d2..40df8a2b116 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -163,7 +163,7 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, * a directory and return a corresponding inode, given the inode for * the directory and the name (and its length) of the new file. */ -int hfs_create(struct inode * dir, struct dentry *dentry, int mode) +int hfs_create(struct inode * dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct hfs_cat_entry *entry = HFS_I(dir)->entry; struct hfs_cat_entry *new; diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c index 78da551630a..62bbda0a631 100644 --- a/fs/hfs/dir_cap.c +++ b/fs/hfs/dir_cap.c @@ -28,7 +28,7 @@ /*================ Forward declarations ================*/ -static struct dentry *cap_lookup(struct inode *, struct dentry *); +static struct dentry *cap_lookup(struct inode *, struct dentry *, struct nameidata *); static int cap_readdir(struct file *, void *, filldir_t); /*================ Global variables ================*/ @@ -95,7 +95,7 @@ struct inode_operations hfs_cap_rdir_inode_operations = { * inode corresponding to an entry in a directory, given the inode for * the directory and the name (and its length) of the entry. */ -static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { ino_t dtype; struct hfs_name cname; diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c index 36b7abd1eb6..ee2ccef70fe 100644 --- a/fs/hfs/dir_dbl.c +++ b/fs/hfs/dir_dbl.c @@ -24,9 +24,9 @@ /*================ Forward declarations ================*/ -static struct dentry *dbl_lookup(struct inode *, struct dentry *); +static struct dentry *dbl_lookup(struct inode *, struct dentry *, struct nameidata *); static int dbl_readdir(struct file *, void *, filldir_t); -static int dbl_create(struct inode *, struct dentry *, int); +static int dbl_create(struct inode *, struct dentry *, int, struct nameidata *); static int dbl_mkdir(struct inode *, struct dentry *, int); static int dbl_unlink(struct inode *, struct dentry *); static int dbl_rmdir(struct inode *, struct dentry *); @@ -108,7 +108,7 @@ static int is_hdr(struct inode *dir, const char *name, int len) * the inode for the directory and the name (and its length) of the * entry. */ -static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct hfs_name cname; struct hfs_cat_entry *entry; @@ -272,7 +272,7 @@ out: * the directory and the name (and its length) of the new file. */ static int dbl_create(struct inode * dir, struct dentry *dentry, - int mode) + int mode, struct nameidata *nd) { int error; @@ -280,7 +280,7 @@ static int dbl_create(struct inode * dir, struct dentry *dentry, if (is_hdr(dir, dentry->d_name.name, dentry->d_name.len)) { error = -EEXIST; } else { - error = hfs_create(dir, dentry, mode); + error = hfs_create(dir, dentry, mode, nd); } unlock_kernel(); return error; diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c index 5dda709ebdf..9688bcf7c14 100644 --- a/fs/hfs/dir_nat.c +++ b/fs/hfs/dir_nat.c @@ -30,7 +30,7 @@ /*================ Forward declarations ================*/ -static struct dentry *nat_lookup(struct inode *, struct dentry *); +static struct dentry *nat_lookup(struct inode *, struct dentry *, struct nameidata *); static int nat_readdir(struct file *, void *, filldir_t); static int nat_rmdir(struct inode *, struct dentry *); static int nat_hdr_unlink(struct inode *, struct dentry *); @@ -97,7 +97,7 @@ struct inode_operations hfs_nat_hdir_inode_operations = { * the inode corresponding to an entry in a directory, given the inode * for the directory and the name (and its length) of the entry. */ -static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { ino_t dtype; struct hfs_name cname; diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index f0a08037ab1..1b083b8b9a2 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -19,7 +19,7 @@ #include #include -static int hfs_revalidate_dentry(struct dentry *, int); +static int hfs_revalidate_dentry(struct dentry *, struct nameidata *); static int hfs_hash_dentry(struct dentry *, struct qstr *); static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static void hfs_dentry_iput(struct dentry *, struct inode *); @@ -90,7 +90,7 @@ static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode) iput(inode); } -static int hfs_revalidate_dentry(struct dentry *dentry, int flags) +static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; int diff; diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index 1c1e10c7282..9f0a0d3b238 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -198,7 +198,7 @@ out: * to tell read_inode to read fnode or not. */ -struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) +struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 91f880e8836..a4dc5bab6ef 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -216,7 +216,7 @@ void hpfs_set_dentry_operations(struct dentry *); int hpfs_dir_release(struct inode *, struct file *); loff_t hpfs_dir_lseek(struct file *, loff_t, int); int hpfs_readdir(struct file *, void *, filldir_t); -struct dentry *hpfs_lookup(struct inode *, struct dentry *); +struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *); /* dnode.c */ @@ -285,7 +285,7 @@ void hpfs_decide_conv(struct inode *, unsigned char *, unsigned); /* namei.c */ int hpfs_mkdir(struct inode *, struct dentry *, int); -int hpfs_create(struct inode *, struct dentry *, int); +int hpfs_create(struct inode *, struct dentry *, int, struct nameidata *); int hpfs_mknod(struct inode *, struct dentry *, int, dev_t); int hpfs_symlink(struct inode *, struct dentry *, const char *); int hpfs_unlink(struct inode *, struct dentry *); diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 8540f23659a..86697655724 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -106,7 +106,7 @@ bail: return -ENOSPC; } -int hpfs_create(struct inode *dir, struct dentry *dentry, int mode) +int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { const char *name = dentry->d_name.name; unsigned len = dentry->d_name.len; @@ -374,7 +374,7 @@ again: d_drop(dentry); spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1 || - permission(inode, MAY_WRITE) || + permission(inode, MAY_WRITE, NULL) || get_write_access(inode)) { spin_unlock(&dentry->d_lock); d_rehash(dentry); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index f0d2a2c6517..5888e05f81b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -462,7 +462,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return retval; } -static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode) +static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0); } diff --git a/fs/intermezzo/dcache.c b/fs/intermezzo/dcache.c index 2d3ebd2a761..91cd4d94b5e 100644 --- a/fs/intermezzo/dcache.c +++ b/fs/intermezzo/dcache.c @@ -50,7 +50,7 @@ kmem_cache_t * presto_dentry_slab; /* called when a cache lookup succeeds */ -static int presto_d_revalidate(struct dentry *de, int flag) +static int presto_d_revalidate(struct dentry *de, struct nameidata *nd) { struct inode *inode = de->d_inode; struct presto_file_set * root_fset; diff --git a/fs/intermezzo/dir.c b/fs/intermezzo/dir.c index 0446fb4dc17..7e646f9c221 100644 --- a/fs/intermezzo/dir.c +++ b/fs/intermezzo/dir.c @@ -81,7 +81,7 @@ static inline void presto_unlock(struct inode *dir) /* * these are initialized in super.c */ -extern int presto_permission(struct inode *inode, int mask); +extern int presto_permission(struct inode *inode, int mask, struct nameidata *nd); static int izo_authorized_uid = 0; int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id, @@ -239,7 +239,7 @@ struct dentry *presto_add_ilookup_dentry(struct dentry *parent, return de; } -struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { int rc = 0; struct dentry *de; @@ -286,7 +286,7 @@ struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry) (dir, dentry, ino, generation); is_ilookup = 1; } else - de = iops->lookup(dir, dentry); + de = iops->lookup(dir, dentry, nd); #if 0 } #endif @@ -412,7 +412,8 @@ int presto_prep(struct dentry *dentry, struct presto_cache **cache, return 0; } -static int presto_create(struct inode * dir, struct dentry * dentry, int mode) +static int presto_create(struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) { int error; struct presto_cache *cache; @@ -829,7 +830,7 @@ int presto_rename(struct inode *old_dir, struct dentry *old_dentry, * appropriate permission function. Thus we do not worry here about ACLs * or EAs. -SHP */ -int presto_permission(struct inode *inode, int mask) +int presto_permission(struct inode *inode, int mask, struct nameidata *nd) { unsigned short mode = inode->i_mode; struct presto_cache *cache; @@ -851,11 +852,11 @@ int presto_permission(struct inode *inode, int mask) if ( S_ISREG(mode) && fiops && fiops->permission ) { EXIT; - return fiops->permission(inode, mask); + return fiops->permission(inode, mask, nd); } if ( S_ISDIR(mode) && diops && diops->permission ) { EXIT; - return diops->permission(inode, mask); + return diops->permission(inode, mask, nd); } } @@ -866,7 +867,7 @@ int presto_permission(struct inode *inode, int mask) * the VFS permission function. */ inode->i_op->permission = NULL; - rc = permission(inode, mask); + rc = permission(inode, mask, nd); inode->i_op->permission = &presto_permission; EXIT; diff --git a/fs/intermezzo/file.c b/fs/intermezzo/file.c index 9f0b10422c4..a1efcbfaa2c 100644 --- a/fs/intermezzo/file.c +++ b/fs/intermezzo/file.c @@ -53,7 +53,7 @@ /* * these are initialized in super.c */ -extern int presto_permission(struct inode *inode, int mask); +extern int presto_permission(struct inode *inode, int mask, struct nameidata *nd); static int presto_open_upcall(int minor, struct dentry *de) diff --git a/fs/intermezzo/intermezzo_fs.h b/fs/intermezzo/intermezzo_fs.h index 8d2d33fcee0..3a7c60be8f2 100644 --- a/fs/intermezzo/intermezzo_fs.h +++ b/fs/intermezzo/intermezzo_fs.h @@ -370,7 +370,7 @@ extern int presto_ilookup_uid; # define PRESTO_ILOOKUP_MAGIC "...ino:" # define PRESTO_ILOOKUP_SEP ':' int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation); -struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry); +struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd); struct presto_dentry_data { int dd_count; /* how mnay dentries are using this dentry */ diff --git a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c index 5dd78cfed58..1cfa4c9a4b6 100644 --- a/fs/intermezzo/vfs.c +++ b/fs/intermezzo/vfs.c @@ -134,7 +134,7 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; - error = permission(dir,MAY_WRITE | MAY_EXEC); + error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); if (error) return error; if (IS_APPEND(dir)) @@ -158,7 +158,7 @@ static inline int may_create(struct inode *dir, struct dentry *child) { return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return permission(dir,MAY_WRITE | MAY_EXEC); + return permission(dir,MAY_WRITE | MAY_EXEC, NULL); } #ifdef PRESTO_DEBUG @@ -598,7 +598,7 @@ int presto_do_create(struct presto_file_set *fset, struct dentry *dir, } DQUOT_INIT(dir->d_inode); lock_kernel(); - error = iops->create(dir->d_inode, dentry, mode); + error = iops->create(dir->d_inode, dentry, mode, NULL); if (error) { EXIT; goto exit_lock; @@ -1840,7 +1840,7 @@ int presto_rename_dir(struct presto_file_set *fset, struct dentry *old_parent, * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = permission(old_dentry->d_inode, MAY_WRITE); + error = permission(old_dentry->d_inode, MAY_WRITE, NULL); } if (error) return error; diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 840cb90d489..8d525f6bf60 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -158,7 +158,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, return 0; } -struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry) +struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { unsigned long ino; struct inode *inode; diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 54f7862a371..2580162cad5 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -169,10 +169,23 @@ void journal_commit_transaction(journal_t *journal) * that multiple journal_get_write_access() calls to the same * buffer are perfectly permissable. */ - while (commit_transaction->t_reserved_list) { - jh = commit_transaction->t_reserved_list; - JBUFFER_TRACE(jh, "reserved, unused: refile"); - journal_refile_buffer(journal, jh); + { + int nr = 0; + while (commit_transaction->t_reserved_list) { + jh = commit_transaction->t_reserved_list; + JBUFFER_TRACE(jh, "reserved, unused: refile"); + journal_refile_buffer(journal, jh); + nr++; + } + if (nr) { + static int noisy; + + if (noisy < 10) { + noisy++; + printk("%s: freed %d reserved buffers\n", + __FUNCTION__, nr); + } + } } /* diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 54e16b97fda..12ad174e766 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -1168,37 +1168,24 @@ out: * journal_release_buffer: undo a get_write_access without any buffer * updates, if the update decided in the end that it didn't need access. * - * journal_get_write_access() can block, so it is quite possible for a - * journaling component to decide after the write access is returned - * that global state has changed and the update is no longer required. - * * The caller passes in the number of credits which should be put back for * this buffer (zero or one). + * + * We leave the buffer attached to t_reserved_list because even though this + * handle doesn't want it, some other concurrent handle may want to journal + * this buffer. If that handle is curently in between get_write_access() and + * journal_dirty_metadata() then it expects the buffer to be reserved. If + * we were to rip it off t_reserved_list here, the other handle will explode + * when journal_dirty_metadata is presented with a non-reserved buffer. + * + * If nobody really wants to journal this buffer then it will be thrown + * away at the start of commit. */ void journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits) { - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - struct journal_head *jh = bh2jh(bh); - - JBUFFER_TRACE(jh, "entry"); - - /* If the buffer is reserved but not modified by this - * transaction, then it is safe to release it. In all other - * cases, just leave the buffer as it is. */ - - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - if (jh->b_jlist == BJ_Reserved && jh->b_transaction == transaction && - !buffer_jbddirty(jh2bh(jh))) { - JBUFFER_TRACE(jh, "unused: refiling it"); - __journal_refile_buffer(jh); - } - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); + BUFFER_TRACE(bh, "entry"); handle->h_buffer_credits += credits; - JBUFFER_TRACE(jh, "exit"); } /** diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index e7e6d544277..94d3560caea 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -642,7 +642,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) /* Find a file in a directory. If the file exists, return its corresponding dentry. */ static struct dentry * -jffs_lookup(struct inode *dir, struct dentry *dentry) +jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct jffs_file *d; struct jffs_file *f; @@ -1273,7 +1273,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) * with d_instantiate(). */ static int -jffs_create(struct inode *dir, struct dentry *dentry, int mode) +jffs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { struct jffs_raw_inode raw_inode; struct jffs_control *c; diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 61d1b71bc20..9a2df58cb48 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -32,8 +32,8 @@ typedef dev_t mknod_arg_t; static int jffs2_readdir (struct file *, void *, filldir_t); -static int jffs2_create (struct inode *,struct dentry *,int); -static struct dentry *jffs2_lookup (struct inode *,struct dentry *); +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 *); @@ -73,7 +73,7 @@ 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) +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; @@ -175,7 +175,8 @@ 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) +static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, + struct nameidata *nd) { struct jffs2_raw_inode *ri; struct jffs2_inode_info *f, *dir_f; diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 758d370e641..a83ab660a0b 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -208,7 +208,7 @@ check_capabilities: return -EACCES; } -int jfs_permission(struct inode * inode, int mask) +int jfs_permission(struct inode * inode, int mask, struct nameidata *nd) { return __jfs_permission(inode, mask, 0); } diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index ae2db5088ba..3ce7feca4ba 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -259,7 +259,7 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks, else IREAD_UNLOCK(ip); } - return -rc; + return rc; } static int jfs_get_block(struct inode *ip, sector_t lblock, diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 179a3893a94..cfb44523197 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h @@ -25,7 +25,7 @@ struct posix_acl *jfs_get_acl(struct inode *, int); int jfs_set_acl(struct inode *, int, struct posix_acl *); int jfs_permission_have_sem(struct inode *, int); -int jfs_permission(struct inode *, int); +int jfs_permission(struct inode *, int, struct nameidata *); int jfs_init_acl(struct inode *, struct inode *); int jfs_setattr(struct dentry *, struct iattr *); diff --git a/fs/jfs/jfs_btree.h b/fs/jfs/jfs_btree.h index 5d1f3914823..53c0a6ea72d 100644 --- a/fs/jfs/jfs_btree.h +++ b/fs/jfs/jfs_btree.h @@ -81,7 +81,7 @@ struct btpage { } else {\ P = NULL;\ jfs_err("bread failed!");\ - RC = EIO;\ + RC = -EIO;\ }\ }\ } diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index f489662ade0..3edd2320d4d 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -188,8 +188,8 @@ signed char budtab[256] = { * * RETURN VALUES: * 0 - success - * ENOMEM - insufficient memory - * EIO - i/o error + * -ENOMEM - insufficient memory + * -EIO - i/o error */ int dbMount(struct inode *ipbmap) { @@ -204,7 +204,7 @@ int dbMount(struct inode *ipbmap) /* allocate memory for the in-memory bmap descriptor */ bmp = kmalloc(sizeof(struct bmap), GFP_KERNEL); if (bmp == NULL) - return (ENOMEM); + return -ENOMEM; /* read the on-disk bmap descriptor. */ mp = read_metapage(ipbmap, @@ -212,7 +212,7 @@ int dbMount(struct inode *ipbmap) PSIZE, 0); if (mp == NULL) { kfree(bmp); - return (EIO); + return -EIO; } /* copy the on-disk bmap descriptor to its in-memory version. */ @@ -267,7 +267,7 @@ int dbMount(struct inode *ipbmap) * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error */ int dbUnmount(struct inode *ipbmap, int mounterror) { @@ -315,7 +315,7 @@ int dbSync(struct inode *ipbmap) PSIZE, 0); if (mp == NULL) { jfs_err("dbSync: read_metapage failed!"); - return (EIO); + return -EIO; } /* copy the in-memory version of the bmap to the on-disk version */ dbmp_le = (struct dbmap *) mp->data; @@ -368,7 +368,7 @@ int dbSync(struct inode *ipbmap) * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error */ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) { @@ -399,7 +399,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { IREAD_UNLOCK(ipbmap); - return (EIO); + return -EIO; } dp = (struct dmap *) mp->data; @@ -448,7 +448,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error */ int dbUpdatePMap(struct inode *ipbmap, @@ -488,7 +488,7 @@ dbUpdatePMap(struct inode *ipbmap, mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) - return (EIO); + return -EIO; } dp = (struct dmap *) mp->data; @@ -721,8 +721,8 @@ unlock: * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error */ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) { @@ -742,7 +742,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) #ifdef _STILL_TO_PORT /* DASD limit check F226941 */ if (OVER_LIMIT(ip, nblocks)) - return ENOSPC; + return -ENOSPC; #endif /* _STILL_TO_PORT */ /* get the log2 number of blocks to be allocated. @@ -812,7 +812,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) /* get the buffer for the dmap containing the hint. */ - rc = EIO; + rc = -EIO; lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) @@ -824,7 +824,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * blocks beginning at the hint. */ if ((rc = dbAllocNext(bmp, dp, blkno, (int) nblocks)) - != ENOSPC) { + != -ENOSPC) { if (rc == 0) { *results = blkno; DBALLOC(bmp->db_DBmap, bmp->db_mapsize, @@ -853,7 +853,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) */ if ((rc = dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb, results)) - != ENOSPC) { + != -ENOSPC) { if (rc == 0) { DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks); @@ -868,7 +868,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * the same dmap as the hint. */ if ((rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results)) - != ENOSPC) { + != -ENOSPC) { if (rc == 0) { DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks); @@ -888,7 +888,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) */ IWRITE_LOCK(ipbmap); if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) - != ENOSPC) { + != -ENOSPC) { if (rc == 0) DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks); @@ -907,7 +907,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) /* Try to allocate within this allocation group. if that fails, try to * allocate anywhere in the map. */ - if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == ENOSPC) + if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == -ENOSPC) rc = dbAllocAny(bmp, nblocks, l2nb, results); if (rc == 0) { DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks); @@ -937,8 +937,8 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error */ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) { @@ -960,13 +960,13 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) */ if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) { IREAD_UNLOCK(ipbmap); - return EINVAL; + return -EINVAL; } if (nblocks > ((s64) 1 << bmp->db_maxfreebud)) { /* the free space is no longer available */ IREAD_UNLOCK(ipbmap); - return ENOSPC; + return -ENOSPC; } /* read in the dmap covering the extent */ @@ -974,7 +974,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { IREAD_UNLOCK(ipbmap); - return (EIO); + return -EIO; } dp = (struct dmap *) mp->data; @@ -1022,8 +1022,8 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error */ int dbReAlloc(struct inode *ip, @@ -1037,7 +1037,7 @@ dbReAlloc(struct inode *ip, *results = blkno; return (0); } else { - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); } @@ -1071,8 +1071,8 @@ dbReAlloc(struct inode *ip, * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error */ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) { @@ -1090,7 +1090,7 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) */ if (((rel_block = blkno & (sbi->nbperpage - 1))) && (rel_block + nblocks + addnblocks > sbi->nbperpage)) - return (ENOSPC); + return -ENOSPC; /* get the last block of the current allocation */ lastblkno = blkno + nblocks - 1; @@ -1117,7 +1117,7 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) if (addnblocks > BPERDMAP || extblkno >= bmp->db_mapsize || (extblkno & (bmp->db_agsize - 1)) == 0) { IREAD_UNLOCK(ipbmap); - return (ENOSPC); + return -ENOSPC; } /* get the buffer for the dmap containing the first block @@ -1127,7 +1127,7 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { IREAD_UNLOCK(ipbmap); - return (EIO); + return -EIO; } DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks); @@ -1148,7 +1148,7 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) } else { /* we were not successful */ release_metapage(mp); - assert(rc == ENOSPC || rc == EIO); + assert(rc == -ENOSPC || rc == -EIO); } return (rc); @@ -1169,8 +1169,8 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap) held on entry/exit; */ @@ -1196,13 +1196,13 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno, * this dmap. */ if (dbitno + nblocks > BPERDMAP) - return (ENOSPC); + return -ENOSPC; /* check if the starting leaf indicates that anything * is free. */ if (leaf[word] == NOFREE) - return (ENOSPC); + return -ENOSPC; /* check the dmaps words corresponding to block range to see * if the block range is free. not all bits of the first and @@ -1231,7 +1231,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno, */ mask = (ONES << (DBWORD - nb) >> wbitno); if ((mask & ~le32_to_cpu(dp->wmap[word])) != mask) - return (ENOSPC); + return -ENOSPC; word += 1; } else { @@ -1249,7 +1249,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno, /* does the leaf describe any free space ? */ if (leaf[word] < BUDMIN) - return (ENOSPC); + return -ENOSPC; /* determine the l2 number of bits provided * by this leaf. @@ -1295,8 +1295,8 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno, * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap) held on entry/exit; */ @@ -1344,7 +1344,7 @@ dbAllocNear(struct bmap * bmp, return (rc); } - return (ENOSPC); + return -ENOSPC; } @@ -1397,8 +1397,8 @@ dbAllocNear(struct bmap * bmp, * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * note: IWRITE_LOCK(ipmap) held on entry/exit; */ @@ -1441,8 +1441,8 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) if (bmp->db_agsize == BPERDMAP || bmp->db_agfree[agno] == bmp->db_agsize) { rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - /* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */ - if ((rc == ENOSPC) && + /* assert(!(rc == -ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */ + if ((rc == -ENOSPC) && (bmp->db_agfree[agno] == bmp->db_agsize)) { jfs_err("dbAllocAG: removed assert, but still need to " "debug here\nblkno = 0x%Lx, nblocks = 0x%Lx", @@ -1458,7 +1458,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, bmp->db_aglevel); mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) - return (EIO); + return -EIO; dcp = (struct dmapctl *) mp->data; budmin = dcp->budmin; @@ -1531,7 +1531,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) if ((rc = dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1, &blkno))) { - assert(rc != ENOSPC); + assert(rc != -ENOSPC); return (rc); } } @@ -1539,16 +1539,16 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) /* allocate the blocks. */ rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - assert(rc != ENOSPC); + assert(rc != -ENOSPC); return (rc); } /* no space in the allocation group. release the buffer and - * return ENOSPC. + * return -ENOSPC. */ release_metapage(mp); - return (ENOSPC); + return -ENOSPC; } @@ -1573,8 +1573,8 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -1595,7 +1595,7 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results) /* allocate the blocks. */ rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - assert(rc != ENOSPC); + assert(rc != -ENOSPC); return (rc); } @@ -1623,8 +1623,8 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -1648,7 +1648,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) lblkno = BLKTOCTL(b, bmp->db_l2nbperpage, lev); mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) - return (EIO); + return -EIO; dcp = (struct dmapctl *) mp->data; budmin = dcp->budmin; @@ -1667,7 +1667,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) */ if (rc) { assert(lev == level); - return (ENOSPC); + return -ENOSPC; } /* adjust the block number to reflect the location within @@ -1730,8 +1730,8 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -1751,7 +1751,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage); mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) - return (EIO); + return -EIO; dp = (struct dmap *) mp->data; /* try to allocate the blocks. @@ -1778,7 +1778,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) lblkno = BLKTODMAP(b, bmp->db_l2nbperpage); mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { - rc = EIO; + rc = -EIO; goto backout; } dp = (struct dmap *) mp->data; @@ -1875,8 +1875,8 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient disk resources - * EIO - i/o error + * -ENOSPC - insufficient disk resources + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or * IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit; @@ -1896,7 +1896,7 @@ dbAllocDmapLev(struct bmap * bmp, * returns the index of the leaf at which free space was found. */ if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx)) - return (ENOSPC); + return -ENOSPC; /* determine the block number within the file system corresponding * to the leaf at which free space was found. @@ -1941,7 +1941,7 @@ dbAllocDmapLev(struct bmap * bmp, * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -1996,7 +1996,7 @@ static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -2376,7 +2376,7 @@ static void dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno, * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */ @@ -2396,7 +2396,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, level); mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0); if (mp == NULL) - return (EIO); + return -EIO; dcp = (struct dmapctl *) mp->data; /* determine the leaf number corresponding to the block and @@ -2819,7 +2819,7 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval) * * RETURN VALUES: * 0 - success - * ENOSPC - insufficient free blocks. + * -ENOSPC - insufficient free blocks. */ static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx) { @@ -2829,7 +2829,7 @@ static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx) * sufficient free space. */ if (l2nb > tp->dmt_stree[ROOT]) - return (ENOSPC); + return -ENOSPC; /* sufficient free space available. now search down the tree * starting at the next level for the leftmost leaf that @@ -3073,7 +3073,7 @@ void fsDirty(void) * * RETURN VALUES: * 0 - success - * EIO - i/o error + * -EIO - i/o error */ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks) { @@ -3104,7 +3104,7 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks) mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { IREAD_UNLOCK(ipbmap); - return (EIO); + return -EIO; } dp = (struct dmap *) mp->data; @@ -3514,7 +3514,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) return 0; errout: - return EIO; + return -EIO; } diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 6c2c59fa1a7..ad67b8b7171 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -134,7 +134,7 @@ struct dtsplit { BT_PUTPAGE(MP);\ updateSuper((IP)->i_sb, FM_DIRTY);\ MP = NULL;\ - RC = EIO;\ + RC = -EIO;\ }\ }\ } @@ -404,7 +404,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0))) { jfs_warn("add_index: xtInsert failed!"); - return -1; + return -EPERM; } ip->i_size = PSIZE; ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage); @@ -412,7 +412,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) if ((mp = get_index_page(ip, 0)) == 0) { jfs_err("add_index: get_metapage failed!"); xtTruncate(tid, ip, 0, COMMIT_PWMAP); - return -1; + return -EPERM; } tlck = txLock(tid, ip, mp, tlckDATA); llck = (struct linelock *) & tlck->lock; @@ -447,7 +447,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) &xaddr, 0))) { jfs_warn("add_index: xtInsert failed!"); jfs_ip->next_index--; - return -1; + return -EPERM; } ip->i_size += PSIZE; ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage); @@ -461,7 +461,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) if (mp == 0) { jfs_err("add_index: get/read_metapage failed!"); - return -1; + return -EPERM; } lock_index(tid, ip, mp, index); @@ -588,7 +588,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS); if (ciKey.name == 0) { - rc = ENOMEM; + rc = -ENOMEM; goto dtSearch_Exit2; } @@ -674,7 +674,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, */ if (flag == JFS_CREATE) { *data = inumber; - rc = EEXIST; + rc = -EEXIST; goto out; } @@ -684,7 +684,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, if ((flag == JFS_REMOVE || flag == JFS_RENAME) && *data != inumber) { - rc = ESTALE; + rc = -ESTALE; goto out; } @@ -732,7 +732,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, */ if (flag == JFS_LOOKUP || flag == JFS_REMOVE || flag == JFS_RENAME) { - rc = ENOENT; + rc = -ENOENT; goto out; } @@ -770,7 +770,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, */ jfs_err("stack overrun in dtSearch!"); updateSuper(sb, FM_DIRTY); - rc = EIO; + rc = -EIO; goto out; } btstack->nsplit++; @@ -840,7 +840,7 @@ int dtInsert(tid_t tid, struct inode *ip, if (DO_INDEX(ip)) { if (JFS_IP(ip)->next_index == DIREND) { DT_PUTPAGE(mp); - return EMLINK; + return -EMLINK; } n = NDTLEAF(name->namlen); data.leaf.tid = tid; @@ -953,7 +953,7 @@ static int dtSplitUp(tid_t tid, GFP_NOFS); if (key.name == 0) { DT_PUTPAGE(smp); - rc = ENOMEM; + rc = -ENOMEM; goto dtSplitUp_Exit; } @@ -1579,7 +1579,7 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split, ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd)); - return 0; + return rc; } @@ -2628,7 +2628,7 @@ static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd, * descend down to leftmost child page */ if (p->header.flag & BT_LEAF) - return ESTALE; + return -ESTALE; /* get the leftmost entry */ stbl = DT_GETSTBL(p); @@ -2666,7 +2666,7 @@ static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd, bn = le64_to_cpu(p->header.next); else { DT_PUTPAGE(mp); - return ESTALE; + return -ESTALE; } /* unpin current page */ @@ -2908,7 +2908,7 @@ static void add_missing_indices(struct inode *inode, s64 bn) d->index = cpu_to_le32(add_index(tid, inode, bn, i)); if (dtlck->index >= dtlck->maxcnt) dtlck = (struct dt_lock *) txLinelock(dtlck); - lv = dtlck->lv; + lv = &dtlck->lv[dtlck->index]; lv->offset = stbl[i]; lv->length = 1; dtlck->index++; @@ -3068,7 +3068,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } if ((rc = dtReadFirst(ip, &btstack))) - return -rc; + return rc; DT_GETSEARCH(ip, btstack.top, bn, mp, p, index); } @@ -3268,7 +3268,7 @@ skip_one: DT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) { free_page(dirent_buf); - return -rc; + return rc; } } @@ -4434,8 +4434,8 @@ static void dtLinelockFreelist(dtpage_t * p, /* directory page */ * flag - JFS_RENAME * * RETURNS: - * ESTALE - If entry found does not match orig_ino passed in - * ENOENT - If no entry can be found to match key + * -ESTALE - If entry found does not match orig_ino passed in + * -ENOENT - If no entry can be found to match key * 0 - If successfully modified entry */ int dtModify(tid_t tid, struct inode *ip, diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 5ae34af50f4..2281f0aa6de 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -83,8 +83,8 @@ extern int jfs_commit_inode(struct inode *, int); * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ int extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) @@ -207,8 +207,8 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) { @@ -350,7 +350,7 @@ exit: * * RETURN VALUES: * 0 - success - * EIO - i/o error. + * -EIO - i/o error. */ int extHint(struct inode *ip, s64 offset, xad_t * xp) { @@ -421,8 +421,8 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ int extRecord(struct inode *ip, xad_t * xp) { @@ -436,7 +436,7 @@ int extRecord(struct inode *ip, xad_t * xp) rc = xtUpdate(0, ip, xp); up(&JFS_IP(ip)->commit_sem); - return (rc); + return rc; } @@ -453,8 +453,8 @@ int extRecord(struct inode *ip, xad_t * xp) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ int extFill(struct inode *ip, xad_t * xp) { @@ -505,8 +505,8 @@ int extFill(struct inode *ip, xad_t * xp) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ static int extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) @@ -535,7 +535,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) /* if something other than an out of space error, * stop and return this error. */ - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); /* decrease the allocation request size */ @@ -596,8 +596,8 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOSPC - insufficient disk resources. + * -EIO - i/o error. + * -ENOSPC - insufficient disk resources. */ static int extBrealloc(struct inode *ip, @@ -610,7 +610,7 @@ extBrealloc(struct inode *ip, *newblkno = blkno; return (0); } else { - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); } diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index 782dff63004..3bf500cf838 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2001 + * Copyright (c) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,9 @@ /* * file system option (superblock flag) */ +/* mount time flag to disable journaling to disk */ +#define JFS_NOINTEGRITY 0x00000010 + /* platform option (conditional compilation) */ #define JFS_AIX 0x80000000 /* AIX support */ /* POSIX name/directory support */ diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index f143116b079..11738b01ca8 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -121,8 +121,8 @@ static void DBGdiFree(struct inomap * imap, ino_t ino); * * RETURN VALUES: * 0 - success - * ENOMEM - insufficient free virtual memory. - * EIO - i/o error. + * -ENOMEM - insufficient free virtual memory. + * -EIO - i/o error. */ int diMount(struct inode *ipimap) { @@ -138,7 +138,7 @@ int diMount(struct inode *ipimap) imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL); if (imap == NULL) { jfs_err("diMount: kmalloc returned NULL!"); - return (ENOMEM); + return -ENOMEM; } /* read the on-disk inode map control structure. */ @@ -148,7 +148,7 @@ int diMount(struct inode *ipimap) PSIZE, 0); if (mp == NULL) { kfree(imap); - return (EIO); + return -EIO; } /* copy the on-disk version to the in-memory version. */ @@ -207,8 +207,8 @@ int diMount(struct inode *ipimap) * * RETURN VALUES: * 0 - success - * ENOMEM - insufficient free virtual memory. - * EIO - i/o error. + * -ENOMEM - insufficient free virtual memory. + * -EIO - i/o error. */ int diUnmount(struct inode *ipimap, int mounterror) { @@ -254,7 +254,7 @@ int diSync(struct inode *ipimap) PSIZE, 0); if (mp == NULL) { jfs_err("diSync: get_metapage failed!"); - return EIO; + return -EIO; } /* copy the in-memory version to the on-disk version */ @@ -320,8 +320,8 @@ int diSync(struct inode *ipimap) * * RETURN VALUES: * 0 - success - * EIO - i/o error. - * ENOMEM - insufficient memory + * -EIO - i/o error. + * -ENOMEM - insufficient memory * */ int diRead(struct inode *ip) @@ -366,7 +366,7 @@ int diRead(struct inode *ip) if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) || (addressPXD(&iagp->inoext[extno]) == 0)) { release_metapage(mp); - return ESTALE; + return -ESTALE; } /* get disk block number of the page within the inode extent @@ -401,7 +401,7 @@ int diRead(struct inode *ip) mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1); if (mp == 0) { jfs_err("diRead: read_metapage failed"); - return EIO; + return -EIO; } /* locate the the disk inode requested */ @@ -411,9 +411,9 @@ int diRead(struct inode *ip) if (ip->i_ino != le32_to_cpu(dp->di_number)) { jfs_err("diRead: i_ino != di_number"); updateSuper(ip->i_sb, FM_DIRTY); - rc = EIO; + rc = -EIO; } else if (le32_to_cpu(dp->di_nlink) == 0) - rc = ESTALE; + rc = -ESTALE; else /* copy the disk inode to the in-memory inode */ rc = copy_from_dinode(dp, ip); @@ -612,7 +612,7 @@ void diFreeSpecial(struct inode *ip) * * RETURN VALUES: * 0 - success - * EIO - i/o error. + * -EIO - i/o error. */ int diWrite(tid_t tid, struct inode *ip) { @@ -671,7 +671,7 @@ int diWrite(tid_t tid, struct inode *ip) retry: mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1); if (mp == 0) - return (EIO); + return -EIO; /* get the pointer to the disk inode */ dp = (struct dinode *) mp->data; @@ -885,7 +885,7 @@ int diWrite(tid_t tid, struct inode *ip) * * RETURN VALUES: * 0 - success - * EIO - i/o error. + * -EIO - i/o error. */ int diFree(struct inode *ip) { @@ -923,7 +923,7 @@ int diFree(struct inode *ip) (uint) inum, iagno, imap->im_nextiag); dump_mem("imap", imap, 32); updateSuper(ip->i_sb, FM_DIRTY); - return EIO; + return -EIO; } /* get the allocation group for this ino. @@ -972,7 +972,7 @@ int diFree(struct inode *ip) IREAD_UNLOCK(ipimap); AG_UNLOCK(imap, agno); updateSuper(ip->i_sb, FM_DIRTY); - return EIO; + return -EIO; } /* * inode extent still has some inodes or below low water mark: @@ -1362,8 +1362,8 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) { @@ -1471,7 +1471,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) rc = diAllocBit(imap, iagp, ino); IREAD_UNLOCK(ipimap); if (rc) { - assert(rc == EIO); + assert(rc == -EIO); } else { /* set the results of the allocation * and write the iag. @@ -1548,7 +1548,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) rc = diAllocBit(imap, iagp, ino); IREAD_UNLOCK(ipimap); if (rc) { - assert(rc == EIO); + assert(rc == -EIO); } else { /* set the results of the allocation * and write the iag. @@ -1584,10 +1584,10 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) * new extent, try to allocate the * disk inode from somewhere else. */ - if (rc == ENOSPC) + if (rc == -ENOSPC) break; - assert(rc == EIO); + assert(rc == -EIO); } else { /* set the results of the allocation * and write the iag. @@ -1626,7 +1626,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) AG_UNLOCK(imap, agno); - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); /* @@ -1662,8 +1662,8 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) @@ -1679,7 +1679,7 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) if (numfree > numinos) { jfs_err("diAllocAG: numfree > numinos"); updateSuper(ip->i_sb, FM_DIRTY); - return EIO; + return -EIO; } /* determine if we should allocate a new extent of free inodes @@ -1702,7 +1702,7 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * below to allocate a free and existing (already backed) * inode from the ag. */ - if ((rc = diAllocExt(imap, agno, ip)) != ENOSPC) + if ((rc = diAllocExt(imap, agno, ip)) != -ENOSPC) return (rc); } @@ -1733,8 +1733,8 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) @@ -1753,7 +1753,7 @@ diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) AG_UNLOCK(imap, ag); - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); } @@ -1766,13 +1766,13 @@ diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) AG_UNLOCK(imap, ag); - if (rc != ENOSPC) + if (rc != -ENOSPC) return (rc); } /* no free disk inodes. */ - return (ENOSPC); + return -ENOSPC; } @@ -1798,8 +1798,8 @@ diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) { @@ -1810,7 +1810,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) /* check if there are iags on the ag's free inode list. */ if ((iagno = imap->im_agctl[agno].inofree) < 0) - return (ENOSPC); + return -ENOSPC; /* obtain read lock on imap inode */ IREAD_LOCK(imap->im_ipimap); @@ -1832,7 +1832,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) jfs_err(" agno = %d, iagno = %d", agno, iagno); dump_mem("iag", iagp, 64); updateSuper(ip->i_sb, FM_DIRTY); - return EIO; + return -EIO; } /* scan the free inode summary map to find an extent @@ -1908,8 +1908,8 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) { @@ -2013,8 +2013,8 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino) { @@ -2153,8 +2153,8 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. */ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) { @@ -2267,7 +2267,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) */ dmp = get_metapage(ipimap, blkno + i, PSIZE, 1); if (dmp == NULL) { - rc = EIO; + rc = -EIO; goto error_out; } dp = (struct dinode *) dmp->data; @@ -2413,8 +2413,8 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) * * RETURN VALUES: * 0 - success. - * ENOSPC - insufficient disk resources. - * EIO - i/o error. + * -ENOSPC - insufficient disk resources. + * -EIO - i/o error. * * serialization: * AG lock held on entry/exit; @@ -2485,7 +2485,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* release the inode map lock */ IWRITE_UNLOCK(ipimap); - rc = ENOSPC; + rc = -ENOSPC; goto out; } @@ -2516,7 +2516,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* release the inode map lock */ IWRITE_UNLOCK(ipimap); - rc = EIO; + rc = -EIO; goto out; } iagp = (struct iag *) mp->data; @@ -2548,7 +2548,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* release the inode map lock */ IWRITE_UNLOCK(ipimap); - rc = EIO; + rc = -EIO; goto out; } @@ -2614,7 +2614,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* read the iag */ if ((rc = diIAGRead(imap, iagno, &mp))) { IREAD_UNLOCK(ipimap); - rc = EIO; + rc = -EIO; goto out; } iagp = (struct iag *) mp->data; @@ -2653,7 +2653,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) * * RETURN VALUES: * 0 - success. - * EIO - i/o error. + * -EIO - i/o error. */ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp) { @@ -2666,7 +2666,7 @@ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp) /* read the iag. */ *mpp = read_metapage(ipimap, blkno, PSIZE, 0); if (*mpp == NULL) { - return (EIO); + return -EIO; } return (0); @@ -2713,7 +2713,8 @@ static int diFindFree(u32 word, int start) * is_free - If TRUE indicates inode should be marked freed, otherwise * indicates inode should be marked allocated. * - * RETURNS: 0 for success + * RETURN VALUES: + * 0 for success */ int diUpdatePMap(struct inode *ipimap, @@ -3009,7 +3010,7 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno, * * RETURN VALUES: * 0 - success - * ENOMEM - insufficient memory + * -ENOMEM - insufficient memory */ static int copy_from_dinode(struct dinode * dip, struct inode *ip) { diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index cb94b67e8be..394c58e2202 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * Portions Copyright (c) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -130,32 +130,34 @@ enum cflags { * JFS-private superblock information. */ struct jfs_sb_info { - unsigned long mntflag; /* 4: aggregate attributes */ - struct inode *ipbmap; /* 4: block map inode */ - struct inode *ipaimap; /* 4: aggregate inode map inode */ - struct inode *ipaimap2; /* 4: secondary aimap inode */ - struct inode *ipimap; /* 4: aggregate inode map inode */ - struct jfs_log *log; /* 4: log */ - short bsize; /* 2: logical block size */ - short l2bsize; /* 2: log2 logical block size */ - short nbperpage; /* 2: blocks per page */ - short l2nbperpage; /* 2: log2 blocks per page */ - short l2niperblk; /* 2: log2 inodes per page */ - u32 logdev; /* 2: external log device */ + unsigned long mntflag; /* aggregate attributes */ + struct inode *ipbmap; /* block map inode */ + struct inode *ipaimap; /* aggregate inode map inode */ + struct inode *ipaimap2; /* secondary aimap inode */ + struct inode *ipimap; /* aggregate inode map inode */ + struct jfs_log *log; /* log */ + short bsize; /* logical block size */ + short l2bsize; /* log2 logical block size */ + short nbperpage; /* blocks per page */ + short l2nbperpage; /* log2 blocks per page */ + short l2niperblk; /* log2 inodes per page */ + u32 logdev; /* external log device */ uint aggregate; /* volume identifier in log record */ - pxd_t logpxd; /* 8: pxd describing log */ - pxd_t fsckpxd; /* 8: pxd describing fsck wkspc */ - pxd_t ait2; /* 8: pxd describing AIT copy */ - char uuid[16]; /* 16: 128-bit uuid for volume */ - char loguuid[16]; /* 16: 128-bit uuid for log */ + pxd_t logpxd; /* pxd describing log */ + pxd_t fsckpxd; /* pxd describing fsck wkspc */ + pxd_t ait2; /* pxd describing AIT copy */ + char uuid[16]; /* 128-bit uuid for volume */ + char loguuid[16]; /* 128-bit uuid for log */ /* Formerly in ipimap */ - uint gengen; /* 4: inode generation generator*/ - uint inostamp; /* 4: shows inode belongs to fileset*/ + uint gengen; /* inode generation generator*/ + uint inostamp; /* shows inode belongs to fileset*/ /* Formerly in ipbmap */ - struct bmap *bmap; /* 4: incore bmap descriptor */ - struct nls_table *nls_tab; /* 4: current codepage */ - uint state; /* 4: mount/recovery state */ + struct bmap *bmap; /* incore bmap descriptor */ + struct nls_table *nls_tab; /* current codepage */ + uint state; /* mount/recovery state */ + unsigned long flag; /* mount time flags */ + uint p_state; /* state prior to going no integrity */ }; static inline struct jfs_inode_info *JFS_IP(struct inode *inode) diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index bd3ca7cf8f3..b523f9a8c6c 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * Portions Copyright (c) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -667,7 +667,7 @@ int lmGroupCommit(struct jfs_log * log, struct tblock * tblk) /* group committed already ? */ if (tblk->flag & tblkGC_COMMITTED) { if (tblk->flag & tblkGC_ERROR) - rc = EIO; + rc = -EIO; LOGGC_UNLOCK(log); return rc; @@ -701,7 +701,7 @@ int lmGroupCommit(struct jfs_log * log, struct tblock * tblk) if (tblk->flag & tblkGC_COMMITTED) { if (tblk->flag & tblkGC_ERROR) - rc = EIO; + rc = -EIO; LOGGC_UNLOCK(log); return rc; @@ -717,7 +717,7 @@ int lmGroupCommit(struct jfs_log * log, struct tblock * tblk) /* removed from commit queue */ if (tblk->flag & tblkGC_ERROR) - rc = EIO; + rc = -EIO; LOGGC_UNLOCK(log); return rc; @@ -1068,7 +1068,7 @@ int lmLogOpen(struct super_block *sb, struct jfs_log ** logptr) struct jfs_log *log; if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) - return ENOMEM; + return -ENOMEM; memset(log, 0, sizeof(struct jfs_log)); init_waitqueue_head(&log->syncwait); @@ -1113,7 +1113,6 @@ int lmLogOpen(struct super_block *sb, struct jfs_log ** logptr) } if ((rc = bd_claim(bdev, log))) { - rc = -rc; goto close; } @@ -1169,7 +1168,7 @@ int lmLogOpen(struct super_block *sb, struct jfs_log ** logptr) * PARAMETER: log - log structure * * RETURN: 0 - if ok - * EINVAL - bad log magic number or superblock dirty + * -EINVAL - bad log magic number or superblock dirty * error returned from logwait() * * serialization: single first open thread @@ -1209,21 +1208,21 @@ int lmLogInit(struct jfs_log * log) if (logsuper->magic != cpu_to_le32(LOGMAGIC)) { jfs_warn("*** Log Format Error ! ***"); - rc = EINVAL; + rc = -EINVAL; goto errout20; } /* logredo() should have been run successfully. */ if (logsuper->state != cpu_to_le32(LOGREDONE)) { jfs_warn("*** Log Is Dirty ! ***"); - rc = EINVAL; + rc = -EINVAL; goto errout20; } /* initialize log inode from log superblock */ if (test_bit(log_INLINELOG,&log->flag)) { if (log->size != le32_to_cpu(logsuper->size)) { - rc = EINVAL; + rc = -EINVAL; goto errout20; } jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x", @@ -1242,6 +1241,15 @@ int lmLogInit(struct jfs_log * log) log->page = le32_to_cpu(logsuper->end) / LOGPSIZE; log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page); + /* check for disabled journaling to disk */ + if (JFS_SBI(log->sb)->flag & JFS_NOINTEGRITY) { + log->no_integrity = 1; + log->ni_page = log->page; + log->ni_eor = log->eor; + } + else + log->no_integrity = 0; + /* * initialize for log append write mode */ @@ -1525,6 +1533,14 @@ int lmLogShutdown(struct jfs_log * log) lrd.type = cpu_to_le16(LOG_SYNCPT); lrd.length = 0; lrd.log.syncpt.sync = 0; + + /* check for disabled journaling to disk */ + if (JFS_SBI(log->sb)->flag & JFS_NOINTEGRITY) { + log->no_integrity = 0; + log->page = log->ni_page; + log->eor = log->ni_eor; + } + lsn = lmWriteRecord(log, NULL, &lrd, NULL); bp = log->bp; lp = (struct logpage *) bp->l_ldata; @@ -1610,7 +1626,7 @@ static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate) if (i == MAX_ACTIVE) { jfs_warn("Somebody stomped on the journal!"); lbmFree(bpsuper); - return EIO; + return -EIO; } } @@ -1698,7 +1714,7 @@ static int lbmLogInit(struct jfs_log * log) error: lbmLogShutdown(log); - return (ENOMEM); + return -ENOMEM; } @@ -1986,10 +2002,18 @@ static void lbmStartIO(struct lbuf * bp) bio->bi_end_io = lbmIODone; bio->bi_private = bp; - submit_bio(WRITE, bio); - - INCREMENT(lmStat.submitted); - blk_run_queues(); + /* check if journaling to disk has been disabled */ + if (!log->no_integrity) { + submit_bio(WRITE, bio); + INCREMENT(lmStat.submitted); + blk_run_queues(); + } + else { + bio->bi_size = 0; + lbmIODone(bio, 0, 0); /* 2nd argument appears to not be used => 0 + * 3rd argument appears to not be used => 0 + */ + } } @@ -2007,7 +2031,7 @@ static int lbmIOWait(struct lbuf * bp, int flag) LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags); - rc = (bp->l_flag & lbmERROR) ? EIO : 0; + rc = (bp->l_flag & lbmERROR) ? -EIO : 0; if (flag & lbmFREE) lbmfree(bp); diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index 97983cb47c0..75d2a5fd607 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * Portions Copyright (c) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -417,6 +417,10 @@ struct jfs_log { struct lbuf *wqueue; /* 4: log pageout queue */ int count; /* 4: count */ char uuid[16]; /* 16: 128-bit uuid of log device */ + + int no_integrity; /* 3: flag to disable journaling to disk */ + int ni_page; /* 4: backup of page for nointegrity option */ + int ni_eor; /* 4: backup of eor for nointegrity option */ }; /* diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c index 3f2f6ac71f9..b9731129941 100644 --- a/fs/jfs/jfs_mount.c +++ b/fs/jfs/jfs_mount.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,11 +72,11 @@ static int logMOUNT(struct super_block *sb); * * PARAMETER: sb - super block * - * RETURN: EBUSY - device already mounted or open for write - * EBUSY - cvrdvp already mounted; - * EBUSY - mount table full - * ENOTDIR - cvrdvp not directory on a device mount - * ENXIO - device open failure + * RETURN: -EBUSY - device already mounted or open for write + * -EBUSY - cvrdvp already mounted; + * -EBUSY - mount table full + * -ENOTDIR- cvrdvp not directory on a device mount + * -ENXIO - device open failure */ int jfs_mount(struct super_block *sb) { @@ -98,7 +98,7 @@ int jfs_mount(struct super_block *sb) ipaimap = diReadSpecial(sb, AGGREGATE_I, 0); if (ipaimap == NULL) { jfs_err("jfs_mount: Faild to read AGGREGATE_I"); - rc = EIO; + rc = -EIO; goto errout20; } sbi->ipaimap = ipaimap; @@ -118,7 +118,7 @@ int jfs_mount(struct super_block *sb) */ ipbmap = diReadSpecial(sb, BMAP_I, 0); if (ipbmap == NULL) { - rc = EIO; + rc = -EIO; goto errout22; } @@ -149,7 +149,7 @@ int jfs_mount(struct super_block *sb) ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1); if (ipaimap2 == 0) { jfs_err("jfs_mount: Faild to read AGGREGATE_I"); - rc = EIO; + rc = -EIO; goto errout35; } sbi->ipaimap2 = ipaimap2; @@ -178,7 +178,7 @@ int jfs_mount(struct super_block *sb) if (ipimap == NULL) { jfs_err("jfs_mount: Failed to read FILESYSTEM_I"); /* open fileset secondary inode allocation map */ - rc = EIO; + rc = -EIO; goto errout40; } jfs_info("jfs_mount: ipimap:0x%p", ipimap); @@ -327,8 +327,7 @@ static int chkSuper(struct super_block *sb) /* validate fs signature */ if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) || j_sb->s_version > cpu_to_le32(JFS_VERSION)) { - //rc = EFORMAT; - rc = EINVAL; + rc = -EINVAL; goto out; } @@ -336,7 +335,7 @@ static int chkSuper(struct super_block *sb) #ifdef _JFS_4K if (bsize != PSIZE) { jfs_err("Currently only 4K block size supported!"); - rc = EINVAL; + rc = -EINVAL; goto out; } #endif /* _JFS_4K */ @@ -372,7 +371,7 @@ static int chkSuper(struct super_block *sb) if (j_sb->s_state != cpu_to_le32(FM_CLEAN) && !(sb->s_flags & MS_RDONLY)) { jfs_err("jfs_mount: Mount Failure: File System Dirty."); - rc = EINVAL; + rc = -EINVAL; goto out; } @@ -421,12 +420,20 @@ int updateSuper(struct super_block *sb, uint state) struct buffer_head *bh; int rc; - /* - * Only fsck can fix dirty state - */ - if (sbi->state == FM_DIRTY) + if (sbi->flag & JFS_NOINTEGRITY) { + if (state == FM_DIRTY) { + sbi->p_state = state; + return 0; + } else if (state == FM_MOUNT) { + sbi->p_state = sbi->state; + state = FM_DIRTY; + } else if (state == FM_CLEAN) { + state = sbi->p_state; + } else + jfs_err("updateSuper: bad state"); + } else if (sbi->state == FM_DIRTY) return 0; - + if ((rc = readSuper(sb, &bh))) return rc; diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index d7740cc3fb3..3549259736e 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * Portions Copyright (c) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -257,7 +257,7 @@ int txInit(void) size = sizeof(struct tblock) * nTxBlock; TxBlock = (struct tblock *) vmalloc(size); if (TxBlock == NULL) - return ENOMEM; + return -ENOMEM; for (k = 1; k < nTxBlock - 1; k++) { TxBlock[k].next = k + 1; @@ -283,7 +283,7 @@ int txInit(void) TxLock = (struct tlock *) vmalloc(size); if (TxLock == NULL) { vfree(TxBlock); - return ENOMEM; + return -ENOMEM; } /* initialize tlock table */ @@ -1098,7 +1098,7 @@ int txCommit(tid_t tid, /* transaction identifier */ struct inode **iplist, /* list of inode to commit */ int flag) { - int rc = 0, rc1 = 0; + int rc = 0; struct commit cd; struct jfs_log *log; struct tblock *tblk; @@ -1318,8 +1318,6 @@ int txCommit(tid_t tid, /* transaction identifier */ out: if (rc != 0) txAbortCommit(&cd, rc); - else - rc = rc1; TheEnd: jfs_info("txCommit: tid = %d, returning %d", tid, rc); @@ -2738,7 +2736,7 @@ void txLazyCommit(struct tblock * tblk) /* We must have gotten ahead of the user thread */ jfs_info("jfs_lazycommit: tblk 0x%p not unlocked", tblk); - schedule(); + yield(); } jfs_info("txLazyCommit: processing tblk 0x%p", tblk); diff --git a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c index 8a0ee0a0d84..118276e1a18 100644 --- a/fs/jfs/jfs_unicode.c +++ b/fs/jfs/jfs_unicode.c @@ -68,8 +68,7 @@ int jfs_strtoUCS(wchar_t * to, jfs_err("jfs_strtoUCS: char2uni returned %d.", charlen); jfs_err("charset = %s, char = 0x%x", codepage->charset, (unsigned char) *from); - to[i] = 0x003f; /* a question mark */ - charlen = 1; + return charlen; } } @@ -89,16 +88,21 @@ int get_UCSname(struct component_name * uniName, struct dentry *dentry, int length = dentry->d_name.len; if (length > JFS_NAME_MAX) - return ENAMETOOLONG; + return -ENAMETOOLONG; uniName->name = kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS); if (uniName->name == NULL) - return ENOSPC; + return -ENOSPC; uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name, length, nls_tab); + if (uniName->namlen < 0) { + kfree(uniName->name); + return uniName->namlen; + } + return 0; } diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index e018e97ec8c..7fb43461cdd 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -73,7 +73,7 @@ BT_PUTPAGE(MP);\ updateSuper((IP)->i_sb, FM_DIRTY);\ MP = NULL;\ - RC = EIO;\ + RC = -EIO;\ }\ }\ } @@ -814,7 +814,7 @@ int xtInsert(tid_t tid, /* transaction id */ /* This test must follow XT_GETSEARCH since mp must be valid if * we branch to out: */ if (cmp == 0) { - rc = EEXIST; + rc = -EEXIST; goto out; } @@ -1033,7 +1033,7 @@ xtSplitUp(tid_t tid, xtSplitRoot(tid, ip, split, &rmp) : xtSplitPage(tid, ip, split, &rmp, &rbn); if (rc) - return EIO; + return -EIO; XT_PUTPAGE(smp); @@ -1238,7 +1238,7 @@ xtSplitPage(tid_t tid, struct inode *ip, rbn = addressPXD(pxd); rmp = get_metapage(ip, rbn, PSIZE, 1); if (rmp == NULL) - return EIO; + return -EIO; jfs_info("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp); @@ -1485,7 +1485,7 @@ xtSplitRoot(tid_t tid, rbn = addressPXD(pxd); rmp = get_metapage(ip, rbn, PSIZE, 1); if (rmp == NULL) - return EIO; + return -EIO; jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp); @@ -2409,7 +2409,7 @@ int xtAppend(tid_t tid, /* transaction id */ XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); if (cmp == 0) { - rc = EEXIST; + rc = -EEXIST; goto out; } //insert: @@ -2557,7 +2557,7 @@ int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag) if (cmp) { /* unpin the leaf page */ XT_PUTPAGE(mp); - return ENOENT; + return -ENOENT; } /* @@ -2788,7 +2788,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ /* validate extent offset */ offset = xoff << JFS_SBI(ip->i_sb)->l2bsize; if (offset >= ip->i_size) - return ESTALE; /* stale extent */ + return -ESTALE; /* stale extent */ jfs_info("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx", xtype, (ulong) xoff, xlen, (ulong) oxaddr, (ulong) nxaddr); @@ -2804,7 +2804,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ return rc; if (cmp) { XT_PUTPAGE(pmp); - return ESTALE; + return -ESTALE; } /* retrieve search result */ @@ -2814,7 +2814,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ xad = &pp->xad[index]; if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) { XT_PUTPAGE(pmp); - return ESTALE; + return -ESTALE; } } else { /* (xtype == XTPAGE) */ @@ -2824,7 +2824,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ return rc; if (cmp) { XT_PUTPAGE(pmp); - return ESTALE; + return -ESTALE; } /* retrieve search result */ @@ -3127,7 +3127,7 @@ static int xtSearchNode(struct inode *ip, xad_t * xad, /* required XAD entry */ if (rc) return rc; if (p->header.flag & BT_LEAF) - return ESTALE; + return -ESTALE; lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART; @@ -3439,7 +3439,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) getPage: XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) - return -rc; + return rc; /* process entries backward from last index */ index = le16_to_cpu(p->header.nextindex) - 1; @@ -3667,7 +3667,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) bn = parent->bn; XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) - return -rc; + return rc; index = parent->index; @@ -3924,7 +3924,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1; rc = xtSearch(ip, xoff, &cmp, &btstack, 0); if (rc) - return -rc; + return rc; assert(cmp == 0); XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); } else { @@ -3941,7 +3941,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) getPage: XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) - return -rc; + return rc; /* process entries backward from last index */ index = le16_to_cpu(p->header.nextindex) - 1; @@ -3986,7 +3986,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) bn = parent->bn; XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) - return -rc; + return rc; index = parent->index; @@ -4311,7 +4311,7 @@ int xtGather(btree_t *t) bn = parent->bn; XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) - return EIO; + return -EIO; /* first subroot page which * covers all new allocated blocks diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index fd146752179..65196d513d9 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -54,11 +54,13 @@ s64 commitZeroLink(tid_t, struct inode *); * PARAMETER: dip - parent directory vnode * dentry - dentry of new file * mode - create mode (rwxrwxrwx). + * nd- nd struct * * RETURN: Errors from subroutines * */ -int jfs_create(struct inode *dip, struct dentry *dentry, int mode) +int jfs_create(struct inode *dip, struct dentry *dentry, int mode, + struct nameidata *nd) { int rc = 0; tid_t tid; /* transaction id */ @@ -85,7 +87,7 @@ int jfs_create(struct inode *dip, struct dentry *dentry, int mode) */ ip = ialloc(dip, mode); if (ip == NULL) { - rc = ENOSPC; + rc = -ENOSPC; goto out2; } @@ -158,8 +160,8 @@ int jfs_create(struct inode *dip, struct dentry *dentry, int mode) out1: - jfs_info("jfs_create: rc:%d", -rc); - return -rc; + jfs_info("jfs_create: rc:%d", rc); + return rc; } @@ -193,7 +195,7 @@ int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) /* link count overflow on parent directory ? */ if (dip->i_nlink == JFS_LINK_MAX) { - rc = EMLINK; + rc = -EMLINK; goto out1; } @@ -211,7 +213,7 @@ int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) */ ip = ialloc(dip, S_IFDIR | mode); if (ip == NULL) { - rc = ENOSPC; + rc = -ENOSPC; goto out2; } @@ -288,8 +290,8 @@ int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out1: - jfs_info("jfs_mkdir: rc:%d", -rc); - return -rc; + jfs_info("jfs_mkdir: rc:%d", rc); + return rc; } /* @@ -300,8 +302,8 @@ int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) * PARAMETER: dip - parent inode * dentry - child directory dentry * - * RETURN: EINVAL - if name is . or .. - * EINVAL - if . or .. exist but are invalid. + * RETURN: -EINVAL - if name is . or .. + * -EINVAL - if . or .. exist but are invalid. * errors from subroutines * * note: @@ -325,7 +327,7 @@ int jfs_rmdir(struct inode *dip, struct dentry *dentry) /* directory must be empty to be removed */ if (!dtEmpty(ip)) { - rc = ENOTEMPTY; + rc = -ENOTEMPTY; goto out; } @@ -411,7 +413,7 @@ int jfs_rmdir(struct inode *dip, struct dentry *dentry) out: jfs_info("jfs_rmdir: rc:%d", rc); - return -rc; + return rc; } /* @@ -497,7 +499,7 @@ int jfs_unlink(struct inode *dip, struct dentry *dentry) up(&JFS_IP(dip)->commit_sem); up(&JFS_IP(ip)->commit_sem); IWRITE_UNLOCK(ip); - rc = -new_size; /* We return -rc */ + rc = new_size; goto out1; } tblk = tid_to_tblock(tid); @@ -559,8 +561,8 @@ int jfs_unlink(struct inode *dip, struct dentry *dentry) out1: free_UCSname(&dname); out: - jfs_info("jfs_unlink: rc:%d", -rc); - return -rc; + jfs_info("jfs_unlink: rc:%d", rc); + return rc; } /* @@ -585,7 +587,7 @@ int jfs_unlink(struct inode *dip, struct dentry *dentry) * PARAMETERS: cd - pointer to commit data structure. * current inode is the one to truncate. * - * RETURN : Errors from subroutines + * RETURN: Errors from subroutines */ s64 commitZeroLink(tid_t tid, struct inode *ip) { @@ -775,7 +777,7 @@ int jfs_link(struct dentry *old_dentry, down(&JFS_IP(ip)->commit_sem); if (ip->i_nlink == JFS_LINK_MAX) { - rc = EMLINK; + rc = -EMLINK; goto out; } @@ -813,7 +815,7 @@ int jfs_link(struct dentry *old_dentry, up(&JFS_IP(ip)->commit_sem); jfs_info("jfs_link: rc:%d", rc); - return -rc; + return rc; } /* @@ -871,7 +873,7 @@ int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) */ ip = ialloc(dip, S_IFLNK | 0777); if (ip == NULL) { - rc = ENOSPC; + rc = -ENOSPC; goto out2; } @@ -963,7 +965,7 @@ int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) if (mp == NULL) { dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); - rc = EIO; + rc = -EIO; goto out3; } memcpy(mp->data, name, copy_size); @@ -981,7 +983,7 @@ int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) ip->i_blocks = LBLK2PBLK(sb, xlen); } else { dtDelete(tid, dip, &dname, &ino, JFS_REMOVE); - rc = ENOSPC; + rc = -ENOSPC; goto out3; } } @@ -1028,8 +1030,8 @@ int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) #endif out1: - jfs_info("jfs_symlink: rc:%d", -rc); - return -rc; + jfs_info("jfs_symlink: rc:%d", rc); + return rc; } @@ -1078,7 +1080,7 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, */ rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP); if (rc || (ino != old_ip->i_ino)) { - rc = ENOENT; + rc = -ENOENT; goto out3; } @@ -1088,26 +1090,26 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP); if (rc == 0) { if ((new_ip == 0) || (ino != new_ip->i_ino)) { - rc = ESTALE; + rc = -ESTALE; goto out3; } - } else if (rc != ENOENT) + } else if (rc != -ENOENT) goto out3; else if (new_ip) { /* no entry exists, but one was expected */ - rc = ESTALE; + rc = -ESTALE; goto out3; } if (S_ISDIR(old_ip->i_mode)) { if (new_ip) { if (!dtEmpty(new_ip)) { - rc = ENOTEMPTY; + rc = -ENOTEMPTY; goto out3; } } else if ((new_dir != old_dir) && (new_dir->i_nlink == JFS_LINK_MAX)) { - rc = EMLINK; + rc = -EMLINK; goto out3; } } else if (new_ip) @@ -1145,7 +1147,7 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* free block resources */ if ((new_size = commitZeroLink(tid, new_ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ - rc = -new_size; /* We return -rc */ + rc = new_size; goto out4; } tblk = tid_to_tblock(tid); @@ -1262,7 +1264,7 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, new_size = xtTruncate_pmap(tid, new_ip, new_size); if (new_size < 0) { txAbort(tid, 1); - rc = -new_size; /* We return -rc */ + rc = new_size; } else rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); txEnd(tid); @@ -1289,7 +1291,7 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } jfs_info("jfs_rename: returning %d", rc); - return -rc; + return rc; } @@ -1316,7 +1318,7 @@ int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) ip = ialloc(dir, mode); if (ip == NULL) { - rc = ENOSPC; + rc = -ENOSPC; goto out1; } @@ -1370,10 +1372,10 @@ int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) out: jfs_info("jfs_mknod: returning %d", rc); - return -rc; + return rc; } -static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry) +static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd) { struct btstack btstack; ino_t inum; @@ -1393,15 +1395,15 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry) else { if ((rc = get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab))) - return ERR_PTR(-rc); + return ERR_PTR(rc); rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP); free_UCSname(&key); - if (rc == ENOENT) { + if (rc == -ENOENT) { d_add(dentry, NULL); return ERR_PTR(0); } else if (rc) { jfs_err("jfs_lookup: dtSearch returned %d", rc); - return ERR_PTR(-rc); + return ERR_PTR(rc); } } diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index 982e628ae03..ba7cb585f54 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c @@ -182,7 +182,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) /* file system cannot be shrinked */ if (newFSSize < bmp->db_mapsize) { - rc = EINVAL; + rc = -EINVAL; goto out; } @@ -315,7 +315,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) if (mapSize > t64) { printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n", (long long) mapSize, (long long) t64); - rc = EIO; + rc = -EIO; goto error_out; } nblocks = min(t64 - mapSize, XSize); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 32a123400a7..d733da4a2b7 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-2003 * Portions Copyright (c) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify @@ -164,7 +164,8 @@ static void jfs_put_super(struct super_block *sb) kfree(sbi); } -static int parse_options(char *options, struct super_block *sb, s64 *newLVSize) +static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, + int *flag) { void *nls_map = NULL; char *this_char; @@ -180,7 +181,11 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize) continue; if ((value = strchr(this_char, '=')) != NULL) *value++ = 0; - if (!strcmp(this_char, "iocharset")) { + if (!strcmp(this_char, "integrity")) { + *flag &= ~JFS_NOINTEGRITY; + } else if (!strcmp(this_char, "nointegrity")) { + *flag |= JFS_NOINTEGRITY; + } else if (!strcmp(this_char, "iocharset")) { if (!value || !*value) goto needs_arg; if (nls_map) /* specified iocharset twice! */ @@ -231,8 +236,9 @@ int jfs_remount(struct super_block *sb, int *flags, char *data) { s64 newLVSize = 0; int rc = 0; + int flag = JFS_SBI(sb)->flag; - if (!parse_options(data, sb, &newLVSize)) { + if (!parse_options(data, sb, &newLVSize, &flag)) { return -EINVAL; } if (newLVSize) { @@ -246,10 +252,24 @@ int jfs_remount(struct super_block *sb, int *flags, char *data) return rc; } - if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) + if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { + JFS_SBI(sb)->flag = flag; return jfs_mount_rw(sb, 1); - else if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) - return jfs_umount_rw(sb); + } + if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) { + rc = jfs_umount_rw(sb); + JFS_SBI(sb)->flag = flag; + return rc; + } + if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY)) + if (!(sb->s_flags & MS_RDONLY)) { + rc = jfs_umount_rw(sb); + if (rc) + return rc; + JFS_SBI(sb)->flag = flag; + return jfs_mount_rw(sb, 1); + } + JFS_SBI(sb)->flag = flag; return 0; } @@ -260,6 +280,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; int rc; s64 newLVSize = 0; + int flag; jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags); @@ -269,10 +290,12 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) memset(sbi, 0, sizeof (struct jfs_sb_info)); sb->s_fs_info = sbi; - if (!parse_options((char *) data, sb, &newLVSize)) { + flag = 0; + if (!parse_options((char *) data, sb, &newLVSize, &flag)) { kfree(sbi); return -EINVAL; } + sbi->flag = flag; if (newLVSize) { printk(KERN_ERR "resize option for remount only\n"); @@ -519,7 +542,7 @@ free_metapage: metapage_exit(); free_slab: kmem_cache_destroy(jfs_inode_cachep); - return -rc; + return rc; } static void __exit exit_jfs_fs(void) diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index a9c455de618..37c17b39d01 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -183,7 +183,7 @@ static int ea_write_inline(struct inode *ip, struct jfs_ea_list *ealist, * used for an inline EA. */ if (!(ji->mode2 & INLINEEA) && !(ji->ea.flag & DXD_INLINE)) - return -1; + return -EPERM; DXDsize(ea, size); DXDlength(ea, 0); @@ -252,7 +252,7 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size, rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno); if (rc) - return -rc; + return rc; /* * Now have nblocks worth of storage to stuff into the FEALIST. @@ -513,7 +513,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed, &blkno); if (rc) - return -rc; + return rc; DXDlength(&ea_buf->new_ea, blocks_needed); DXDaddress(&ea_buf->new_ea, blkno); @@ -731,7 +731,7 @@ static int can_set_xattr(struct inode *inode, const char *name, #ifdef CONFIG_JFS_POSIX_ACL return jfs_permission_have_sem(inode, MAY_WRITE); #else - return permission(inode, MAY_WRITE); + return permission(inode, MAY_WRITE, NULL); #endif } @@ -893,7 +893,7 @@ static int can_get_xattr(struct inode *inode, const char *name) else return jfs_permission_have_sem(inode, MAY_READ); #else - return permission(inode, MAY_READ); + return permission(inode, MAY_READ, NULL); #endif } @@ -964,10 +964,17 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, size_t buf_size) { - return __jfs_getxattr(dentry->d_inode, name, data, buf_size); + int err; + + down(&dentry->d_inode->i_sem); + err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); + up(&dentry->d_inode->i_sem); + + return err; } -ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) +static ssize_t __jfs_listxattr(struct dentry * dentry, char *data, + size_t buf_size) { struct inode *inode = dentry->d_inode; char *buffer; @@ -1013,6 +1020,17 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) return size; } +ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size) +{ + int err; + + down(&dentry->d_inode->i_sem); + err = __jfs_listxattr(dentry, data, buf_size); + up(&dentry->d_inode->i_sem); + + return err; +} + int jfs_removexattr(struct dentry *dentry, const char *name) { return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE); diff --git a/fs/libfs.c b/fs/libfs.c index 62fb3c0fbc2..884da83cf77 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -29,7 +29,7 @@ int simple_statfs(struct super_block *sb, struct kstatfs *buf) * exist, we know it is negative. */ -struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry) +struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { d_add(dentry, NULL); return NULL; diff --git a/fs/minix/namei.c b/fs/minix/namei.c index d2b9ae264ce..2b9e6c64d25 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -54,7 +54,7 @@ struct dentry_operations minix_dentry_operations = { .d_hash = minix_hash, }; -static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode = NULL; ino_t ino; @@ -89,7 +89,8 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_ return error; } -static int minix_create(struct inode * dir, struct dentry *dentry, int mode) +static int minix_create(struct inode * dir, struct dentry *dentry, int mode, + struct nameidata *nd) { return minix_mknod(dir, dentry, mode, 0); } diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 31eb0d076c1..19c047776ec 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -193,7 +193,7 @@ static struct dentry_operations msdos_dentry_operations = { */ /***** Get inode using directory and name */ -struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry) +struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry, struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct inode *inode = NULL; @@ -261,7 +261,8 @@ static int msdos_add_entry(struct inode *dir, const char *name, */ /***** Create a file */ -int msdos_create(struct inode *dir,struct dentry *dentry,int mode) +int msdos_create(struct inode *dir,struct dentry *dentry,int mode, + struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct buffer_head *bh; diff --git a/fs/namei.c b/fs/namei.c index 8c847a1963f..4bd15bdcef4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -203,7 +203,7 @@ int vfs_permission(struct inode * inode, int mask) return -EACCES; } -int permission(struct inode * inode,int mask) +int permission(struct inode * inode,int mask, struct nameidata *nd) { int retval; int submask; @@ -212,7 +212,7 @@ int permission(struct inode * inode,int mask) submask = mask & ~MAY_APPEND; if (inode->i_op && inode->i_op->permission) - retval = inode->i_op->permission(inode, submask); + retval = inode->i_op->permission(inode, submask, nd); else retval = vfs_permission(inode, submask); if (retval) @@ -273,7 +273,7 @@ void path_release(struct nameidata *nd) * Internal lookup() using the new generic dcache. * SMP-safe */ -static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags) +static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd) { struct dentry * dentry = __d_lookup(parent, name); @@ -284,7 +284,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, dentry = d_lookup(parent, name); if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { - if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) { + if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) { dput(dentry); dentry = NULL; } @@ -336,7 +336,7 @@ ok: * make sure that nobody added the entry to the dcache in the meantime.. * SMP-safe */ -static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags) +static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd) { struct dentry * result; struct inode *dir = parent->d_inode; @@ -361,7 +361,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i struct dentry * dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { - result = dir->i_op->lookup(dir, dentry); + result = dir->i_op->lookup(dir, dentry, nd); if (result) dput(dentry); else @@ -377,7 +377,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i */ up(&dir->i_sem); if (result->d_op && result->d_op->d_revalidate) { - if (!result->d_op->d_revalidate(result, flags) && !d_invalidate(result)) { + if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { dput(result); result = ERR_PTR(-ENOENT); } @@ -524,7 +524,7 @@ struct path { * It _is_ time-critical. */ static int do_lookup(struct nameidata *nd, struct qstr *name, - struct path *path, int flags) + struct path *path) { struct vfsmount *mnt = nd->mnt; struct dentry *dentry = __d_lookup(nd->dentry, name); @@ -539,13 +539,13 @@ done: return 0; need_lookup: - dentry = real_lookup(nd->dentry, name, LOOKUP_CONTINUE); + dentry = real_lookup(nd->dentry, name, nd); if (IS_ERR(dentry)) goto fail; goto done; need_revalidate: - if (dentry->d_op->d_revalidate(dentry, flags)) + if (dentry->d_op->d_revalidate(dentry, nd)) goto done; if (d_invalidate(dentry)) goto done; @@ -588,7 +588,7 @@ int link_path_walk(const char * name, struct nameidata *nd) err = exec_permission_lite(inode); if (err == -EAGAIN) { - err = permission(inode, MAY_EXEC); + err = permission(inode, MAY_EXEC, nd); } if (err) break; @@ -638,8 +638,9 @@ int link_path_walk(const char * name, struct nameidata *nd) if (err < 0) break; } + nd->flags |= LOOKUP_CONTINUE; /* This does the actual lookups.. */ - err = do_lookup(nd, &this, &next, LOOKUP_CONTINUE); + err = do_lookup(nd, &this, &next); if (err) break; /* Check mountpoints.. */ @@ -681,6 +682,7 @@ int link_path_walk(const char * name, struct nameidata *nd) last_with_slashes: lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; last_component: + nd->flags &= ~LOOKUP_CONTINUE; if (lookup_flags & LOOKUP_PARENT) goto lookup_parent; if (this.name[0] == '.') switch (this.len) { @@ -700,7 +702,7 @@ last_component: if (err < 0) break; } - err = do_lookup(nd, &this, &next, 0); + err = do_lookup(nd, &this, &next); if (err) break; follow_mount(&next.mnt, &next.dentry); @@ -769,6 +771,7 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) */ nd_root.last_type = LAST_ROOT; nd_root.flags = nd->flags; + memcpy(&nd_root.intent, &nd->intent, sizeof(nd_root.intent)); read_lock(¤t->fs->lock); nd_root.mnt = mntget(current->fs->rootmnt); nd_root.dentry = dget(current->fs->root); @@ -866,14 +869,14 @@ int path_lookup(const char *name, unsigned int flags, struct nameidata *nd) * needs parent already locked. Doesn't follow mounts. * SMP-safe. */ -struct dentry * lookup_hash(struct qstr *name, struct dentry * base) +static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd) { struct dentry * dentry; struct inode *inode; int err; inode = base->d_inode; - err = permission(inode, MAY_EXEC); + err = permission(inode, MAY_EXEC, nd); dentry = ERR_PTR(err); if (err) goto out; @@ -889,13 +892,13 @@ struct dentry * lookup_hash(struct qstr *name, struct dentry * base) goto out; } - dentry = cached_lookup(base, name, 0); + dentry = cached_lookup(base, name, nd); if (!dentry) { struct dentry *new = d_alloc(base, name); dentry = ERR_PTR(-ENOMEM); if (!new) goto out; - dentry = inode->i_op->lookup(inode, new); + dentry = inode->i_op->lookup(inode, new, nd); if (!dentry) dentry = new; else @@ -905,6 +908,11 @@ out: return dentry; } +struct dentry * lookup_hash(struct qstr *name, struct dentry * base) +{ + return __lookup_hash(name, base, NULL); +} + /* SMP-safe */ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len) { @@ -988,12 +996,12 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ -static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) +static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir) { int error; if (!victim->d_inode || victim->d_parent->d_inode != dir) return -ENOENT; - error = permission(dir,MAY_WRITE | MAY_EXEC); + error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); if (error) return error; if (IS_APPEND(dir)) @@ -1023,12 +1031,14 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) * 3. We should have write and exec permissions on dir * 4. We can't do it if dir is immutable (done in permission()) */ -static inline int may_create(struct inode *dir, struct dentry *child) { +static inline int may_create(struct inode *dir, struct dentry *child, + struct nameidata *nd) +{ if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return permission(dir,MAY_WRITE | MAY_EXEC); + return permission(dir,MAY_WRITE | MAY_EXEC, nd); } /* @@ -1097,9 +1107,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) } } -int vfs_create(struct inode *dir, struct dentry *dentry, int mode) +int vfs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { - int error = may_create(dir, dentry); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -1112,7 +1123,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode) if (error) return error; DQUOT_INIT(dir); - error = dir->i_op->create(dir, dentry, mode); + error = dir->i_op->create(dir, dentry, mode, nd); if (!error) { inode_dir_notify(dir, DN_CREATE); security_inode_post_create(dir, dentry, mode); @@ -1135,7 +1146,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) return -EISDIR; - error = permission(inode, acc_mode); + error = permission(inode, acc_mode, nd); if (error) return error; @@ -1222,11 +1233,15 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) if (flag & O_APPEND) acc_mode |= MAY_APPEND; + /* Fill in the open() intent data */ + nd->intent.open.flags = flag; + nd->intent.open.create_mode = mode; + /* * The simplest case - just a plain lookup. */ if (!(flag & O_CREAT)) { - error = path_lookup(pathname, lookup_flags(flag), nd); + error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); if (error) return error; dentry = nd->dentry; @@ -1236,7 +1251,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) /* * Create - we need to know the parent. */ - error = path_lookup(pathname, LOOKUP_PARENT, nd); + error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd); if (error) return error; @@ -1250,8 +1265,9 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) goto exit; dir = nd->dentry; + nd->flags &= ~LOOKUP_PARENT; down(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); + dentry = __lookup_hash(&nd->last, nd->dentry, nd); do_last: error = PTR_ERR(dentry); @@ -1264,7 +1280,7 @@ do_last: if (!dentry->d_inode) { if (!IS_POSIXACL(dir->d_inode)) mode &= ~current->fs->umask; - error = vfs_create(dir->d_inode, dentry, mode); + error = vfs_create(dir->d_inode, dentry, mode, nd); up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -1328,6 +1344,7 @@ do_link: * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ + nd->flags |= LOOKUP_PARENT; error = security_inode_follow_link(dentry, nd); if (error) goto exit_dput; @@ -1336,6 +1353,7 @@ do_link: dput(dentry); if (error) return error; + nd->flags &= ~LOOKUP_PARENT; if (nd->last_type == LAST_BIND) { dentry = nd->dentry; goto ok; @@ -1354,7 +1372,7 @@ do_link: } dir = nd->dentry; down(&dir->d_inode->i_sem); - dentry = lookup_hash(&nd->last, nd->dentry); + dentry = __lookup_hash(&nd->last, nd->dentry, nd); putname(nd->last.name); goto do_last; } @@ -1368,6 +1386,7 @@ static struct dentry *lookup_create(struct nameidata *nd, int is_dir) dentry = ERR_PTR(-EEXIST); if (nd->last_type != LAST_NORM) goto fail; + nd->flags &= ~LOOKUP_PARENT; dentry = lookup_hash(&nd->last, nd->dentry); if (IS_ERR(dentry)) goto fail; @@ -1383,7 +1402,7 @@ fail: int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - int error = may_create(dir, dentry); + int error = may_create(dir, dentry, NULL); if (error) return error; @@ -1431,7 +1450,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, dev_t dev) if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(nd.dentry->d_inode,dentry,mode); + error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: error = vfs_mknod(nd.dentry->d_inode,dentry,mode,dev); @@ -1454,7 +1473,7 @@ out: int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - int error = may_create(dir, dentry); + int error = may_create(dir, dentry, NULL); if (error) return error; @@ -1700,7 +1719,7 @@ slashes: int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) { - int error = may_create(dir, dentry); + int error = may_create(dir, dentry, NULL); if (error) return error; @@ -1762,7 +1781,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (!inode) return -ENOENT; - error = may_create(dir, new_dentry); + error = may_create(dir, new_dentry, NULL); if (error) return error; @@ -1883,7 +1902,7 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = permission(old_dentry->d_inode, MAY_WRITE); + error = permission(old_dentry->d_inode, MAY_WRITE, NULL); if (error) return error; } @@ -1961,7 +1980,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, return error; if (!new_dentry->d_inode) - error = may_create(new_dir, new_dentry); + error = may_create(new_dir, new_dentry, NULL); else error = may_delete(new_dir, new_dentry, is_dir); if (error) diff --git a/fs/namespace.c b/fs/namespace.c index 61e5ec89136..a31cd95801c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -403,7 +403,7 @@ static int mount_is_safe(struct nameidata *nd) if (current->uid != nd->dentry->d_inode->i_uid) return -EPERM; } - if (permission(nd->dentry->d_inode, MAY_WRITE)) + if (permission(nd->dentry->d_inode, MAY_WRITE, nd)) return -EPERM; return 0; #endif diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index d4577dc7a55..f10460e559a 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -34,8 +34,8 @@ static void ncp_do_readdir(struct file *, void *, filldir_t, static int ncp_readdir(struct file *, void *, filldir_t); -static int ncp_create(struct inode *, struct dentry *, int); -static struct dentry *ncp_lookup(struct inode *, struct dentry *); +static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); +static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); static int ncp_unlink(struct inode *, struct dentry *); static int ncp_mkdir(struct inode *, struct dentry *, int); static int ncp_rmdir(struct inode *, struct dentry *); @@ -72,7 +72,7 @@ struct inode_operations ncp_dir_inode_operations = /* * Dentry operations routines */ -static int ncp_lookup_validate(struct dentry *, int); +static int ncp_lookup_validate(struct dentry *, struct nameidata *); static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); static int ncp_delete_dentry(struct dentry *); @@ -264,7 +264,7 @@ leave_me:; static int -__ncp_lookup_validate(struct dentry * dentry, int flags) +__ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) { struct ncp_server *server; struct dentry *parent; @@ -333,11 +333,11 @@ finished: } static int -ncp_lookup_validate(struct dentry * dentry, int flags) +ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) { int res; lock_kernel(); - res = __ncp_lookup_validate(dentry, flags); + res = __ncp_lookup_validate(dentry, nd); unlock_kernel(); return res; } @@ -797,7 +797,7 @@ out: return result; } -static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct ncp_server *server = NCP_SERVER(dir); struct inode *inode = NULL; @@ -942,7 +942,8 @@ out: return error; } -static int ncp_create(struct inode *dir, struct dentry *dentry, int mode) +static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { return ncp_create_new(dir, dentry, mode, 0, 0); } diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 3497f67be92..fb3e550a9ab 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -40,7 +40,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, switch (cmd) { case NCP_IOC_NCPREQUEST: - if ((permission(inode, MAY_WRITE) != 0) + if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; } @@ -99,7 +99,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { struct ncp_fs_info info; - if ((permission(inode, MAY_WRITE) != 0) + if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; } @@ -127,7 +127,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { struct ncp_fs_info_v2 info2; - if ((permission(inode, MAY_WRITE) != 0) + if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; } @@ -155,7 +155,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { unsigned long tmp = server->m.mounted_uid; - if ( (permission(inode, MAY_READ) != 0) + if ( (permission(inode, MAY_READ, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -169,7 +169,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { struct ncp_setroot_ioctl sr; - if ( (permission(inode, MAY_READ) != 0) + if ( (permission(inode, MAY_READ, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -249,7 +249,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, #ifdef CONFIG_NCPFS_PACKET_SIGNING case NCP_IOC_SIGN_INIT: - if ((permission(inode, MAY_WRITE) != 0) + if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -272,7 +272,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, return 0; case NCP_IOC_SIGN_WANTED: - if ( (permission(inode, MAY_READ) != 0) + if ( (permission(inode, MAY_READ, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -285,7 +285,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { int newstate; - if ( (permission(inode, MAY_WRITE) != 0) + if ( (permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -306,7 +306,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, #ifdef CONFIG_NCPFS_IOCTL_LOCKING case NCP_IOC_LOCKUNLOCK: - if ( (permission(inode, MAY_WRITE) != 0) + if ( (permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; @@ -608,7 +608,7 @@ outrel: } #endif /* CONFIG_NCPFS_NLS */ case NCP_IOC_SETDENTRYTTL: - if ((permission(inode, MAY_WRITE) != 0) && + if ((permission(inode, MAY_WRITE, NULL) != 0) && (current->uid != server->m.mounted_uid)) return -EACCES; { @@ -637,7 +637,7 @@ outrel: /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2, so we have this out of switch */ if (cmd == NCP_IOC_GETMOUNTUID) { - if ((permission(inode, MAY_READ) != 0) + if ((permission(inode, MAY_READ, NULL) != 0) && (current->uid != server->m.mounted_uid)) { return -EACCES; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d5499baadd1..fd894fa6584 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -37,10 +37,10 @@ static int nfs_opendir(struct inode *, struct file *); static int nfs_readdir(struct file *, void *, filldir_t); -static struct dentry *nfs_lookup(struct inode *, struct dentry *); +static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); static int nfs_cached_lookup(struct inode *, struct dentry *, struct nfs_fh *, struct nfs_fattr *); -static int nfs_create(struct inode *, struct dentry *, int); +static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); static int nfs_mkdir(struct inode *, struct dentry *, int); static int nfs_rmdir(struct inode *, struct dentry *); static int nfs_unlink(struct inode *, struct dentry *); @@ -78,13 +78,9 @@ struct inode_operations nfs_dir_inode_operations = { static int nfs_opendir(struct inode *inode, struct file *filp) { - struct nfs_server *server = NFS_SERVER(inode); int res = 0; lock_kernel(); - /* Do cto revalidation */ - if (!(server->flags & NFS_MOUNT_NOCTO)) - res = __nfs_revalidate_inode(server, inode); /* Call generic open code in order to cache credentials */ if (!res) res = nfs_open(inode, filp); @@ -485,9 +481,13 @@ static inline void nfs_renew_times(struct dentry * dentry) } static inline -int nfs_lookup_verify_inode(struct inode *inode) +int nfs_lookup_verify_inode(struct inode *inode, int isopen) { - return nfs_revalidate_inode(NFS_SERVER(inode), inode); + struct nfs_server *server = NFS_SERVER(inode); + + if (isopen && !(server->flags & NFS_MOUNT_NOCTO)) + return __nfs_revalidate_inode(server, inode); + return nfs_revalidate_inode(server, inode); } /* @@ -497,8 +497,17 @@ int nfs_lookup_verify_inode(struct inode *inode) * If parent mtime has changed, we revalidate, else we wait for a * period corresponding to the parent's attribute cache timeout value. */ -static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry) +static inline +int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) { + int ndflags = 0; + + if (nd) + ndflags = nd->flags; + /* Don't revalidate a negative dentry if we're creating a new file */ + if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE)) + return 0; if (!nfs_check_verifier(dir, dentry)) return 1; return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir)); @@ -515,7 +524,7 @@ static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry) * If the parent directory is seen to have changed, we throw out the * cached dentry and do a new lookup. */ -static int nfs_lookup_revalidate(struct dentry * dentry, int flags) +static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) { struct inode *dir; struct inode *inode; @@ -523,14 +532,18 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + int isopen = 0; parent = dget_parent(dentry); lock_kernel(); dir = parent->d_inode; inode = dentry->d_inode; + if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN)) + isopen = 1; + if (!inode) { - if (nfs_neg_need_reval(dir, dentry)) + if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; goto out_valid; } @@ -543,7 +556,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { - if (nfs_lookup_verify_inode(inode)) + if (nfs_lookup_verify_inode(inode, isopen)) goto out_bad; goto out_valid; } @@ -552,7 +565,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) if (!error) { if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) goto out_bad; - if (nfs_lookup_verify_inode(inode)) + if (nfs_lookup_verify_inode(inode, isopen)) goto out_bad; goto out_valid_renew; } @@ -630,7 +643,17 @@ struct dentry_operations nfs_dentry_operations = { .d_iput = nfs_dentry_iput, }; -static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry) +static inline +int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) +{ + if (NFS_PROTO(dir)->version == 2) + return 0; + if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE)) + return 0; + return (nd->intent.open.flags & O_EXCL) != 0; +} + +static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { struct inode *inode = NULL; int error; @@ -647,6 +670,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry) error = -ENOMEM; dentry->d_op = &nfs_dentry_operations; + /* If we're doing an exclusive create, optimize away the lookup */ + if (nfs_is_exclusive_create(dir, nd)) + return NULL; + lock_kernel(); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); if (!error) { @@ -787,12 +814,14 @@ out_err: * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */ -static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) +static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { struct iattr attr; struct nfs_fattr fattr; struct nfs_fh fhandle; int error; + int open_flags = 0; dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); @@ -800,6 +829,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) attr.ia_mode = mode; attr.ia_valid = ATTR_MODE; + if (nd && (nd->flags & LOOKUP_CREATE)) + open_flags = nd->intent.open.flags; + /* * The 0 argument passed into the create function should one day * contain the O_EXCL flag if requested. This allows NFSv3 to @@ -809,7 +841,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode) lock_kernel(); nfs_zap_caches(dir); error = NFS_PROTO(dir)->create(dir, &dentry->d_name, - &attr, 0, &fhandle, &fattr); + &attr, open_flags, &fhandle, &fattr); if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); else @@ -1239,13 +1271,20 @@ out: } int -nfs_permission(struct inode *inode, int mask) +nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; struct rpc_cred *cred; int mode = inode->i_mode; int res; + /* Are we checking permissions on anything other than lookup? */ + if (!(mask & MAY_EXEC)) { + /* We only need to check permissions on file open() and access() */ + if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS))) + return 0; + } + if (mask & MAY_WRITE) { /* * diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 26956c7de1d..7375f369e51 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -82,9 +82,6 @@ nfs_file_open(struct inode *inode, struct file *filp) /* Do NFSv4 open() call */ if ((open = server->rpc_ops->file_open) != NULL) res = open(inode, filp); - /* Do cto revalidation */ - else if (!(server->flags & NFS_MOUNT_NOCTO)) - res = __nfs_revalidate_inode(server, inode); /* Call generic open code in order to cache credentials */ if (!res) res = nfs_open(inode, filp); @@ -104,11 +101,13 @@ nfs_file_flush(struct file *file) dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); + lock_kernel(); status = nfs_wb_file(inode, file); if (!status) { status = file->f_error; file->f_error = 0; } + unlock_kernel(); return status; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 6d023b27ff6..32a50f1bed1 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -56,7 +56,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry) /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); - err = permission(parent->d_inode, S_IXOTH); + err = permission(parent->d_inode, S_IXOTH, NULL); if (err < 0) { dput(parent); break; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8759cb1076a..663f4839cc3 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -924,7 +924,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_perm; switch (type) { case S_IFREG: - err = vfs_create(dirp, dchild, iap->ia_mode); + err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: err = vfs_mkdir(dirp, dchild, iap->ia_mode); @@ -1067,7 +1067,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } - err = vfs_create(dirp, dchild, iap->ia_mode); + err = vfs_create(dirp, dchild, iap->ia_mode, NULL); if (err < 0) goto out_nfserr; @@ -1584,12 +1584,12 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) inode->i_uid == current->fsuid) return 0; - err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); + err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL); /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && acc == (MAY_READ | MAY_OWNER_OVERRIDE)) - err = permission(inode, MAY_EXEC); + err = permission(inode, MAY_EXEC, NULL); return err? nfserrno(err) : 0; } diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 84d43247ba6..a8c6e8a4e3b 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -29,6 +29,7 @@ * ntfs_lookup - find the inode represented by a dentry in a directory inode * @dir_ino: directory inode in which to look for the inode * @dent: dentry representing the inode to look for + * @nd: lookup nameidata * * In short, ntfs_lookup() looks for the inode represented by the dentry @dent * in the directory inode @dir_ino and if found attaches the inode to the @@ -87,7 +88,7 @@ * name. We then convert the name to the current NLS code page, and proceed * searching for a dentry with this name, etc, as in case 2), above. */ -static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent) +static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, struct nameidata *nd) { ntfs_volume *vol = NTFS_SB(dir_ino->i_sb); struct inode *dent_inode; diff --git a/fs/open.c b/fs/open.c index 2e2e4e4dae9..8a4197969f2 100644 --- a/fs/open.c +++ b/fs/open.c @@ -219,7 +219,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length) if (!S_ISREG(inode->i_mode)) goto dput_and_out; - error = permission(inode,MAY_WRITE); + error = permission(inode,MAY_WRITE,&nd); if (error) goto dput_and_out; @@ -365,7 +365,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && - (error = permission(inode,MAY_WRITE)) != 0) + (error = permission(inode,MAY_WRITE,&nd)) != 0) goto dput_and_out; } down(&inode->i_sem); @@ -410,7 +410,7 @@ long do_utimes(char __user * filename, struct timeval * times) newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { if (current->fsuid != inode->i_uid && - (error = permission(inode,MAY_WRITE)) != 0) + (error = permission(inode,MAY_WRITE,&nd)) != 0) goto dput_and_out; } down(&inode->i_sem); @@ -467,9 +467,9 @@ asmlinkage long sys_access(const char __user * filename, int mode) else current->cap_effective = current->cap_permitted; - res = user_path_walk(filename, &nd); + res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); if (!res) { - res = permission(nd.dentry->d_inode, mode); + res = permission(nd.dentry->d_inode, mode, &nd); /* SuS v2 requires we report a read only fs too */ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) && !special_file(nd.dentry->d_inode->i_mode)) @@ -493,7 +493,7 @@ asmlinkage long sys_chdir(const char __user * filename) if (error) goto out; - error = permission(nd.dentry->d_inode,MAY_EXEC); + error = permission(nd.dentry->d_inode,MAY_EXEC,&nd); if (error) goto dput_and_out; @@ -526,7 +526,7 @@ asmlinkage long sys_fchdir(unsigned int fd) if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = permission(inode, MAY_EXEC); + error = permission(inode, MAY_EXEC, NULL); if (!error) set_fs_pwd(current->fs, mnt, dentry); out_putf: @@ -544,7 +544,7 @@ asmlinkage long sys_chroot(const char __user * filename) if (error) goto out; - error = permission(nd.dentry->d_inode,MAY_EXEC); + error = permission(nd.dentry->d_inode,MAY_EXEC,&nd); if (error) goto dput_and_out; @@ -952,11 +952,8 @@ int filp_close(struct file *filp, fl_owner_t id) return 0; } retval = 0; - if (filp->f_op && filp->f_op->flush) { - lock_kernel(); + if (filp->f_op && filp->f_op->flush) retval = filp->f_op->flush(filp); - unlock_kernel(); - } dnotify_flush(filp, id); locks_remove_posix(filp, id); fput(filp); diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 5a1fb89449b..c0df469c9dc 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -59,9 +59,9 @@ static char *alias_names [ALIASES_NNODES]; #define NODE2INO(node) (node + OPENPROM_FIRST_INO) #define NODEP2INO(no) (no + OPENPROM_FIRST_INO + last_node) -static int openpromfs_create (struct inode *, struct dentry *, int); +static int openpromfs_create (struct inode *, struct dentry *, int, struct nameidata *); static int openpromfs_readdir(struct file *, void *, filldir_t); -static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry); +static struct dentry *openpromfs_lookup(struct inode *, struct dentry *dentry, struct nameidata *nd); static int openpromfs_unlink (struct inode *, struct dentry *dentry); static ssize_t nodenum_read(struct file *file, char *buf, @@ -639,7 +639,7 @@ static int lookup_children(u16 n, const char * name, int len) return 0; } -static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { int ino = 0; #define OPFSL_DIR 0 @@ -854,7 +854,8 @@ out: return 0; } -static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode) +static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { char *p; struct inode *inode; diff --git a/fs/proc/base.c b/fs/proc/base.c index e843c6584cc..485ff692e87 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -334,7 +334,7 @@ out: goto exit; } -static int proc_permission(struct inode *inode, int mask) +static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) { if (vfs_permission(inode, mask) != 0) return -EACCES; @@ -864,7 +864,7 @@ out_unlock: * directory. In this case, however, we can do it - no aliasing problems * due to the way we treat inodes. */ -static int pid_revalidate(struct dentry * dentry, int flags) +static int pid_revalidate(struct dentry * dentry, struct nameidata *nd) { if (pid_alive(proc_task(dentry->d_inode))) return 1; @@ -872,7 +872,7 @@ static int pid_revalidate(struct dentry * dentry, int flags) return 0; } -static int pid_fd_revalidate(struct dentry * dentry, int flags) +static int pid_fd_revalidate(struct dentry * dentry, struct nameidata *nd) { struct task_struct *task = proc_task(dentry->d_inode); int fd = proc_type(dentry->d_inode) - PROC_PID_FD_DIR; @@ -961,7 +961,7 @@ out: } /* SMP-safe */ -static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry) +static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { struct task_struct *task = proc_task(dir); unsigned fd = name_to_int(dentry); @@ -1219,7 +1219,7 @@ out: return ERR_PTR(error); } -static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry){ +static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ return proc_pident_lookup(dir, dentry, base_stuff); } @@ -1245,7 +1245,9 @@ static struct file_operations proc_attr_operations = { .readdir = proc_attr_readdir, }; -static struct dentry *proc_attr_lookup(struct inode *dir, struct dentry *dentry){ +static struct dentry *proc_attr_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ return proc_pident_lookup(dir, dentry, attr_stuff); } @@ -1326,7 +1328,7 @@ void proc_pid_flush(struct dentry *proc_dentry) } /* SMP-safe */ -struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry) +struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { struct task_struct *task; struct inode *inode; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 6f658ceafc3..979237c7296 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -336,7 +336,7 @@ static struct dentry_operations proc_dentry_operations = * Don't create negative dentries here, return -ENOENT by hand * instead. */ -struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct proc_dir_entry * de; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 1268f3883f4..eed19a3ea67 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -497,11 +497,10 @@ static int ds1286_read_proc(char *page, char **start, off_t off, static int locks_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - int len; - lock_kernel(); - len = get_locks_status(page, start, off, count); - unlock_kernel(); - if (len < count) *eof = 1; + int len = get_locks_status(page, start, off, count); + + if (len < count) + *eof = 1; return len; } diff --git a/fs/proc/root.c b/fs/proc/root.c index f6b7c065a96..936962d01c2 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -79,19 +79,21 @@ void __init proc_root_init(void) proc_bus = proc_mkdir("bus", 0); } -static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) +static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { - if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ - lock_kernel(); + /* + * nr_threads is actually protected by the tasklist_lock; + * however, it's conventional to do reads, especially for + * reporting, without any locking whatsoever. + */ + if (dir->i_ino == PROC_ROOT_INO) /* check for safety... */ dir->i_nlink = proc_root.nlink + nr_threads; - unlock_kernel(); - } - if (!proc_lookup(dir, dentry)) { + if (!proc_lookup(dir, dentry, nd)) { return NULL; } - return proc_pid_lookup(dir, dentry); + return proc_pid_lookup(dir, dentry, nd); } static int proc_root_readdir(struct file * filp, diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 0a7592c5b95..36e903d8977 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -107,7 +107,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, return NULL; } -struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry) +struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { int ino; struct qnx4_inode_entry *de; @@ -142,7 +142,8 @@ out: } #ifdef CONFIG_QNX4FS_RW -int qnx4_create(struct inode *dir, struct dentry *dentry, int mode) +int qnx4_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { QNX4DEBUG(("qnx4: qnx4_create\n")); if (dir == NULL) { diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 372f0651590..362ee3135e6 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -111,7 +111,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) return retval; } -static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode) +static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { return ramfs_mknod(dir, dentry, mode | S_IFREG, 0); } @@ -146,6 +146,7 @@ static struct file_operations ramfs_file_operations = { .mmap = generic_file_mmap, .fsync = simple_sync_file, .sendfile = generic_file_sendfile, + .llseek = generic_file_llseek, }; static struct inode_operations ramfs_file_inode_operations = { diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 46bc6549577..93151fb285c 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -316,7 +316,7 @@ static int reiserfs_find_entry (struct inode * dir, const char * name, int namel } -static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry) +static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry, struct nameidata *nd) { int retval; struct inode * inode = NULL; @@ -558,7 +558,8 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode) { return 0 ; } -static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode) +static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode, + struct nameidata *nd) { int retval; struct inode * inode; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index fb60389d42f..24cd428a521 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -329,7 +329,7 @@ out: } static struct dentry * -romfs_lookup(struct inode *dir, struct dentry *dentry) +romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { unsigned long offset, maxoff; int fslen, res; diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index af4b42beab8..f0b62740ae8 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -24,8 +24,8 @@ static int smb_readdir(struct file *, void *, filldir_t); static int smb_dir_open(struct inode *, struct file *); -static struct dentry *smb_lookup(struct inode *, struct dentry *); -static int smb_create(struct inode *, struct dentry *, int); +static struct dentry *smb_lookup(struct inode *, struct dentry *, struct nameidata *); +static int smb_create(struct inode *, struct dentry *, int, struct nameidata *); static int smb_mkdir(struct inode *, struct dentry *, int); static int smb_rmdir(struct inode *, struct dentry *); static int smb_unlink(struct inode *, struct dentry *); @@ -268,7 +268,7 @@ smb_dir_open(struct inode *dir, struct file *file) /* * Dentry operations routines */ -static int smb_lookup_validate(struct dentry *, int); +static int smb_lookup_validate(struct dentry *, struct nameidata *); static int smb_hash_dentry(struct dentry *, struct qstr *); static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static int smb_delete_dentry(struct dentry *); @@ -292,7 +292,7 @@ static struct dentry_operations smbfs_dentry_operations_case = * This is the callback when the dcache has a lookup hit. */ static int -smb_lookup_validate(struct dentry * dentry, int flags) +smb_lookup_validate(struct dentry * dentry, struct nameidata *nd) { struct smb_sb_info *server = server_from_dentry(dentry); struct inode * inode = dentry->d_inode; @@ -420,7 +420,7 @@ smb_renew_times(struct dentry * dentry) } static struct dentry * -smb_lookup(struct inode *dir, struct dentry *dentry) +smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct smb_fattr finfo; struct inode *inode; @@ -510,7 +510,8 @@ out_close: /* N.B. How should the mode argument be used? */ static int -smb_create(struct inode *dir, struct dentry *dentry, int mode) +smb_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { struct smb_sb_info *server = server_from_dentry(dentry); __u16 fileid; diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index a174775b2d1..6b25d7c8917 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -367,7 +367,7 @@ smb_file_release(struct inode *inode, struct file * file) * privileges, so we need our own check for this. */ static int -smb_file_permission(struct inode *inode, int mask) +smb_file_permission(struct inode *inode, int mask, struct nameidata *nd) { int mode = inode->i_mode; int error = 0; diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index e5439f1aafa..7f0d265d0bb 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -2,6 +2,8 @@ * bin.c - binary file operations for sysfs. */ +#undef DEBUG + #include #include #include @@ -42,18 +44,17 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off) ret = fill_read(dentry, buffer, offs, count); if (ret < 0) - goto Done; + return ret; count = ret; - ret = -EFAULT; - if (copy_to_user(userbuf, buffer, count) != 0) - goto Done; + if (copy_to_user(userbuf, buffer + offs, count) != 0) + return -EINVAL; + + pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); *off = offs + count; - ret = count; - Done: - return ret; + return count; } static int @@ -72,7 +73,6 @@ static ssize_t write(struct file * file, const char __user * userbuf, struct dentry *dentry = file->f_dentry; int size = dentry->d_inode->i_size; loff_t offs = *off; - int ret; if (count > PAGE_SIZE) count = PAGE_SIZE; @@ -83,16 +83,13 @@ static ssize_t write(struct file * file, const char __user * userbuf, count = size - offs; } - ret = -EFAULT; - if (copy_from_user(buffer, userbuf, count)) - goto Done; + if (copy_from_user(buffer + offs, userbuf, count)) + return -EFAULT; count = flush_write(dentry, buffer, offs, count); if (count > 0) *off = offs + count; - ret = count; - Done: - return ret; + return count; } static int open(struct inode * inode, struct file * file) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 1ca3a06db1d..0b1588ab925 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -121,7 +121,29 @@ void sysfs_remove_dir(struct kobject * kobj) dput(parent); } +void sysfs_rename_dir(struct kobject * kobj, char *new_name) +{ + struct dentry * new_dentry, * parent; + + if (!strcmp(kobj->name, new_name)) + return; + + if (!kobj->parent) + return; + + parent = kobj->parent->dentry; + + down(&parent->d_inode->i_sem); + + new_dentry = sysfs_get_dentry(parent, new_name); + d_move(kobj->dentry, new_dentry); + + strlcpy(kobj->name, new_name, KOBJ_NAME_LEN); + + up(&parent->d_inode->i_sem); +} EXPORT_SYMBOL(sysfs_create_dir); EXPORT_SYMBOL(sysfs_remove_dir); +EXPORT_SYMBOL(sysfs_rename_dir); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1d25a84702b..2cedefe8c4a 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -247,6 +247,12 @@ static int check_perm(struct inode * inode, struct file * file) if (!kobj || !attr) goto Einval; + /* Grab the module reference for this attribute if we have one */ + if (!try_module_get(attr->owner)) { + error = -ENODEV; + goto Done; + } + /* if the kobject has no ktype, then we assume that it is a subsystem * itself, and use ops for it. */ @@ -300,6 +306,7 @@ static int check_perm(struct inode * inode, struct file * file) goto Done; Eaccess: error = -EACCES; + module_put(attr->owner); Done: if (error && kobj) kobject_put(kobj); @@ -314,10 +321,12 @@ static int sysfs_open_file(struct inode * inode, struct file * filp) static int sysfs_release(struct inode * inode, struct file * filp) { struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata; + struct attribute * attr = filp->f_dentry->d_fsdata; struct sysfs_buffer * buffer = filp->private_data; if (kobj) kobject_put(kobj); + module_put(attr->owner); if (buffer) { if (buffer->page) diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index f2988f10769..cbf08f04d07 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -64,7 +64,7 @@ struct dentry_operations sysv_dentry_operations = { .d_hash = sysv_hash, }; -static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry) +static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) { struct inode * inode = NULL; ino_t ino; @@ -96,7 +96,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_ return err; } -static int sysv_create(struct inode * dir, struct dentry * dentry, int mode) +static int sysv_create(struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { return sysv_mknod(dir, dentry, mode, 0); } diff --git a/fs/udf/file.c b/fs/udf/file.c index 9fd46aff63a..b1cf9999e90 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -188,7 +188,7 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, { int result = -EINVAL; - if ( permission(inode, MAY_READ) != 0 ) + if ( permission(inode, MAY_READ, NULL) != 0 ) { udf_debug("no permission to access inode %lu\n", inode->i_ino); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index b5be4880dea..d2ac88dae44 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -289,6 +289,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry, * PRE-CONDITIONS * dir Pointer to inode of parent directory. * dentry Pointer to dentry to complete. + * nd Pointer to lookup nameidata * * POST-CONDITIONS * Zero on success. @@ -299,7 +300,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry, */ static struct dentry * -udf_lookup(struct inode *dir, struct dentry *dentry) +udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct inode *inode = NULL; struct fileIdentDesc cfi, *fi; @@ -620,7 +621,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL); } -static int udf_create(struct inode *dir, struct dentry *dentry, int mode) +static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { struct udf_fileident_bh fibh; struct inode *inode; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 24c6c5d2938..82f391298c4 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -62,7 +62,7 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) return err; } -static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode = NULL; ino_t ino; @@ -92,7 +92,8 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry) * If the create succeeds, we fill in the inode information * with d_instantiate(). */ -static int ufs_create (struct inode * dir, struct dentry * dentry, int mode) +static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, + struct nameidata *nd) { struct inode * inode = ufs_new_inode(dir, mode); int err = PTR_ERR(inode); diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index befb7545f53..775f0202112 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -30,7 +30,7 @@ extern struct inode *pseudo_root; */ /* nothing for now ... */ -static int umsdos_dentry_validate(struct dentry *dentry, int flags) +static int umsdos_dentry_validate(struct dentry *dentry, struct nameidata *nd) { return 1; } @@ -564,7 +564,7 @@ out_remove: * Called by VFS; should fill dentry->d_inode via d_add. */ -struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry) +struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct dentry *ret; diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 06190391d47..7fadb55b7e4 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -105,7 +105,7 @@ int umsdos_make_emd(struct dentry *parent) Printk(("umsdos_make_emd: creating EMD %s/%s\n", parent->d_name.name, demd->d_name.name)); - err = msdos_create(parent->d_inode, demd, S_IFREG | 0777); + err = msdos_create(parent->d_inode, demd, S_IFREG | 0777, NULL); if (err) { printk (KERN_WARNING "umsdos_make_emd: create %s/%s failed, err=%d\n", diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 3d89ba970a0..2d8a64af1ae 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -274,7 +274,7 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry, if (fake->d_inode) goto out_remove_dput; - ret = msdos_create (dir, fake, S_IFREG | 0777); + ret = msdos_create (dir, fake, S_IFREG | 0777, NULL); if (ret) goto out_remove_dput; @@ -311,7 +311,7 @@ out_remove: * * Return the status of the operation. 0 mean success. */ -int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode) +int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { return umsdos_create_any (dir, dentry, mode, 0, 0); } diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index d4ac89d1e66..2f32539b1a3 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -101,7 +101,7 @@ struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int goto out; } - ret = msdos_lookup (dir, dentry); + ret = msdos_lookup (dir, dentry, NULL); if (ret) { printk(KERN_WARNING "umsdos_rlookup_x: %s/%s failed, ret=%ld\n", @@ -129,7 +129,7 @@ out: } -struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry) +struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry, struct nameidata *nd) { return umsdos_rlookup_x (dir, dentry, 0); } diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 1f83a9d77e8..12c067c8355 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -45,7 +45,7 @@ static int vfat_hashi(struct dentry *parent, struct qstr *qstr); static int vfat_hash(struct dentry *parent, struct qstr *qstr); static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); -static int vfat_revalidate(struct dentry *dentry, int); +static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd); static struct dentry_operations vfat_dentry_ops[4] = { { @@ -68,7 +68,7 @@ static struct dentry_operations vfat_dentry_ops[4] = { } }; -static int vfat_revalidate(struct dentry *dentry, int flags) +static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) { PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name)); spin_lock(&dcache_lock); @@ -860,7 +860,7 @@ static int vfat_find(struct inode *dir,struct qstr* qname, return res ? res : -ENOENT; } -struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry) +struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry, struct nameidata *nd) { int res; struct vfat_slot_info sinfo; @@ -912,7 +912,8 @@ error: return dentry; } -int vfat_create(struct inode *dir,struct dentry* dentry,int mode) +int vfat_create(struct inode *dir,struct dentry* dentry,int mode, + struct nameidata *nd) { struct super_block *sb = dir->i_sb; struct inode *inode = NULL; diff --git a/fs/xattr.c b/fs/xattr.c index 2a2b6d53af1..37d2a109eef 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -160,9 +160,7 @@ getxattr(struct dentry *d, char *name, void *value, size_t size) error = security_inode_getxattr(d, kname); if (error) goto out; - down(&d->d_inode->i_sem); error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); - up(&d->d_inode->i_sem); } if (kvalue && error > 0) @@ -233,9 +231,7 @@ listxattr(struct dentry *d, char *list, size_t size) error = security_inode_listxattr(d); if (error) goto out; - down(&d->d_inode->i_sem); error = d->d_inode->i_op->listxattr(d, klist, size); - up(&d->d_inode->i_sem); } if (klist && error > 0) diff --git a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c index a8ea382c967..8370a0564a2 100644 --- a/fs/xfs/linux/xfs_globals.c +++ b/fs/xfs/linux/xfs_globals.c @@ -38,6 +38,7 @@ #include "xfs.h" #include "xfs_bmap_btree.h" #include "xfs_bit.h" +#include "xfs_rw.h" /* * System memory size - used to scale certain data structures in XFS. @@ -48,7 +49,18 @@ unsigned long xfs_physmem; * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n, * other XFS code uses these values. */ -xfs_param_t xfs_params = { 0, 1, 0, 0, 3, 30 * HZ, 0 }; + +xfs_param_t xfs_params = { + /* MIN DFLT MAX */ + restrict_chown: { 0, 1, 1 }, + sgid_inherit: { 0, 0, 1 }, + symlink_mode: { 0, 0, 1 }, + panic_mask: { 0, 0, 127 }, + error_level: { 0, 3, 11 }, + sync_interval: { HZ, 30*HZ, 60*HZ }, + stats_clear: { 0, 0, 1 }, + +}; /* * Global system credential structure. diff --git a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c index 14d393eb6d2..59f52039014 100644 --- a/fs/xfs/linux/xfs_iops.c +++ b/fs/xfs/linux/xfs_iops.c @@ -175,7 +175,8 @@ STATIC int linvfs_create( struct inode *dir, struct dentry *dentry, - int mode) + int mode, + struct nameidata *nd) { return linvfs_mknod(dir, dentry, mode, 0); } @@ -192,7 +193,8 @@ linvfs_mkdir( STATIC struct dentry * linvfs_lookup( struct inode *dir, - struct dentry *dentry) + struct dentry *dentry, + struct nameidata *nd) { struct inode *ip = NULL; vnode_t *vp, *cvp = NULL; @@ -429,7 +431,8 @@ linvfs_follow_link( STATIC int linvfs_permission( struct inode *inode, - int mode) + int mode, + struct nameidata *nd) { vnode_t *vp = LINVFS_GET_VP(inode); int error; @@ -639,7 +642,7 @@ linvfs_setxattr( } STATIC ssize_t -linvfs_getxattr( +__linvfs_getxattr( struct dentry *dentry, const char *name, void *data, @@ -694,9 +697,24 @@ linvfs_getxattr( return -EOPNOTSUPP; } +STATIC ssize_t +linvfs_getxattr( + struct dentry *dentry, + const char *name, + void *data, + size_t size) +{ + int error; + + down(&dentry->d_inode->i_sem); + error = __linvfs_getxattr(dentry, name, data, size); + up(&dentry->d_inode->i_sem); + + return error; +} STATIC ssize_t -linvfs_listxattr( +__linvfs_listxattr( struct dentry *dentry, char *data, size_t size) @@ -738,6 +756,21 @@ linvfs_listxattr( return result; } +STATIC ssize_t +linvfs_listxattr( + struct dentry *dentry, + char *data, + size_t size) +{ + int error; + + down(&dentry->d_inode->i_sem); + error = __linvfs_listxattr(dentry, data, size); + up(&dentry->d_inode->i_sem); + + return error; +} + STATIC int linvfs_removexattr( struct dentry *dentry, diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h index 1387dc68f47..fe259b0c32f 100644 --- a/fs/xfs/linux/xfs_linux.h +++ b/fs/xfs/linux/xfs_linux.h @@ -87,11 +87,15 @@ static inline void set_buffer_unwritten_io(struct buffer_head *bh) bh->b_end_io = linvfs_unwritten_done; } -#define restricted_chown xfs_params.restrict_chown -#define irix_sgid_inherit xfs_params.sgid_inherit -#define irix_symlink_mode xfs_params.symlink_mode -#define xfs_panic_mask xfs_params.panic_mask -#define xfs_error_level xfs_params.error_level +#define xfs_refcache_size xfs_params.refcache_size.val +#define xfs_refcache_purge_count xfs_params.refcache_purge.val +#define restricted_chown xfs_params.restrict_chown.val +#define irix_sgid_inherit xfs_params.sgid_inherit.val +#define irix_symlink_mode xfs_params.symlink_mode.val +#define xfs_panic_mask xfs_params.panic_mask.val +#define xfs_error_level xfs_params.error_level.val +#define xfs_syncd_interval xfs_params.sync_interval.val +#define xfs_stats_clear xfs_params.stats_clear.val #define NBPP PAGE_SIZE #define DPPSHFT (PAGE_SHIFT - 9) diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 0df0d915865..2c83b2b5dc0 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -71,6 +71,7 @@ #include #include #include +#include STATIC struct quotactl_ops linvfs_qops; STATIC struct super_operations linvfs_sops; @@ -265,8 +266,8 @@ xfs_setsize_buftarg( if (set_blocksize(btp->pbr_bdev, sectorsize)) { printk(KERN_WARNING - "XFS: Cannot set_blocksize to %u on device 0x%x\n", - sectorsize, btp->pbr_dev); + "XFS: Cannot set_blocksize to %u on device 0x%lx\n", + sectorsize, (unsigned long)btp->pbr_dev); } } @@ -400,7 +401,10 @@ syncd(void *arg) for (;;) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(xfs_params.sync_interval); + schedule_timeout(xfs_syncd_interval); + /* swsusp */ + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); if (vfsp->vfs_flag & VFS_UMOUNT) break; if (vfsp->vfs_flag & VFS_RDONLY) diff --git a/fs/xfs/linux/xfs_syncd.c b/fs/xfs/linux/xfs_syncd.c deleted file mode 100644 index 4aadb59ab88..00000000000 --- a/fs/xfs/linux/xfs_syncd.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ - */ - -#include - -#define SYNCD_FLAGS (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR) - -int syncd(void *arg) -{ - vfs_t *vfsp = (vfs_t *) arg; - int error; - - daemonize("xfs_syncd"); - - vfsp->vfs_sync_task = current; - wmb(); - wake_up(&vfsp->vfs_wait_sync_task); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(xfs_params.sync_interval); - if (vfsp->vfs_flag & VFS_UMOUNT) - break; - if (vfsp->vfs_flag & VFS_RDONLY); - continue; - VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error); - } - - vfsp->vfs_sync_task = NULL; - wmb(); - wake_up(&vfsp->vfs_wait_sync_task); - - return 0; -} - -int -linvfs_start_syncd(vfs_t *vfsp) -{ - int pid; - - pid = kernel_thread(syncd, (void *) vfsp, - CLONE_VM | CLONE_FS | CLONE_FILES); - if (pid < 0) - return pid; - wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task); - return 0; -} - -void -linvfs_stop_syncd(vfs_t *vfsp) -{ - vfsp->vfs_flag |= VFS_UMOUNT; - wmb(); - - wake_up_process(vfsp->vfs_sync_task); - wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task); -} diff --git a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c index 745a6f04e40..34041998ba3 100644 --- a/fs/xfs/linux/xfs_sysctl.c +++ b/fs/xfs/linux/xfs_sysctl.c @@ -36,9 +36,6 @@ #include -STATIC ulong xfs_min[XFS_PARAM] = { 0, 0, 0, 0, 0, HZ, 0 }; -STATIC ulong xfs_max[XFS_PARAM] = { 1, 1, 1, 127, 3, HZ * 60, 1 }; - static struct ctl_table_header *xfs_table_header; @@ -62,7 +59,7 @@ xfs_stats_clear_proc_handler( vn_active = xfsstats.vn_active; memset(&xfsstats, 0, sizeof(xfsstats)); xfsstats.vn_active = vn_active; - xfs_params.stats_clear = 0; + xfs_stats_clear = 0; } return ret; @@ -70,35 +67,42 @@ xfs_stats_clear_proc_handler( #endif /* CONFIG_PROC_FS */ STATIC ctl_table xfs_table[] = { - {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown, + {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]}, + &sysctl_intvec, NULL, + &xfs_params.restrict_chown.min, &xfs_params.restrict_chown.max}, - {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit, + {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[1], &xfs_max[1]}, + &sysctl_intvec, NULL, + &xfs_params.sgid_inherit.min, &xfs_params.sgid_inherit.max}, - {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode, + {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]}, + &sysctl_intvec, NULL, + &xfs_params.symlink_mode.min, &xfs_params.symlink_mode.max}, - {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask, + {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[3], &xfs_max[3]}, + &sysctl_intvec, NULL, + &xfs_params.panic_mask.min, &xfs_params.panic_mask.max}, - {XFS_ERRLEVEL, "error_level", &xfs_params.error_level, + {XFS_ERRLEVEL, "error_level", &xfs_params.error_level.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[4], &xfs_max[4]}, + &sysctl_intvec, NULL, + &xfs_params.error_level.min, &xfs_params.error_level.max}, - {XFS_SYNC_INTERVAL, "sync_interval", &xfs_params.sync_interval, + {XFS_SYNC_INTERVAL, "sync_interval", &xfs_params.sync_interval.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]}, + &sysctl_intvec, NULL, + &xfs_params.sync_interval.min, &xfs_params.sync_interval.max}, /* please keep this the last entry */ #ifdef CONFIG_PROC_FS - {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear, + {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler, - &sysctl_intvec, NULL, &xfs_min[6], &xfs_max[6]}, + &sysctl_intvec, NULL, + &xfs_params.stats_clear.min, &xfs_params.stats_clear.max}, #endif /* CONFIG_PROC_FS */ {0} diff --git a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h index 1fa2bd0ff38..45bc8a0a8f4 100644 --- a/fs/xfs/linux/xfs_sysctl.h +++ b/fs/xfs/linux/xfs_sysctl.h @@ -39,17 +39,22 @@ * Tunable xfs parameters */ -#define XFS_PARAM (sizeof(struct xfs_param) / sizeof(ulong)) +typedef struct xfs_sysctl_val { + ulong min; + ulong val; + ulong max; +} xfs_sysctl_val_t; typedef struct xfs_param { - ulong restrict_chown; /* Root/non-root can give away files. */ - ulong sgid_inherit; /* Inherit ISGID bit if process' GID is */ - /* not a member of the parent dir GID. */ - ulong symlink_mode; /* Symlink creat mode affected by umask. */ - ulong panic_mask; /* bitmask to specify panics on errors. */ - ulong error_level; /* Degree of reporting for internal probs*/ - ulong sync_interval; /* time between sync calls */ - ulong stats_clear; /* Reset all XFS statistics to zero. */ + xfs_sysctl_val_t restrict_chown;/* Root/non-root can give away files.*/ + xfs_sysctl_val_t sgid_inherit; /* Inherit ISGID bit if process' GID + * is not a member of the parent dir + * GID */ + xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */ + xfs_sysctl_val_t panic_mask; /* bitmask to cause panic on errors. */ + xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ + xfs_sysctl_val_t sync_interval; /* time between sync calls */ + xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ } xfs_param_t; /* diff --git a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c index a94cca589b0..3b9245eab54 100644 --- a/fs/xfs/pagebuf/page_buf.c +++ b/fs/xfs/pagebuf/page_buf.c @@ -92,7 +92,7 @@ pb_trace_func( int j; unsigned long flags; - if (!pb_params.p_un.debug) return; + if (!pb_params.debug.val) return; if (ra == NULL) ra = (void *)__builtin_return_address(0); @@ -129,10 +129,13 @@ STATIC struct workqueue_struct *pagebuf_dataio_workqueue; * /proc/sys/vm/pagebuf */ -unsigned long pagebuf_min[P_PARAM] = { HZ/2, 1*HZ, 0, 0 }; -unsigned long pagebuf_max[P_PARAM] = { HZ*30, HZ*300, 1, 1 }; - -pagebuf_param_t pb_params = {{ HZ, 15 * HZ, 0, 0 }}; +pagebuf_param_t pb_params = { + /* MIN DFLT MAX */ + flush_interval: { HZ/2, HZ, 30*HZ }, + age_buffer: { 1*HZ, 15*HZ, 300*HZ }, + stats_clear: { 0, 0, 1 }, + debug: { 0, 0, 1 }, +}; /* * Pagebuf statistics variables @@ -1556,7 +1559,7 @@ pagebuf_delwri_queue( } list_add_tail(&pb->pb_list, &pbd_delwrite_queue); - pb->pb_flushtime = jiffies + pb_params.p_un.age_buffer; + pb->pb_flushtime = jiffies + pb_params.age_buffer.val; spin_unlock(&pbd_delwrite_lock); if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { @@ -1621,7 +1624,7 @@ pagebuf_daemon( if (pbd_active == 1) { mod_timer(&pb_daemon_timer, - jiffies + pb_params.p_un.flush_interval); + jiffies + pb_params.flush_interval.val); interruptible_sleep_on(&pbd_waitq); } @@ -1824,7 +1827,7 @@ pb_stats_clear_handler( if (!ret && write && *valp) { printk("XFS Clearing pbstats\n"); memset(&pbstats, 0, sizeof(pbstats)); - pb_params.p_un.stats_clear = 0; + pb_params.stats_clear.val = 0; } return ret; @@ -1833,22 +1836,26 @@ pb_stats_clear_handler( STATIC struct ctl_table_header *pagebuf_table_header; STATIC ctl_table pagebuf_table[] = { - {PB_FLUSH_INT, "flush_int", &pb_params.data[0], + {PB_FLUSH_INT, "flush_int", &pb_params.flush_interval.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, - &sysctl_intvec, NULL, &pagebuf_min[0], &pagebuf_max[0]}, + &sysctl_intvec, NULL, + &pb_params.flush_interval.min, &pb_params.flush_interval.max}, - {PB_FLUSH_AGE, "flush_age", &pb_params.data[1], + {PB_FLUSH_AGE, "flush_age", &pb_params.age_buffer.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, - &sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]}, + &sysctl_intvec, NULL, + &pb_params.age_buffer.min, &pb_params.age_buffer.max}, - {PB_STATS_CLEAR, "stats_clear", &pb_params.data[2], + {PB_STATS_CLEAR, "stats_clear", &pb_params.stats_clear.val, sizeof(ulong), 0644, NULL, &pb_stats_clear_handler, - &sysctl_intvec, NULL, &pagebuf_min[2], &pagebuf_max[2]}, + &sysctl_intvec, NULL, + &pb_params.stats_clear.min, &pb_params.stats_clear.max}, #ifdef PAGEBUF_TRACE - {PB_DEBUG, "debug", &pb_params.data[3], + {PB_DEBUG, "debug", &pb_params.debug.val, sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax, - &sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]}, + &sysctl_intvec, NULL, + &pb_params.debug.min, &pb_params.debug.max}, #endif {0} }; diff --git a/fs/xfs/pagebuf/page_buf_internal.h b/fs/xfs/pagebuf/page_buf_internal.h index b751d3ed055..bec3d234018 100644 --- a/fs/xfs/pagebuf/page_buf_internal.h +++ b/fs/xfs/pagebuf/page_buf_internal.h @@ -85,18 +85,19 @@ struct pagebuf_trace_buf { * Tunable pagebuf parameters */ -#define P_PARAM 4 - -typedef union pagebuf_param { - struct { - ulong flush_interval; /* interval between runs of the +typedef struct pb_sysctl_val { + ulong min; + ulong val; + ulong max; +} pb_sysctl_val_t; + +typedef struct pagebuf_param { + pb_sysctl_val_t flush_interval; /* interval between runs of the * delwri flush daemon. */ - ulong age_buffer; /* time for buffer to age before + pb_sysctl_val_t age_buffer; /* time for buffer to age before * we flush it. */ - ulong debug; /* debug tracing on or off */ - ulong stats_clear; /* clear the pagebuf stats */ - } p_un; - ulong data[P_PARAM]; + pb_sysctl_val_t stats_clear; /* clear the pagebuf stats */ + pb_sysctl_val_t debug; /* debug tracing on or off */ } pagebuf_param_t; enum { diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 240a53e1ee4..515fef85f41 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -96,9 +96,6 @@ xfs_init(void) #endif /* DEBUG */ #ifdef XFS_DABUF_DEBUG extern lock_t xfs_dabuf_global_lock; -#endif - -#ifdef XFS_DABUF_DEBUG spinlock_init(&xfs_dabuf_global_lock, "xfsda"); #endif diff --git a/include/asm-alpha/div64.h b/include/asm-alpha/div64.h index 080dcd48080..6cd978cefb2 100644 --- a/include/asm-alpha/div64.h +++ b/include/asm-alpha/div64.h @@ -1,14 +1 @@ -#ifndef __ALPHA_DIV64 -#define __ALPHA_DIV64 - -/* - * Hey, we're already 64-bit, no - * need to play games.. - */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) (n)) % (unsigned) (base); \ - (n) = ((unsigned long) (n)) / (unsigned) (base); \ - __res; }) - -#endif +#include diff --git a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h index 6d1b408e3ed..f09f71909aa 100644 --- a/include/asm-alpha/machvec.h +++ b/include/asm-alpha/machvec.h @@ -68,7 +68,7 @@ struct alpha_machine_vector int (*mv_is_ioaddr)(unsigned long); void (*mv_switch_mm)(struct mm_struct *, struct mm_struct *, - struct task_struct *, long); + struct task_struct *); void (*mv_activate_mm)(struct mm_struct *, struct mm_struct *); void (*mv_flush_tlb_current)(struct mm_struct *); diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h index a087254ea38..3ae6408acae 100644 --- a/include/asm-alpha/mmu_context.h +++ b/include/asm-alpha/mmu_context.h @@ -130,11 +130,12 @@ __get_new_mm_context(struct mm_struct *mm, long cpu) __EXTERN_INLINE void ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, - struct task_struct *next, long cpu) + struct task_struct *next) { /* Check if our ASN is of an older version, and thus invalid. */ unsigned long asn; unsigned long mmc; + long cpu = smp_processor_id(); #ifdef CONFIG_SMP cpu_data[cpu].asn_lock = 1; @@ -159,7 +160,7 @@ ev5_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, __EXTERN_INLINE void ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, - struct task_struct *next, long cpu) + struct task_struct *next) { /* As described, ASN's are broken for TLB usage. But we can optimize for switching between threads -- if the mm is @@ -174,7 +175,7 @@ ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, /* Do continue to allocate ASNs, because we can still use them to avoid flushing the icache. */ - ev5_switch_mm(prev_mm, next_mm, next, cpu); + ev5_switch_mm(prev_mm, next_mm, next); } extern void __load_new_mm_context(struct mm_struct *); @@ -212,14 +213,14 @@ ev4_activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm) #define deactivate_mm(tsk,mm) do { } while (0) #ifdef CONFIG_ALPHA_GENERIC -# define switch_mm(a,b,c,d) alpha_mv.mv_switch_mm((a),(b),(c),(d)) +# define switch_mm(a,b,c) alpha_mv.mv_switch_mm((a),(b),(c)) # define activate_mm(x,y) alpha_mv.mv_activate_mm((x),(y)) #else # ifdef CONFIG_ALPHA_EV4 -# define switch_mm(a,b,c,d) ev4_switch_mm((a),(b),(c),(d)) +# define switch_mm(a,b,c) ev4_switch_mm((a),(b),(c)) # define activate_mm(x,y) ev4_activate_mm((x),(y)) # else -# define switch_mm(a,b,c,d) ev5_switch_mm((a),(b),(c),(d)) +# define switch_mm(a,b,c) ev5_switch_mm((a),(b),(c)) # define activate_mm(x,y) ev5_activate_mm((x),(y)) # endif #endif @@ -245,7 +246,7 @@ destroy_context(struct mm_struct *mm) } static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { tsk->thread_info->pcb.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT; diff --git a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h index 6edb9c64aa7..36e3130c669 100644 --- a/include/asm-alpha/mmzone.h +++ b/include/asm-alpha/mmzone.h @@ -31,7 +31,6 @@ extern pg_data_t node_data[]; #define pa_to_nid(pa) alpha_pa_to_nid(pa) #define NODE_DATA(nid) (&node_data[(nid)]) -#define node_size(nid) (NODE_DATA(nid)->node_size) #define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn) @@ -124,7 +123,7 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n) #define pfn_to_nid(pfn) pa_to_nid(((u64)pfn << PAGE_SHIFT)) #define pfn_valid(pfn) \ (((pfn) - node_start_pfn(pfn_to_nid(pfn))) < \ - node_size(pfn_to_nid(pfn))) \ + node_spanned_pages(pfn_to_nid(pfn))) \ #define virt_addr_valid(kaddr) pfn_valid((__pa(kaddr) >> PAGE_SHIFT)) diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h index 3b3b473c668..e0340f5fbf3 100644 --- a/include/asm-arm/mmu_context.h +++ b/include/asm-arm/mmu_context.h @@ -28,7 +28,7 @@ * tsk->mm will be NULL */ static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -40,7 +40,7 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) */ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned int cpu) + struct task_struct *tsk) { if (prev != next) { cpu_switch_mm(next->pgd, next); diff --git a/include/asm-arm26/arch.h b/include/asm-arm26/arch.h deleted file mode 100644 index 1011bcc6d7a..00000000000 --- a/include/asm-arm26/arch.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * linux/include/asm-arm/mach/arch.h - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * The size of struct machine_desc - * (for assembler code) - * FIXME - I count 45... or is this padding? - */ -#define SIZEOF_MACHINE_DESC 48 - -#ifndef __ASSEMBLY__ - -struct tag; - -struct machine_desc { - int nr; /* arch no FIXME - get rid */ - const char *name; /* architecture name */ - unsigned int param_offset; /* parameter page */ - - unsigned int video_start; /* start of video RAM */ - unsigned int video_end; /* end of video RAM */ - - unsigned int reserve_lp0 :1; /* never has lp0 */ - unsigned int reserve_lp1 :1; /* never has lp1 */ - unsigned int reserve_lp2 :1; /* never has lp2 */ - unsigned int soft_reboot :1; /* soft reboot */ - void (*fixup)(struct machine_desc *, - struct tag *, char **, - struct meminfo *); - void (*map_io)(void);/* IO mapping function */ - void (*init_irq)(void); -}; - -/* - * Set of macros to define architecture features. This is built into - * a table by the linker. - */ -#define MACHINE_START(_type,_name) \ -const struct machine_desc __mach_desc_##_type \ - __attribute__((__section__(".arch.info"))) = { \ - nr: MACH_TYPE_##_type, \ - name: _name, - -#define MAINTAINER(n) - -#define BOOT_PARAMS(_params) \ - param_offset: _params, - -#define INITIRQ(_func) \ - init_irq: _func, - -#define MACHINE_END \ -}; - -#endif diff --git a/include/asm-arm26/bug.h b/include/asm-arm26/bug.h index a92b1bc8eb1..a1afde728b0 100644 --- a/include/asm-arm26/bug.h +++ b/include/asm-arm26/bug.h @@ -4,7 +4,7 @@ #include #ifdef CONFIG_DEBUG_BUGVERBOSE -extern void __bug(const char *file, int line, void *data); +extern volatile void __bug(const char *file, int line, void *data); /* give file/line information */ #define BUG() __bug(__FILE__, __LINE__, NULL) @@ -18,4 +18,13 @@ extern void __bug(const char *file, int line, void *data); #endif +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + #endif diff --git a/include/asm-arm26/bugs.h b/include/asm-arm26/bugs.h index 665ab62c27c..e99ac2e46d7 100644 --- a/include/asm-arm26/bugs.h +++ b/include/asm-arm26/bugs.h @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/bugs.h + * linux/include/asm-arm26/bugs.h * * Copyright (C) 1995 Russell King * diff --git a/include/asm-arm26/div64.h b/include/asm-arm26/div64.h index 27fec4ee6ae..6cd978cefb2 100644 --- a/include/asm-arm26/div64.h +++ b/include/asm-arm26/div64.h @@ -1,14 +1 @@ -#ifndef __ASM_ARM_DIV64 -#define __ASM_ARM_DIV64 - -/* We're not 64-bit, but... */ -#define do_div(n,base) \ -({ \ - int __res; \ - __res = ((unsigned long)n) % (unsigned int)base; \ - n = ((unsigned long)n) / (unsigned int)base; \ - __res; \ -}) - -#endif - +#include diff --git a/include/asm-arm26/ecard.h b/include/asm-arm26/ecard.h index 28af14fd7f7..8318a0c1df8 100644 --- a/include/asm-arm26/ecard.h +++ b/include/asm-arm26/ecard.h @@ -26,6 +26,9 @@ #define PROD_ACORN_ETHER1 0x0003 #define PROD_ACORN_MFM 0x000b +#define MANU_CCONCEPTS 0x0009 +#define PROD_CCONCEPTS_COLOURCARD 0x0050 + #define MANU_ANT2 0x0011 #define PROD_ANT_ETHER3 0x00a4 diff --git a/include/asm-arm26/mach-types.h b/include/asm-arm26/mach-types.h index 514b8032696..b34045b7812 100644 --- a/include/asm-arm26/mach-types.h +++ b/include/asm-arm26/mach-types.h @@ -1,5 +1,6 @@ /* * Unlike ARM32 this is NOT automatically generated. DONT delete it + * Instead, consider FIXME-ing it so its auto-detected. */ #ifndef __ASM_ARM_MACH_TYPE_H diff --git a/include/asm-arm26/mmu_context.h b/include/asm-arm26/mmu_context.h index 88b7b4f8f21..1a929bfe5c3 100644 --- a/include/asm-arm26/mmu_context.h +++ b/include/asm-arm26/mmu_context.h @@ -26,7 +26,7 @@ * tsk->mm will be NULL */ static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -36,7 +36,7 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) */ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned int cpu) + struct task_struct *tsk) { cpu_switch_mm(next->pgd, next); } diff --git a/include/asm-arm26/pgalloc.h b/include/asm-arm26/pgalloc.h index bf2e1951252..6437167b1ff 100644 --- a/include/asm-arm26/pgalloc.h +++ b/include/asm-arm26/pgalloc.h @@ -55,9 +55,9 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) * is thrown away. It just cant be zero. -IM */ -#define pmd_alloc_one(mm,addr) ((pmd_t *)2); BUG() +#define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) #define pmd_free(pmd) do { } while (0) -#define pgd_populate(mm,pmd,pte) (0) +#define pgd_populate(mm,pmd,pte) BUG() extern pgd_t *get_pgd_slow(struct mm_struct *mm); extern void free_pgd_slow(pgd_t *pgd); diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h index a6ac3957b0b..3fb067eaf80 100644 --- a/include/asm-arm26/pgtable.h +++ b/include/asm-arm26/pgtable.h @@ -179,7 +179,7 @@ extern struct page *empty_zero_page; /* Is pmd_page supposed to return a pointer to a page in some arches? ours seems to * return a pointer to memory (no special alignment) */ -#define pmd_page(pmd) ((unsigned long)(pmd_val((pmd)) & ~_PMD_PRESENT)) +#define pmd_page(pmd) ((struct page *)(pmd_val((pmd)) & ~_PMD_PRESENT)) #define pmd_page_kernel(pmd) ((pte_t *)(pmd_val((pmd)) & ~_PMD_PRESENT)) #define pte_offset_kernel(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr)) diff --git a/include/asm-arm26/statfs.h b/include/asm-arm26/statfs.h index a1eba73ded9..776dbc8f762 100644 --- a/include/asm-arm26/statfs.h +++ b/include/asm-arm26/statfs.h @@ -1,25 +1,8 @@ #ifndef _ASMARM_STATFS_H #define _ASMARM_STATFS_H -#ifndef __KERNEL_STRICT_NAMES +//FIXME - this may not be appropriate for arm26. check it out. -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-arm26/thread_info.h b/include/asm-arm26/thread_info.h index 3f298bf9206..24c5136484f 100644 --- a/include/asm-arm26/thread_info.h +++ b/include/asm-arm26/thread_info.h @@ -85,7 +85,7 @@ static inline struct thread_info *current_thread_info(void) //#define INIT_THREAD_SIZE (65536) #define __get_user_regs(x) (((struct pt_regs *)((unsigned long)(x) + THREAD_SIZE - 8)) - 1) -extern struct thread_info *alloc_thread_info(void); +extern struct thread_info *alloc_thread_info(struct task_struct *task); extern void free_thread_info(struct thread_info *); #define get_thread_info(ti) get_task_struct((ti)->task) diff --git a/include/asm-cris/arch-v10/bitops.h b/include/asm-cris/arch-v10/bitops.h new file mode 100644 index 00000000000..21b7ae8c9bb --- /dev/null +++ b/include/asm-cris/arch-v10/bitops.h @@ -0,0 +1,73 @@ +/* asm/arch/bitops.h for Linux/CRISv10 */ + +#ifndef _CRIS_ARCH_BITOPS_H +#define _CRIS_ARCH_BITOPS_H + +/* + * Helper functions for the core of the ff[sz] functions, wrapping the + * syntactically awkward asms. The asms compute the number of leading + * zeroes of a bits-in-byte and byte-in-word and word-in-dword-swapped + * number. They differ in that the first function also inverts all bits + * in the input. + */ +extern inline unsigned long cris_swapnwbrlz(unsigned long w) +{ + /* Let's just say we return the result in the same register as the + input. Saying we clobber the input but can return the result + in another register: + ! __asm__ ("swapnwbr %2\n\tlz %2,%0" + ! : "=r,r" (res), "=r,X" (dummy) : "1,0" (w)); + confuses gcc (sched.c, gcc from cris-dist-1.14). */ + + unsigned long res; + __asm__ ("swapnwbr %0 \n\t" + "lz %0,%0" + : "=r" (res) : "0" (w)); + return res; +} + +extern inline unsigned long cris_swapwbrlz(unsigned long w) +{ + unsigned res; + __asm__ ("swapwbr %0 \n\t" + "lz %0,%0" + : "=r" (res) + : "0" (w)); + return res; +} + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +extern inline unsigned long ffz(unsigned long w) +{ + return cris_swapnwbrlz(w); +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +extern __inline__ unsigned long __ffs(unsigned long word) +{ + return cris_swapnwbrlz(~word); +} + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +extern inline unsigned long kernel_ffs(unsigned long w) +{ + return w ? cris_swapwbrlz (w) + 1 : 0; +} + +#endif diff --git a/include/asm-cris/arch-v10/byteorder.h b/include/asm-cris/arch-v10/byteorder.h new file mode 100644 index 00000000000..bac946459b8 --- /dev/null +++ b/include/asm-cris/arch-v10/byteorder.h @@ -0,0 +1,25 @@ +#ifndef _CRIS_ARCH_BYTEORDER_H +#define _CRIS_ARCH_BYTEORDER_H + +#include + +/* we just define these two (as we can do the swap in a single + * asm instruction in CRIS) and the arch-independent files will put + * them together into ntohl etc. + */ + +extern __inline__ __const__ __u32 ___arch__swab32(__u32 x) +{ + __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); + + return(x); +} + +extern __inline__ __const__ __u16 ___arch__swab16(__u16 x) +{ + __asm__ ("swapb %0" : "=r" (x) : "0" (x)); + + return(x); +} + +#endif diff --git a/include/asm-cris/arch-v10/cache.h b/include/asm-cris/arch-v10/cache.h new file mode 100644 index 00000000000..1e796271ea5 --- /dev/null +++ b/include/asm-cris/arch-v10/cache.h @@ -0,0 +1,8 @@ +#ifndef _ASM_ARCH_CACHE_H +#define _ASM_ARCH_CACHE_H + +/* Etrax 100LX have 32-byte cache-lines. */ +#define L1_CACHE_BYTES 32 +#define L1_CACHE_SHIFT_MAX 5 + +#endif /* _ASM_ARCH_CACHE_H */ diff --git a/include/asm-cris/arch-v10/checksum.h b/include/asm-cris/arch-v10/checksum.h new file mode 100644 index 00000000000..fde1d00aaa9 --- /dev/null +++ b/include/asm-cris/arch-v10/checksum.h @@ -0,0 +1,29 @@ +#ifndef _CRIS_ARCH_CHECKSUM_H +#define _CRIS_ARCH_CHECKSUM_H + +/* Checksum some values used in TCP/UDP headers. + * + * The gain by doing this in asm is that C will not generate carry-additions + * for the 32-bit components of the checksum, so otherwise we would have had + * to split all of those into 16-bit components, then add. + */ + +extern inline unsigned int +csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + int res; + __asm__ ("add.d %2, %0\n\t" + "ax\n\t" + "add.d %3, %0\n\t" + "ax\n\t" + "add.d %4, %0\n\t" + "ax\n\t" + "addq 0, %0\n" + : "=r" (res) + : "0" (sum), "r" (daddr), "r" (saddr), "r" ((ntohs(len) << 16) + (proto << 8))); + + return res; +} + +#endif diff --git a/include/asm-cris/arch-v10/delay.h b/include/asm-cris/arch-v10/delay.h new file mode 100644 index 00000000000..cfedae0d2f5 --- /dev/null +++ b/include/asm-cris/arch-v10/delay.h @@ -0,0 +1,20 @@ +#ifndef _CRIS_ARCH_DELAY_H +#define _CRIS_ARCH_DELAY_H + +extern __inline__ void __delay(int loops) +{ + __asm__ __volatile__ ( + "move.d %0,$r9\n\t" + "beq 2f\n\t" + "subq 1,$r9\n\t" + "1:\n\t" + "bne 1b\n\t" + "subq 1,$r9\n" + "2:" + : : "g" (loops) : "r9"); +} + +#endif /* defined(_CRIS_ARCH_DELAY_H) */ + + + diff --git a/include/asm-cris/dma.h b/include/asm-cris/arch-v10/dma.h similarity index 63% copy from include/asm-cris/dma.h copy to include/asm-cris/arch-v10/dma.h index fde1cbf1a80..9e078b9bc93 100644 --- a/include/asm-cris/dma.h +++ b/include/asm-cris/arch-v10/dma.h @@ -1,16 +1,7 @@ -/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - */ +/* Defines for using and allocating dma channels. */ -#ifndef _ASM_DMA_H -#define _ASM_DMA_H - -/* it's useless on the Etrax, but unfortunately needed by the new - bootmem allocator (but this should do it for this) */ - -#define MAX_DMA_ADDRESS PAGE_OFFSET - -/* TODO: check nbr of channels on Etrax-100LX */ +#ifndef _ASM_ARCH_DMA_H +#define _ASM_ARCH_DMA_H #define MAX_DMA_CHANNELS 10 @@ -52,8 +43,4 @@ #define USB_TX_DMA_NBR 8 #define USB_RX_DMA_NBR 9 -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it */ - -#endif /* _ASM_DMA_H */ +#endif diff --git a/include/asm-cris/elf.h b/include/asm-cris/arch-v10/elf.h similarity index 56% copy from include/asm-cris/elf.h copy to include/asm-cris/arch-v10/elf.h index 798aeaeaabd..2a2201ca538 100644 --- a/include/asm-cris/elf.h +++ b/include/asm-cris/arch-v10/elf.h @@ -1,5 +1,5 @@ -#ifndef __ASMCRIS_ELF_H -#define __ASMCRIS_ELF_H +#ifndef __ASMCRIS_ARCH_ELF_H +#define __ASMCRIS_ARCH_ELF_H /* * ELF register definitions.. @@ -7,38 +7,16 @@ #include -typedef unsigned long elf_greg_t; +/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts (a register; assume first param register for CRIS) + contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. -/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is - thus exposed to user-space. */ -#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + A value of 0 tells we have no such handler. */ -/* A placeholder; CRIS does not have any fp regs. */ -typedef unsigned long elf_fpregset_t; - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ( (x)->e_machine == EM_CRIS ) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB; -#define ELF_ARCH EM_CRIS - - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts (a register; assume first param register for CRIS) - contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. - - A value of 0 tells we have no such handler. */ - - /* Explicitly set registers to 0 to increase determinism. */ +/* Explicitly set registers to 0 to increase determinism. */ #define ELF_PLAT_INIT(_r, load_addr) do { \ (_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \ (_r)->r9 = 0; (_r)->r8 = 0; (_r)->r7 = 0; (_r)->r6 = 0; \ @@ -46,8 +24,6 @@ typedef unsigned long elf_fpregset_t; (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ } while (0) -#define USE_ELF_CORE_DUMP - /* The additional layer below is because the stack pointer is missing in the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t, and should be filled in according to the layout of the user_regs_struct @@ -92,30 +68,4 @@ typedef unsigned long elf_fpregset_t; pr_reg[34] = 0; /* csrdata */ -#define ELF_EXEC_PAGESIZE 8192 - -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) - -/* This yields a mask that user programs can use to figure out what - instruction set this CPU supports. This could be done in user space, - but it's not easy, and we've already done it here. */ - -#define ELF_HWCAP (0) - -/* This yields a string that ld.so will use to load implementation - specific libraries for optimization. This is more specific in - intent than poking at uname or /proc/cpuinfo. -*/ - -#define ELF_PLATFORM (NULL) - -#ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) -#endif - #endif diff --git a/include/asm-cris/io.h b/include/asm-cris/arch-v10/io.h similarity index 77% copy from include/asm-cris/io.h copy to include/asm-cris/arch-v10/io.h index 82a06f841c9..0bc38a0313c 100644 --- a/include/asm-cris/io.h +++ b/include/asm-cris/arch-v10/io.h @@ -1,39 +1,9 @@ -#ifndef _ASM_CRIS_IO_H -#define _ASM_CRIS_IO_H +#ifndef _ASM_ARCH_CRIS_IO_H +#define _ASM_ARCH_CRIS_IO_H -#include /* for __va, __pa */ -#include +#include #include -/* Console I/O for simulated etrax100. Use #ifdef so erroneous - use will be evident. */ -#ifdef CONFIG_SVINTO_SIM - /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) \ - asm ("moveq 4,$r9 \n\t" \ - "moveq 2,$r10 \n\t" \ - "move.d %0,$r11 \n\t" \ - "move.d %1,$r12 \n\t" \ - "push $irp \n\t" \ - "move 0f,$irp \n\t" \ - "jump -6809 \n" \ - "0: \n\t" \ - "pop $irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") -#define TRACE_ON() __extension__ \ - ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ - (255)); _Foofoo; }) - -#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) -#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) -#define CRIS_CYCLES() __extension__ \ - ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) -#else /* ! defined CONFIG_SVINTO_SIM */ -/* FIXME: Is there a reliable cycle counter available in some chip? Use - that then. */ -#define CRIS_CYCLES() 0 -#endif /* ! defined CONFIG_SVINTO_SIM */ - /* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ extern unsigned long port_g_data_shadow; @@ -195,71 +165,29 @@ extern volatile unsigned long *port_csp4_addr; #define SOFT_SHUTDOWN() #endif -/* - * Change virtual addresses to physical addresses and vv. - */ - -static inline unsigned long virt_to_phys(volatile void * address) -{ - return __pa(address); -} - -static inline void * phys_to_virt(unsigned long address) -{ - return __va(address); -} - -extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); - -extern inline void * ioremap (unsigned long offset, unsigned long size) -{ - return __ioremap(offset, size, 0); -} - -/* - * IO bus memory addresses are also 1:1 with the physical address - */ -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt - -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the CRIS architecture, we just read/write the - * memory location directly. - */ -#define readb(addr) (*(volatile unsigned char *) (addr)) -#define readw(addr) (*(volatile unsigned short *) (addr)) -#define readl(addr) (*(volatile unsigned int *) (addr)) - -#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) -#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) -#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b)) - -#define memset_io(a,b,c) memset((void *)(a),(b),(c)) -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -/* - * Again, CRIS does not require mem IO specific function. - */ - -#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) - -/* The following is junk needed for the arch-independent code but which - * we never use in the CRIS port - */ +/* Console I/O for simulated etrax100. Use #ifdef so erroneous + use will be evident. */ +#ifdef CONFIG_SVINTO_SIM + /* Let's use the ucsim interface since it lets us do write(2, ...) */ +#define SIMCOUT(s,len) \ + asm ("moveq 4,$r9 \n\t" \ + "moveq 2,$r10 \n\t" \ + "move.d %0,$r11 \n\t" \ + "move.d %1,$r12 \n\t" \ + "push $irp \n\t" \ + "move 0f,$irp \n\t" \ + "jump -6809 \n" \ + "0: \n\t" \ + "pop $irp" \ + : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") +#define TRACE_ON() __extension__ \ + ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ + (255)); _Foofoo; }) -#define IO_SPACE_LIMIT 0xffff -#define inb(x) (0) -#define outb(x,y) -#define outw(x,y) -#define outl(x,y) -#define insb(x,y,z) -#define insw(x,y,z) -#define insl(x,y,z) -#define outsb(x,y,z) -#define outsw(x,y,z) -#define outsl(x,y,z) +#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) +#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) +#define CRIS_CYCLES() __extension__ \ + ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) +#endif /* ! defined CONFIG_SVINTO_SIM */ #endif diff --git a/include/asm-cris/irq.h b/include/asm-cris/arch-v10/irq.h similarity index 92% copy from include/asm-cris/irq.h copy to include/asm-cris/arch-v10/irq.h index 5e4fb8db673..f657c75ddcf 100644 --- a/include/asm-cris/irq.h +++ b/include/asm-cris/arch-v10/irq.h @@ -1,21 +1,11 @@ /* - * Interrupt handling assembler and defines for Linux/CRIS - * - * Copyright (c) 2000, 2001 Axis Communications AB - * - */ - -#ifndef _ASM_IRQ_H -#define _ASM_IRQ_H - -/* - * linux/include/asm-cris/irq.h + * Interrupt handling assembler and defines for Linux/CRISv10 */ -#include -#include +#ifndef _ASM_ARCH_IRQ_H +#define _ASM_ARCH_IRQ_H -#include +#include #define NR_IRQS 32 #define SOME_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, some) /* 0 ? */ @@ -70,16 +60,6 @@ /* usb: controller at irq 31 + uses DMA8 and DMA9 */ #define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb) - - - - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -#define disable_irq_nosync disable_irq -#define enable_irq_nosync enable_irq - /* our fine, global, etrax irq vector! the pointer lives in the head.S file. */ typedef void (*irqvectptr)(void); @@ -92,6 +72,9 @@ extern struct etrax_interrupt_vector *etrax_irv; void set_int_vector(int n, irqvectptr addr, irqvectptr saddr); void set_break_vector(int n, irqvectptr addr); +#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); +#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); + #define __STR(x) #x #define STR(x) __STR(x) @@ -108,7 +91,7 @@ void set_break_vector(int n, irqvectptr addr); "push $r10\n\t" /* push orig_r10 */ \ "clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */ - /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq in irq.c */ + /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq */ #define BLOCK_IRQ(mask,nr) \ "move.d " #mask ",$r0\n\t" \ @@ -190,6 +173,4 @@ __asm__ ( \ "reti\n\t" \ "nop\n"); -#endif /* _ASM_IRQ_H */ - - +#endif diff --git a/include/asm-cris/mmu.h b/include/asm-cris/arch-v10/mmu.h similarity index 54% copy from include/asm-cris/mmu.h copy to include/asm-cris/arch-v10/mmu.h index df2d5ee85c7..d18aa00e50b 100644 --- a/include/asm-cris/mmu.h +++ b/include/asm-cris/arch-v10/mmu.h @@ -2,8 +2,8 @@ * CRIS MMU constants and PTE layout */ -#ifndef _CRIS_MMU_H -#define _CRIS_MMU_H +#ifndef _CRIS_ARCH_MMU_H +#define _CRIS_ARCH_MMU_H /* type used in struct mm to couple an MMU context to an active mm */ @@ -54,9 +54,53 @@ typedef unsigned int mm_context_t; /* Bits the HW doesn't care about but the kernel uses them in SW */ #define _PAGE_PRESENT (1<<4) /* page present in memory */ +#define _PAGE_FILE (1<<5) /* set: pagecache, unset: swap (when !PRESENT) */ #define _PAGE_ACCESSED (1<<5) /* simulated in software using valid bit */ #define _PAGE_MODIFIED (1<<6) /* simulated in software using we bit */ #define _PAGE_READ (1<<7) /* read-enabled */ #define _PAGE_WRITE (1<<8) /* write-enabled */ +/* Define some higher level generic page attributes. */ + +#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED) +#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED) + +#define _PAGE_TABLE (_PAGE_PRESENT | __READABLE | __WRITEABLE) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED) + +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_WRITE | \ + _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | __READABLE) // | _PAGE_COW +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | __READABLE) +#define PAGE_KERNEL __pgprot(_PAGE_GLOBAL | _PAGE_KERNEL | \ + _PAGE_PRESENT | __READABLE | __WRITEABLE) +#define _KERNPG_TABLE (_PAGE_TABLE | _PAGE_KERNEL) + +/* + * CRIS can't do page protection for execute, and considers read the same. + * Also, write permissions imply read permissions. This is the closest we can + * get.. + */ + +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +#define PTE_FILE_MAX_BITS 26 + #endif diff --git a/include/asm-cris/arch-v10/offset.h b/include/asm-cris/arch-v10/offset.h new file mode 100644 index 00000000000..87901a75274 --- /dev/null +++ b/include/asm-cris/arch-v10/offset.h @@ -0,0 +1,33 @@ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ +/* + * DO NOT MODIFY. + * + * This file was generated by arch/cris/Makefile + * + */ + +#define PT_orig_r10 4 /* offsetof(struct pt_regs, orig_r10) */ +#define PT_r13 8 /* offsetof(struct pt_regs, r13) */ +#define PT_r12 12 /* offsetof(struct pt_regs, r12) */ +#define PT_r11 16 /* offsetof(struct pt_regs, r11) */ +#define PT_r10 20 /* offsetof(struct pt_regs, r10) */ +#define PT_r9 24 /* offsetof(struct pt_regs, r9) */ +#define PT_mof 64 /* offsetof(struct pt_regs, mof) */ +#define PT_dccr 68 /* offsetof(struct pt_regs, dccr) */ +#define PT_srp 72 /* offsetof(struct pt_regs, srp) */ + +#define TI_task 0 /* offsetof(struct thread_info, task) */ +#define TI_flags 8 /* offsetof(struct thread_info, flags) */ +#define TI_preempt_count 16 /* offsetof(struct thread_info, preempt_count) */ + +#define THREAD_ksp 0 /* offsetof(struct thread_struct, ksp) */ +#define THREAD_usp 4 /* offsetof(struct thread_struct, usp) */ +#define THREAD_dccr 8 /* offsetof(struct thread_struct, dccr) */ + +#define TASK_pid 121 /* offsetof(struct task_struct, pid) */ + +#define LCLONE_VM 256 /* CLONE_VM */ +#define LCLONE_UNTRACED 8388608 /* CLONE_UNTRACED */ + +#endif diff --git a/include/asm-cris/arch-v10/page.h b/include/asm-cris/arch-v10/page.h new file mode 100644 index 00000000000..407e6e68f49 --- /dev/null +++ b/include/asm-cris/arch-v10/page.h @@ -0,0 +1,31 @@ +#ifndef _CRIS_ARCH_PAGE_H +#define _CRIS_ARCH_PAGE_H + +#include + +#ifdef __KERNEL__ + +/* This handles the memory map.. */ +#ifdef CONFIG_CRIS_LOW_MAP +#define PAGE_OFFSET KSEG_6 /* kseg_6 is mapped to physical ram */ +#else +#define PAGE_OFFSET KSEG_C /* kseg_c is mapped to physical ram */ +#endif + +/* macros to convert between really physical and virtual addresses + * by stripping a selected bit, we can convert between KSEG_x and 0x40000000 where + * the DRAM really resides + */ + +#ifdef CONFIG_CRIS_LOW_MAP +/* we have DRAM virtually at 0x6 */ +#define __pa(x) ((unsigned long)(x) & 0xdfffffff) +#define __va(x) ((void *)((unsigned long)(x) | 0x20000000)) +#else +/* we have DRAM virtually at 0xc */ +#define __pa(x) ((unsigned long)(x) & 0x7fffffff) +#define __va(x) ((void *)((unsigned long)(x) | 0x80000000)) +#endif + +#endif +#endif diff --git a/include/asm-cris/arch-v10/pgtable.h b/include/asm-cris/arch-v10/pgtable.h new file mode 100644 index 00000000000..65eecd1e653 --- /dev/null +++ b/include/asm-cris/arch-v10/pgtable.h @@ -0,0 +1,19 @@ +#ifndef _CRIS_ARCH_PGTABLE_H +#define _CRIS_ARCH_PGTABLE_H + +/* + * Kernels own virtual memory area. + */ + +#ifdef CONFIG_CRIS_LOW_MAP +#define VMALLOC_START KSEG_7 +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END KSEG_8 +#else +#define VMALLOC_START KSEG_D +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END KSEG_E +#endif + +#endif + diff --git a/include/asm-cris/arch-v10/processor.h b/include/asm-cris/arch-v10/processor.h new file mode 100644 index 00000000000..9355d8675a5 --- /dev/null +++ b/include/asm-cris/arch-v10/processor.h @@ -0,0 +1,62 @@ +#ifndef __ASM_CRIS_ARCH_PROCESSOR_H +#define __ASM_CRIS_ARCH_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({void *pc; __asm__ ("move.d $pc,%0" : "=rm" (pc)); pc; }) + +/* CRIS has no problems with write protection */ +#define wp_works_ok 1 + +/* CRIS thread_struct. this really has nothing to do with the processor itself, since + * CRIS does not do any hardware task-switching, but it's here for legacy reasons. + * The thread_struct here is used when task-switching using _resume defined in entry.S. + * The offsets here are hardcoded into _resume - if you change this struct, you need to + * change them as well!!! +*/ + +struct thread_struct { + unsigned long ksp; /* kernel stack pointer */ + unsigned long usp; /* user stack pointer */ + unsigned long dccr; /* saved flag register */ +}; + +/* + * User space process size. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ + +#ifdef CONFIG_CRIS_LOW_MAP +#define TASK_SIZE (0x50000000UL) /* 1.25 GB */ +#else +#define TASK_SIZE (0xA0000000UL) /* 2.56 GB */ +#endif + +#define INIT_THREAD { \ + 0, 0, 0x20 } /* ccr = int enable, nothing else */ + +#define KSTK_EIP(tsk) \ +({ \ + unsigned long eip = 0; \ + unsigned long regs = (unsigned long)user_regs(tsk); \ + if (regs > PAGE_SIZE && \ + virt_addr_valid(regs)) \ + eip = ((struct pt_regs *)regs)->irp; \ + eip; \ +}) + +/* give the thread a program location + * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) + * switch user-stackpointer + */ + +#define start_thread(regs, ip, usp) do { \ + set_fs(USER_DS); \ + regs->irp = ip; \ + regs->dccr |= 1 << U_DCCR_BITNR; \ + wrusp(usp); \ +} while(0) + +#endif diff --git a/include/asm-cris/ptrace.h b/include/asm-cris/arch-v10/ptrace.h similarity index 92% copy from include/asm-cris/ptrace.h copy to include/asm-cris/arch-v10/ptrace.h index b7391cc079d..939d9846477 100644 --- a/include/asm-cris/ptrace.h +++ b/include/asm-cris/arch-v10/ptrace.h @@ -1,5 +1,11 @@ -#ifndef _CRIS_PTRACE_H -#define _CRIS_PTRACE_H +#ifndef _CRIS_ARCH_PTRACE_H +#define _CRIS_ARCH_PTRACE_H + +/* Frame types */ + +#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ +#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return + path */ /* Register numbers in the ptrace system call interface */ @@ -44,12 +50,6 @@ #define P_DCCR_BITNR 9 #define F_DCCR_BITNR 10 -/* Frame types */ - -#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ -#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return - path */ - /* pt_regs not only specifices the format in the user-struct during * ptrace but is also the frame format used in the kernel prologue/epilogues * themselves @@ -106,15 +106,9 @@ struct switch_stack { unsigned long return_ip; /* ip that _resume will return to */ }; -#ifdef __KERNEL__ -/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 - /* bit 8 is user-mode flag */ #define user_mode(regs) (((regs)->dccr & 0x100) != 0) #define instruction_pointer(regs) ((regs)->irp) extern void show_regs(struct pt_regs *); -#endif -#endif /* _CRIS_PTRACE_H */ +#endif diff --git a/include/asm-cris/sv_addr.agh b/include/asm-cris/arch-v10/sv_addr.agh similarity index 99% rename from include/asm-cris/sv_addr.agh rename to include/asm-cris/arch-v10/sv_addr.agh index ddaf91fa38c..6ac3a7bc976 100644 --- a/include/asm-cris/sv_addr.agh +++ b/include/asm-cris/arch-v10/sv_addr.agh @@ -691,10 +691,10 @@ #define R_GEN_CONFIG__g24dir__WIDTH 1 #define R_GEN_CONFIG__g24dir__in 0 #define R_GEN_CONFIG__g24dir__out 1 -#define R_GEN_CONFIG__g16_20dir__BITNR 26 -#define R_GEN_CONFIG__g16_20dir__WIDTH 1 -#define R_GEN_CONFIG__g16_20dir__in 0 -#define R_GEN_CONFIG__g16_20dir__out 1 +#define R_GEN_CONFIG__g16_23dir__BITNR 26 +#define R_GEN_CONFIG__g16_23dir__WIDTH 1 +#define R_GEN_CONFIG__g16_23dir__in 0 +#define R_GEN_CONFIG__g16_23dir__out 1 #define R_GEN_CONFIG__g8_15dir__BITNR 25 #define R_GEN_CONFIG__g8_15dir__WIDTH 1 #define R_GEN_CONFIG__g8_15dir__in 0 @@ -1142,7 +1142,7 @@ #define R_SERIAL0_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL0_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_CTRL__rec_stick_par__stick 1 #define R_SERIAL0_CTRL__rec_par__BITNR 18 #define R_SERIAL0_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_par__even 0 @@ -1172,7 +1172,7 @@ #define R_SERIAL0_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL0_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_CTRL__tr_stick_par__stick 1 #define R_SERIAL0_CTRL__tr_par__BITNR 10 #define R_SERIAL0_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_par__even 0 @@ -1246,7 +1246,7 @@ #define R_SERIAL0_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL0_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL0_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL0_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_par__even 0 @@ -1278,7 +1278,7 @@ #define R_SERIAL0_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL0_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL0_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL0_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_par__even 0 @@ -1434,7 +1434,7 @@ #define R_SERIAL1_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL1_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_CTRL__rec_stick_par__stick 1 #define R_SERIAL1_CTRL__rec_par__BITNR 18 #define R_SERIAL1_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_par__even 0 @@ -1464,7 +1464,7 @@ #define R_SERIAL1_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL1_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_CTRL__tr_stick_par__stick 1 #define R_SERIAL1_CTRL__tr_par__BITNR 10 #define R_SERIAL1_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_par__even 0 @@ -1538,7 +1538,7 @@ #define R_SERIAL1_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL1_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL1_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL1_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_par__even 0 @@ -1570,7 +1570,7 @@ #define R_SERIAL1_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL1_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL1_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL1_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_par__even 0 @@ -1726,7 +1726,7 @@ #define R_SERIAL2_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL2_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_CTRL__rec_stick_par__stick 1 #define R_SERIAL2_CTRL__rec_par__BITNR 18 #define R_SERIAL2_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_par__even 0 @@ -1756,7 +1756,7 @@ #define R_SERIAL2_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL2_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_CTRL__tr_stick_par__stick 1 #define R_SERIAL2_CTRL__tr_par__BITNR 10 #define R_SERIAL2_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_par__even 0 @@ -1830,7 +1830,7 @@ #define R_SERIAL2_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL2_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL2_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL2_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_par__even 0 @@ -1862,7 +1862,7 @@ #define R_SERIAL2_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL2_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL2_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL2_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_par__even 0 @@ -2018,7 +2018,7 @@ #define R_SERIAL3_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL3_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_CTRL__rec_stick_par__stick 1 #define R_SERIAL3_CTRL__rec_par__BITNR 18 #define R_SERIAL3_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_par__even 0 @@ -2048,7 +2048,7 @@ #define R_SERIAL3_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL3_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_CTRL__tr_stick_par__stick 1 #define R_SERIAL3_CTRL__tr_par__BITNR 10 #define R_SERIAL3_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_par__even 0 @@ -2122,7 +2122,7 @@ #define R_SERIAL3_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL3_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL3_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL3_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_par__even 0 @@ -2154,7 +2154,7 @@ #define R_SERIAL3_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL3_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL3_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL3_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_par__even 0 diff --git a/include/asm-cris/sv_addr_ag.h b/include/asm-cris/arch-v10/sv_addr_ag.h similarity index 76% rename from include/asm-cris/sv_addr_ag.h rename to include/asm-cris/arch-v10/sv_addr_ag.h index c80826bf941..e4a6b68b898 100644 --- a/include/asm-cris/sv_addr_ag.h +++ b/include/asm-cris/arch-v10/sv_addr_ag.h @@ -25,33 +25,41 @@ /* IO_MASK returns a mask for a specified bitfield in a register. Note that this macro doesn't work when field width is 32 bits. */ -#define IO_MASK(reg,field) \ - ( ( ( 1 << reg##__##field##__WIDTH ) - 1 ) << reg##__##field##__BITNR ) +#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_) +#define IO_MASK_(reg_, field_) \ + ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR ) /* IO_STATE returns a constant corresponding to a one of the symbolic states that the bitfield can have. (Shifted to correct position) */ -#define IO_STATE(reg,field,state) \ - ( reg##__##field##__##state << reg##__##field##__BITNR ) +#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state) +#define IO_STATE_(reg_, field_, _state) \ + ( reg_##_##field_##_state << reg_##_##field_##_BITNR ) /* IO_EXTRACT returns the masked and shifted value corresponding to the bitfield can have. */ -#define IO_EXTRACT(reg,field,val) ( (( ( ( 1 << reg##__##field##__WIDTH ) \ - - 1 ) << reg##__##field##__BITNR ) & (val)) >> reg##__##field##__BITNR ) +#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val) +#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \ + - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR ) /* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic states that the bitfield can have. (Not shifted) */ -#define IO_STATE_VALUE(reg,field,state) ( reg##__##field##__##state ) +#define IO_STATE_VALUE(reg, field, state) \ + IO_STATE_VALUE_ (reg##_, field##_, _##state) +#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state ) /* IO_FIELD shifts the val parameter to be aligned with the bitfield specified. */ -#define IO_FIELD(reg,field,val) ((val) << reg##__##field##__BITNR) +#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val) +#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR) /* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is LSB and the returned bitnumber is LSB of the field. */ -#define IO_BITNR(reg,field) (reg##__##field##__BITNR) +#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_) +#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR) /* IO_WIDTH returns the width, in bits, of a bitfield. */ -#define IO_WIDTH(reg,field) (reg##__##field##__WIDTH) +#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_) +#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH) /*--- Obsolete. Kept for backw compatibility. ---*/ /* Reads (or writes) a byte/uword/udword from the specified mode @@ -66,7 +74,9 @@ !*-----------------------------------------------------------*/ #define MEM_CSE0_START (0x00000000) +#define MEM_CSE0_SIZE (0x04000000) #define MEM_CSE1_START (0x04000000) +#define MEM_CSE1_SIZE (0x04000000) #define MEM_CSR0_START (0x08000000) #define MEM_CSR1_START (0x0c000000) #define MEM_CSP0_START (0x10000000) diff --git a/include/asm-cris/svinto.h b/include/asm-cris/arch-v10/svinto.h similarity index 95% rename from include/asm-cris/svinto.h rename to include/asm-cris/arch-v10/svinto.h index c0a16650a20..0881a1af7ce 100644 --- a/include/asm-cris/svinto.h +++ b/include/asm-cris/arch-v10/svinto.h @@ -58,4 +58,7 @@ typedef struct etrax_dma_descr { */ #define WAIT_DMA( n ) WAIT_DMA_NUM( n ) +extern void prepare_rx_descriptor(struct etrax_dma_descr *desc); +extern void flush_etrax_cache(void); + #endif diff --git a/include/asm-cris/arch-v10/system.h b/include/asm-cris/arch-v10/system.h new file mode 100644 index 00000000000..781ca30229a --- /dev/null +++ b/include/asm-cris/arch-v10/system.h @@ -0,0 +1,62 @@ +#ifndef __ASM_CRIS_ARCH_SYSTEM_H +#define __ASM_CRIS_ARCH_SYSTEM_H + +#include + +/* read the CPU version register */ + +extern inline unsigned long rdvr(void) { + unsigned char vr; + __asm__ volatile ("move $vr,%0" : "=rm" (vr)); + return vr; +} + +/* read/write the user-mode stackpointer */ + +extern inline unsigned long rdusp(void) { + unsigned long usp; + __asm__ __volatile__("move $usp,%0" : "=rm" (usp)); + return usp; +} + +#define wrusp(usp) \ + __asm__ __volatile__("move %0,$usp" : /* no outputs */ : "rm" (usp)) + +/* read the current stackpointer */ + +extern inline unsigned long rdsp(void) { + unsigned long sp; + __asm__ __volatile__("move.d $sp,%0" : "=rm" (sp)); + return sp; +} + +extern inline unsigned long _get_base(char * addr) +{ + return 0; +} + +#define nop() __asm__ __volatile__ ("nop"); + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* interrupt control.. */ +#define local_save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); +#define local_irq_restore(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); +#define local_irq_disable() __asm__ __volatile__ ( "di" : : :"memory"); +#define local_irq_enable() __asm__ __volatile__ ( "ei" : : :"memory"); + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + !(flags & (1<<5)); \ +}) + +/* For spinlocks etc */ +#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); + +#endif diff --git a/include/asm-cris/arch-v10/thread_info.h b/include/asm-cris/arch-v10/thread_info.h new file mode 100644 index 00000000000..357f5df0c90 --- /dev/null +++ b/include/asm-cris/arch-v10/thread_info.h @@ -0,0 +1,12 @@ +#ifndef _ASM_ARCH_THREAD_INFO_H +#define _ASM_ARCH_THREAD_INFO_H + +/* how to get the thread information struct from C */ +extern inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + __asm__("and.d $sp,%0; ":"=r" (ti) : "0" (~8191UL)); + return ti; +} + +#endif diff --git a/include/asm-cris/arch-v10/timex.h b/include/asm-cris/arch-v10/timex.h new file mode 100644 index 00000000000..ecfc553c06a --- /dev/null +++ b/include/asm-cris/arch-v10/timex.h @@ -0,0 +1,30 @@ +/* + * Use prescale timer at 25000 Hz instead of the baudrate timer at + * 19200 to get rid of the 64ppm to fast timer (and we get better + * resolution within a jiffie as well. + */ +#ifndef _ASM_CRIS_ARCH_TIMEX_H +#define _ASM_CRIS_ARCH_TIMEX_H + +/* The prescaler clock runs at 25MHz, we divide it by 1000 in the prescaler */ +/* If you change anything here you must check time.c as well... */ +#define PRESCALE_FREQ 25000000 +#define PRESCALE_VALUE 1000 +#define CLOCK_TICK_RATE 25000 /* Underlying frequency of the HZ timer */ +/* The timer0 values gives 40us resolution (1/25000) but interrupts at HZ*/ +#define TIMER0_FREQ (CLOCK_TICK_RATE) +#define TIMER0_CLKSEL flexible +#define TIMER0_DIV (TIMER0_FREQ/(HZ)) + + +#define GET_JIFFIES_USEC() \ + ( (TIMER0_DIV - *R_TIMER0_DATA) * (1000000/HZ)/TIMER0_DIV ) + +unsigned long get_ns_in_jiffie(void); + +extern inline unsigned long get_us_in_jiffie_highres(void) +{ + return get_ns_in_jiffie()/1000; +} + +#endif diff --git a/include/asm-cris/arch-v10/tlb.h b/include/asm-cris/arch-v10/tlb.h new file mode 100644 index 00000000000..31525bbe75c --- /dev/null +++ b/include/asm-cris/arch-v10/tlb.h @@ -0,0 +1,13 @@ +#ifndef _CRIS_ARCH_TLB_H +#define _CRIS_ARCH_TLB_H + +/* The TLB can host up to 64 different mm contexts at the same time. + * The last page_id is never running - it is used as an invalid page_id + * so we can make TLB entries that will never match. + */ +#define NUM_TLB_ENTRIES 64 +#define NUM_PAGEID 64 +#define INVALID_PAGEID 63 +#define NO_CONTEXT -1 + +#endif diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/arch-v10/uaccess.h similarity index 58% copy from include/asm-cris/uaccess.h copy to include/asm-cris/arch-v10/uaccess.h index 41d66748c16..787d2e60c83 100644 --- a/include/asm-cris/uaccess.h +++ b/include/asm-cris/arch-v10/uaccess.h @@ -2,183 +2,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * Hans-Peter Nilsson (hp@axis.com) * - * $Log: uaccess.h,v $ - * Revision 1.8 2001/10/29 13:01:48 bjornw - * Removed unused variable tmp2 in strnlen_user - * - * Revision 1.7 2001/10/02 12:44:52 hp - * Add support for 64-bit put_user/get_user - * - * Revision 1.6 2001/10/01 14:51:17 bjornw - * Added register prefixes and removed underscores - * - * Revision 1.5 2000/10/25 03:33:21 hp - * - Provide implementation for everything else but get_user and put_user; - * copying inline to/from user for constant length 0..16, 20, 24, and - * clearing for 0..4, 8, 12, 16, 20, 24, strncpy_from_user and strnlen_user - * always inline. - * - Constraints for destination addr in get_user cannot be memory, only reg. - * - Correct labels for PC at expected fault points. - * - Nits with assembly code. - * - Don't use statement expressions without value; use "do {} while (0)". - * - Return correct values from __generic_... functions. - * - * Revision 1.4 2000/09/12 16:28:25 bjornw - * * Removed comments from the get/put user asm code - * * Constrains for destination addr in put_user cannot be memory, only reg - * - * Revision 1.3 2000/09/12 14:30:20 bjornw - * MAX_ADDR_USER does not exist anymore - * - * Revision 1.2 2000/07/13 15:52:48 bjornw - * New user-access functions - * - * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw - * CRIS architecture, working draft - * - * - * */ - -/* Asm:s have been tweaked (within the domain of correctness) to give - satisfactory results for "gcc version 2.96 20000427 (experimental)". - - Check regularly... - - Register $r9 is chosen for temporaries, being a call-clobbered register - first in line to be used (notably for local blocks), not colliding with - parameter registers. */ - -#ifndef _CRIS_UACCESS_H -#define _CRIS_UACCESS_H - -#ifndef __ASSEMBLY__ -#include -#include -#include -#include - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ - -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -/* addr_limit is the maximum accessible address for the task. we misuse - * the KERNEL_DS and USER_DS values to both assign and compare the - * addr_limit values through the equally misnamed get/set_fs macros. - * (see above) - */ - -#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) -#define USER_DS MAKE_MM_SEG(TASK_SIZE) - -#define get_ds() (KERNEL_DS) -#define get_fs() (current->addr_limit) -#define set_fs(x) (current->addr_limit = (x)) - -#define segment_eq(a,b) ((a).seg == (b).seg) - -#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) -#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size))) -#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) -#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) - -extern inline int verify_area(int type, const void * addr, unsigned long size) -{ - return access_ok(type,addr,size) ? 0 : -EFAULT; -} - - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry -{ - unsigned long insn, fixup; -}; - -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * This gets kind of ugly. We want to return _two_ values in "get_user()" - * and yet we don't want to do any pointers, because that is too much - * of a performance impact. Thus we have a few rather ugly macros here, - * and hide all the ugliness from the user. - * - * The "__xxx" versions of the user access functions are versions that - * do not verify the address space, that must have been done previously - * with a separate "access_ok()" call (this is used when we do multiple - * accesses to the same area of user memory). - * - * As we use the same address space for kernel and user data on - * CRIS, we can just do these as direct assignments. (Of course, the - * exception handling means that it's no longer "just"...) - */ -#define get_user(x,ptr) \ - __get_user_check((x),(ptr),sizeof(*(ptr))) -#define put_user(x,ptr) \ - __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) - -#define __get_user(x,ptr) \ - __get_user_nocheck((x),(ptr),sizeof(*(ptr))) -#define __put_user(x,ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) - -extern long __put_user_bad(void); - -#define __put_user_nocheck(x,ptr,size) \ -({ \ - long __pu_err; \ - __put_user_size((x),(ptr),(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_check(x,ptr,size) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ - __put_user_size((x),__pu_addr,(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __put_user_asm_64(x,ptr,retval); break; \ - default: __put_user_bad(); \ - } \ -} while (0) - -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct *)(x)) +#ifndef _CRIS_ARCH_UACCESS_H +#define _CRIS_ARCH_UACCESS_H /* * We don't tell gcc that we are accessing memory, but this is OK @@ -218,39 +44,6 @@ struct __large_struct { unsigned long buf[100]; }; : "=r" (err) \ : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) - -#define __get_user_nocheck(x,ptr,size) \ -({ \ - long __gu_err, __gu_val; \ - __get_user_size(__gu_val,(ptr),(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_check(x,ptr,size) \ -({ \ - long __gu_err = -EFAULT, __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - if (access_ok(VERIFY_READ,__gu_addr,size)) \ - __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -extern long __get_user_bad(void); - -#define __get_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __get_user_asm_64(x,ptr,retval); break; \ - default: (x) = __get_user_bad(); \ - } \ -} while (0) - /* See comment before __put_user_asm. */ #define __get_user_asm(x, addr, err, op) \ @@ -285,13 +78,6 @@ do { \ : "=r" (err), "=r" (x) \ : "r" (addr), "g" (-EFAULT), "0" (err)) -/* More complex functions. Most are inline, but some call functions that - live in lib/usercopy.c */ - -extern unsigned long __copy_user(void *to, const void *from, unsigned long n); -extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n); -extern unsigned long __do_clear_user(void *to, unsigned long n); - /* * Copy a null terminated string from userspace. * @@ -301,8 +87,7 @@ extern unsigned long __do_clear_user(void *to, unsigned long n); * bytes copied if we hit a null byte * (without the null byte) */ - -static inline long +extern inline long __do_strncpy_from_user(char *dst, const char *src, long count) { long res; @@ -362,45 +147,6 @@ __do_strncpy_from_user(char *dst, const char *src, long count) return res; } -static inline unsigned long -__generic_copy_to_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - return __copy_user(to,from,n); - return n; -} - -static inline unsigned long -__generic_copy_from_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_READ, from, n)) - return __copy_user_zeroing(to,from,n); - return n; -} - -static inline unsigned long -__generic_clear_user(void *to, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - return __do_clear_user(to,n); - return n; -} - -static inline long -__strncpy_from_user(char *dst, const char *src, long count) -{ - return __do_strncpy_from_user(dst, src, count); -} - -static inline long -strncpy_from_user(char *dst, const char *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - res = __do_strncpy_from_user(dst, src, count); - return res; -} - /* A few copy asms to build up the more complex ones from. Note again, a post-increment is performed regardless of whether a bus @@ -772,7 +518,7 @@ strncpy_from_user(char *dst, const char *src, long count) " .previous" \ : "=r" (to), "=r" (ret) \ : "0" (to), "1" (ret) \ - : "r9", "memory") + : "memory") #define __asm_clear_1(to, ret) \ __asm_clear(to, ret, \ @@ -849,183 +595,6 @@ strncpy_from_user(char *dst, const char *src, long count) #define __asm_clear_24(to, ret) \ __asm_clear_24x_cont(to, ret, "", "", "") -/* Note that if these expand awfully if made into switch constructs, so - don't do that. */ - -static inline unsigned long -__constant_copy_from_user(void *to, const void *from, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_copy_from_user_1(to, from, ret); - else if (n == 2) - __asm_copy_from_user_2(to, from, ret); - else if (n == 3) - __asm_copy_from_user_3(to, from, ret); - else if (n == 4) - __asm_copy_from_user_4(to, from, ret); - else if (n == 5) - __asm_copy_from_user_5(to, from, ret); - else if (n == 6) - __asm_copy_from_user_6(to, from, ret); - else if (n == 7) - __asm_copy_from_user_7(to, from, ret); - else if (n == 8) - __asm_copy_from_user_8(to, from, ret); - else if (n == 9) - __asm_copy_from_user_9(to, from, ret); - else if (n == 10) - __asm_copy_from_user_10(to, from, ret); - else if (n == 11) - __asm_copy_from_user_11(to, from, ret); - else if (n == 12) - __asm_copy_from_user_12(to, from, ret); - else if (n == 13) - __asm_copy_from_user_13(to, from, ret); - else if (n == 14) - __asm_copy_from_user_14(to, from, ret); - else if (n == 15) - __asm_copy_from_user_15(to, from, ret); - else if (n == 16) - __asm_copy_from_user_16(to, from, ret); - else if (n == 20) - __asm_copy_from_user_20(to, from, ret); - else if (n == 24) - __asm_copy_from_user_24(to, from, ret); - else - ret = __generic_copy_from_user(to, from, n); - - return ret; -} - -/* Ditto, don't make a switch out of this. */ - -static inline unsigned long -__constant_copy_to_user(void *to, const void *from, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_copy_to_user_1(to, from, ret); - else if (n == 2) - __asm_copy_to_user_2(to, from, ret); - else if (n == 3) - __asm_copy_to_user_3(to, from, ret); - else if (n == 4) - __asm_copy_to_user_4(to, from, ret); - else if (n == 5) - __asm_copy_to_user_5(to, from, ret); - else if (n == 6) - __asm_copy_to_user_6(to, from, ret); - else if (n == 7) - __asm_copy_to_user_7(to, from, ret); - else if (n == 8) - __asm_copy_to_user_8(to, from, ret); - else if (n == 9) - __asm_copy_to_user_9(to, from, ret); - else if (n == 10) - __asm_copy_to_user_10(to, from, ret); - else if (n == 11) - __asm_copy_to_user_11(to, from, ret); - else if (n == 12) - __asm_copy_to_user_12(to, from, ret); - else if (n == 13) - __asm_copy_to_user_13(to, from, ret); - else if (n == 14) - __asm_copy_to_user_14(to, from, ret); - else if (n == 15) - __asm_copy_to_user_15(to, from, ret); - else if (n == 16) - __asm_copy_to_user_16(to, from, ret); - else if (n == 20) - __asm_copy_to_user_20(to, from, ret); - else if (n == 24) - __asm_copy_to_user_24(to, from, ret); - else - ret = __generic_copy_to_user(to, from, n); - - return ret; -} - -/* No switch, please. */ - -static inline unsigned long -__constant_clear_user(void *to, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_clear_1(to, ret); - else if (n == 2) - __asm_clear_2(to, ret); - else if (n == 3) - __asm_clear_3(to, ret); - else if (n == 4) - __asm_clear_4(to, ret); - else if (n == 8) - __asm_clear_8(to, ret); - else if (n == 12) - __asm_clear_12(to, ret); - else if (n == 16) - __asm_clear_16(to, ret); - else if (n == 20) - __asm_clear_20(to, ret); - else if (n == 24) - __asm_clear_24(to, ret); - else - ret = __generic_clear_user(to, n); - - return ret; -} - - -#define clear_user(to, n) \ -(__builtin_constant_p(n) ? \ - __constant_clear_user(to, n) : \ - __generic_clear_user(to, n)) - -#define copy_from_user(to, from, n) \ -(__builtin_constant_p(n) ? \ - __constant_copy_from_user(to, from, n) : \ - __generic_copy_from_user(to, from, n)) - -#define copy_to_user(to, from, n) \ -(__builtin_constant_p(n) ? \ - __constant_copy_to_user(to, from, n) : \ - __generic_copy_to_user(to, from, n)) - -/* We let the __ versions of copy_from/to_user inline, because they're often - * used in fast paths and have only a small space overhead. - */ - -static inline unsigned long -__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) -{ - return __copy_user_zeroing(to,from,n); -} - -static inline unsigned long -__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) -{ - return __copy_user(to,from,n); -} - -static inline unsigned long -__generic_clear_user_nocheck(void *to, unsigned long n) -{ - return __do_clear_user(to,n); -} - -/* without checking */ - -#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n)) -#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) -#define __clear_user(to,n) __generic_clear_user_nocheck((to),(n)) - /* * Return the size of a string (including the ending 0) * @@ -1033,7 +602,7 @@ __generic_clear_user_nocheck(void *to, unsigned long n) * or 0 for error. Return a value greater than N if too long. */ -static inline long +extern inline long strnlen_user(const char *s, long n) { long res, tmp1; @@ -1088,8 +657,4 @@ strnlen_user(const char *s, long n) return res; } -#define strlen_user(str) strnlen_user((str), 0x7ffffffe) - -#endif /* __ASSEMBLY__ */ - -#endif /* _CRIS_UACCESS_H */ +#endif diff --git a/include/asm-cris/arch-v10/unistd.h b/include/asm-cris/arch-v10/unistd.h new file mode 100644 index 00000000000..d1a38b9e626 --- /dev/null +++ b/include/asm-cris/arch-v10/unistd.h @@ -0,0 +1,148 @@ +#ifndef _ASM_CRIS_ARCH_UNISTD_H_ +#define _ASM_CRIS_ARCH_UNISTD_H_ + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +/* + * Don't remove the .ifnc tests; they are an insurance against + * any hard-to-spot gcc register allocation bugs. + */ +#define _syscall0(type,name) \ +type name(void) \ +{ \ + register long __a __asm__ ("r10"); \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3,$r10$r9$r11\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4,$r10$r9$r11$r12\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), "r" (__c)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "move %6,$mof\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "move %6,$mof\n\tmove %7,$srp\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\ + : "srp"); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#endif diff --git a/include/asm-cris/arch-v10/user.h b/include/asm-cris/arch-v10/user.h new file mode 100644 index 00000000000..9303ea77c91 --- /dev/null +++ b/include/asm-cris/arch-v10/user.h @@ -0,0 +1,46 @@ +#ifndef __ASM_CRIS_ARCH_USER_H +#define __ASM_CRIS_ARCH_USER_H + +/* User mode registers, used for core dumps. In order to keep ELF_NGREG + sensible we let all registers be 32 bits. The csr registers are included + for future use. */ +struct user_regs_struct { + unsigned long r0; /* General registers. */ + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long sp; /* Stack pointer. */ + unsigned long pc; /* Program counter. */ + unsigned long p0; /* Constant zero (only 8 bits). */ + unsigned long vr; /* Version register (only 8 bits). */ + unsigned long p2; /* Reserved. */ + unsigned long p3; /* Reserved. */ + unsigned long p4; /* Constant zero (only 16 bits). */ + unsigned long ccr; /* Condition code register (only 16 bits). */ + unsigned long p6; /* Reserved. */ + unsigned long mof; /* Multiply overflow register. */ + unsigned long p8; /* Constant zero. */ + unsigned long ibr; /* Not accessible. */ + unsigned long irp; /* Not accessible. */ + unsigned long srp; /* Subroutine return pointer. */ + unsigned long bar; /* Not accessible. */ + unsigned long dccr; /* Dword condition code register. */ + unsigned long brp; /* Not accessible. */ + unsigned long usp; /* User-mode stack pointer. Same as sp when + in user mode. */ + unsigned long csrinstr; /* Internal status registers. */ + unsigned long csraddr; + unsigned long csrdata; +}; + +#endif diff --git a/include/asm-cris/atomic.h b/include/asm-cris/atomic.h index f2f51505d6d..19ae993cb56 100644 --- a/include/asm-cris/atomic.h +++ b/include/asm-cris/atomic.h @@ -27,115 +27,115 @@ typedef struct { int counter; } atomic_t; /* These should be written in asm but we do it in C for now. */ -static __inline__ void atomic_add(int i, volatile atomic_t *v) +extern __inline__ void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); v->counter += i; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ void atomic_sub(int i, volatile atomic_t *v) +extern __inline__ void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); v->counter -= i; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ int atomic_add_return(int i, volatile atomic_t *v) +extern __inline__ int atomic_add_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter += i); - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_sub_return(int i, volatile atomic_t *v) +extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter -= i); - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) +extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter -= i) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ void atomic_inc(volatile atomic_t *v) +extern __inline__ void atomic_inc(volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); (v->counter)++; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ void atomic_dec(volatile atomic_t *v) +extern __inline__ void atomic_dec(volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); (v->counter)--; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ int atomic_inc_return(volatile atomic_t *v) +extern __inline__ int atomic_inc_return(volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter)++; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_dec_return(volatile atomic_t *v) +extern __inline__ int atomic_dec_return(volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter)--; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_dec_and_test(volatile atomic_t *v) +extern __inline__ int atomic_dec_and_test(volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = --(v->counter) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_inc_and_test(volatile atomic_t *v) +extern __inline__ int atomic_inc_and_test(volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = ++(v->counter) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } diff --git a/include/asm-cris/axisflashmap.h b/include/asm-cris/axisflashmap.h index c54f65d4a4a..600bb8715d8 100644 --- a/include/asm-cris/axisflashmap.h +++ b/include/asm-cris/axisflashmap.h @@ -9,25 +9,6 @@ * and it has nothing to do with the partition table. */ - -/* the partitiontable consists of some "jump over" code, a head and - * then the actual entries. - * tools/mkptable is used to generate the ptable. - */ - -/* The partition table starts with code to "jump over" it. The ba - instruction and delay-slot is modified elsewhere (for example the - mkptable script); don't change this to fill the delay-slot. */ -#define PARTITIONTABLE_CODE_START { \ - 0x0f, 0x05, /* nop 0 */\ - 0x25, 0xf0, /* di 2 */\ - 0xed, 0xff /* ba 4 */ } - -/* The actual offset depend on the number of entries */ -#define PARTITIONTABLE_CODE_END { \ - 0x00, 0x00, /* ba offset 6 */\ - 0x0f, 0x05 /* nop 8 */} - #define PARTITION_TABLE_OFFSET 10 #define PARTITION_TABLE_MAGIC 0xbeef /* Not a good magic */ diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h index 563cc9f6a99..10de1ccd1e0 100644 --- a/include/asm-cris/bitops.h +++ b/include/asm-cris/bitops.h @@ -1,9 +1,6 @@ /* asm/bitops.h for Linux/CRIS * * TODO: asm versions if speed is needed - * set_bit, clear_bit and change_bit wastes cycles being only - * macros into test_and_set_bit etc. - * kernel-doc things (**) for macros are disabled * * All bit operations return 0 if the bit was cleared before the * operation and != 0 if it was not. @@ -17,11 +14,8 @@ /* Currently this is unsuitable for consumption outside the kernel. */ #ifdef __KERNEL__ +#include #include - -/* We use generic_ffs so get it; include guards resolve the possible - mutually inclusion. */ -#include #include /* @@ -63,7 +57,7 @@ struct __dummy { unsigned long a[100]; }; /* * change_bit - Toggle a bit in memory - * @nr: Bit to clear + * @nr: Bit to change * @addr: Address to start counting from * * change_bit() is atomic and may not be reordered. @@ -75,7 +69,7 @@ struct __dummy { unsigned long a[100]; }; /* * __change_bit - Toggle a bit in memory - * @nr: the bit to set + * @nr: the bit to change * @addr: the address to start counting from * * Unlike change_bit(), this function is non-atomic and may be reordered. @@ -94,7 +88,7 @@ struct __dummy { unsigned long a[100]; }; * It also implies a memory barrier. */ -static inline int test_and_set_bit(int nr, void *addr) +extern inline int test_and_set_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -102,15 +96,15 @@ static inline int test_and_set_bit(int nr, void *addr) adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr |= mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static inline int __test_and_set_bit(int nr, void *addr) +extern inline int __test_and_set_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -130,14 +124,14 @@ static inline int __test_and_set_bit(int nr, void *addr) /** * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set + * @nr: Bit to clear * @addr: Address to count from * * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_clear_bit(int nr, void *addr) +extern inline int test_and_clear_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -145,17 +139,17 @@ static inline int test_and_clear_bit(int nr, void *addr) adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr &= ~mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } /** * __test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set + * @nr: Bit to clear * @addr: Address to count from * * This operation is non-atomic and can be reordered. @@ -163,7 +157,7 @@ static inline int test_and_clear_bit(int nr, void *addr) * but actually fail. You must protect multiple accesses with a lock. */ -static inline int __test_and_clear_bit(int nr, void *addr) +extern inline int __test_and_clear_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -176,31 +170,31 @@ static inline int __test_and_clear_bit(int nr, void *addr) } /** * test_and_change_bit - Change a bit and return its new value - * @nr: Bit to set + * @nr: Bit to change * @addr: Address to count from * * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_change_bit(int nr, void *addr) +extern inline int test_and_change_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; unsigned int *adr = (unsigned int *)addr; adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr ^= mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } /* WARNING: non atomic and it can be reordered! */ -static inline int __test_and_change_bit(int nr, void *addr) +extern inline int __test_and_change_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -221,7 +215,7 @@ static inline int __test_and_change_bit(int nr, void *addr) * This routine doesn't need to be atomic. */ -static inline int test_bit(int nr, const void *addr) +extern inline int test_bit(int nr, const void *addr) { unsigned int mask; unsigned int *adr = (unsigned int *)addr; @@ -236,63 +230,28 @@ static inline int test_bit(int nr, const void *addr) */ /* - * Helper functions for the core of the ff[sz] functions, wrapping the - * syntactically awkward asms. The asms compute the number of leading - * zeroes of a bits-in-byte and byte-in-word and word-in-dword-swapped - * number. They differ in that the first function also inverts all bits - * in the input. + * Since we define it "external", it collides with the built-in + * definition, which doesn't have the same semantics. We don't want to + * use -fno-builtin, so just hide the name ffs. */ -static inline unsigned long cris_swapnwbrlz(unsigned long w) -{ - /* Let's just say we return the result in the same register as the - input. Saying we clobber the input but can return the result - in another register: - ! __asm__ ("swapnwbr %2\n\tlz %2,%0" - ! : "=r,r" (res), "=r,X" (dummy) : "1,0" (w)); - confuses gcc (sched.c, gcc from cris-dist-1.14). */ - - unsigned long res; - __asm__ ("swapnwbr %0 \n\t" - "lz %0,%0" - : "=r" (res) : "0" (w)); - return res; -} - -static inline unsigned long cris_swapwbrlz(unsigned long w) -{ - unsigned res; - __asm__ ("swapwbr %0 \n\t" - "lz %0,%0" - : "=r" (res) - : "0" (w)); - return res; -} +#define ffs kernel_ffs /* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. + * fls: find last bit set. */ -static inline unsigned long ffz(unsigned long w) -{ - /* The generic_ffs function is used to avoid the asm when the - argument is a constant. */ - return __builtin_constant_p (w) - ? (~w ? (unsigned long) generic_ffs ((int) ~w) - 1 : 32) - : cris_swapnwbrlz (w); -} + +#define fls(x) generic_fls(x) /* - * Somewhat like ffz but the equivalent of generic_ffs: in contrast to - * ffz we return the first one-bit *plus one*. + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ -static inline unsigned long ffs(unsigned long w) -{ - /* The generic_ffs function is used to avoid the asm when the - argument is a constant. */ - return __builtin_constant_p (w) - ? (unsigned long) generic_ffs ((int) w) - : w ? cris_swapwbrlz (w) + 1 : 0; -} + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) /** * find_next_zero_bit - find the first zero bit in a memory region @@ -300,7 +259,7 @@ static inline unsigned long ffs(unsigned long w) * @offset: The bitnumber to start searching at * @size: The maximum size to search */ -static inline int find_next_zero_bit (void * addr, int size, int offset) +extern inline int find_next_zero_bit (void * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -348,17 +307,6 @@ static inline int find_next_zero_bit (void * addr, int size, int offset) #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -/* - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh - * - * The Hamming Weight of a number is the total number of bits set in it. - */ - -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) - #define ext2_set_bit test_and_set_bit #define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit test_and_clear_bit @@ -373,44 +321,20 @@ static inline int find_next_zero_bit (void * addr, int size, int offset) #define minix_test_bit(nr,addr) test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) -#if 0 -/* TODO: see below */ -#define sched_find_first_zero_bit(addr) find_first_zero_bit(addr, 168) - -#else -/* TODO: left out pending where to put it.. (there are .h dependencies) */ - - /* - * Every architecture must define this function. It's the fastest - * way of searching a 168-bit bitmap where the first 128 bits are - * unlikely to be set. It's guaranteed that at least one of the 168 - * bits is cleared. - */ -#if 0 -#if MAX_RT_PRIO != 128 || MAX_PRIO != 168 -# error update this function. -#endif -#else -#define MAX_RT_PRIO 128 -#define MAX_PRIO 168 -#endif - -static inline int sched_find_first_zero_bit(char *bitmap) +extern inline int sched_find_first_bit(unsigned long *b) { - unsigned int *b = (unsigned int *)bitmap; - unsigned int rt; - - rt = b[0] & b[1] & b[2] & b[3]; - if (unlikely(rt != 0xffffffff)) - return find_first_zero_bit(bitmap, MAX_RT_PRIO); - - if (b[4] != ~0) - return ffz(b[4]) + MAX_RT_PRIO; - return ffz(b[5]) + 32 + MAX_RT_PRIO; + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (unlikely(b[3])) + return __ffs(b[3]) + 96; + if (b[4]) + return __ffs(b[4]) + 128; + return __ffs(b[5]) + 32 + 128; } -#undef MAX_PRIO -#undef MAX_RT_PRIO -#endif #endif /* __KERNEL__ */ diff --git a/include/asm-cris/byteorder.h b/include/asm-cris/byteorder.h index 64275f6045e..a1a222adaa9 100644 --- a/include/asm-cris/byteorder.h +++ b/include/asm-cris/byteorder.h @@ -1,30 +1,9 @@ -/* $Id: byteorder.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ - #ifndef _CRIS_BYTEORDER_H #define _CRIS_BYTEORDER_H -#include - #ifdef __GNUC__ -/* we just define these two (as we can do the swap in a single - * asm instruction in CRIS) and the arch-independent files will put - * them together into ntohl etc. - */ - -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) -{ - __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); - - return(x); -} - -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) -{ - __asm__ ("swapb %0" : "=r" (x) : "0" (x)); - - return(x); -} +#include /* defines are necessary because the other files detect the presence * of a defined __arch_swab32, not an inline diff --git a/include/asm-cris/cache.h b/include/asm-cris/cache.h index 1899bd77461..46a3b26e205 100644 --- a/include/asm-cris/cache.h +++ b/include/asm-cris/cache.h @@ -1,12 +1,6 @@ #ifndef _ASM_CACHE_H #define _ASM_CACHE_H -/* Etrax 100LX have 32-byte cache-lines. When we add support for future chips - * here should be a check for CPU type. - */ - -#define L1_CACHE_BYTES 32 - -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ +#include #endif /* _ASM_CACHE_H */ diff --git a/include/asm-i386/cacheflush.h b/include/asm-cris/cacheflush.h similarity index 68% copy from include/asm-i386/cacheflush.h copy to include/asm-cris/cacheflush.h index adc632b9754..6be38857a0a 100644 --- a/include/asm-i386/cacheflush.h +++ b/include/asm-cris/cacheflush.h @@ -1,14 +1,17 @@ -#ifndef _I386_CACHEFLUSH_H -#define _I386_CACHEFLUSH_H +#ifndef _CRIS_CACHEFLUSH_H +#define _CRIS_CACHEFLUSH_H /* Keep includes the same across arches. */ #include -/* Caches aren't brain-dead on the intel. */ +/* The cache doesn't need to be flushed when TLB entries change because + * the cache is mapped to physical memory, not virtual memory + */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) #define flush_cache_range(vma, start, end) do { } while (0) #define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) #define flush_dcache_page(page) do { } while (0) #define flush_icache_range(start, end) do { } while (0) #define flush_icache_page(vma,pg) do { } while (0) @@ -17,4 +20,4 @@ void global_flush_tlb(void); int change_page_attr(struct page *page, int numpages, pgprot_t prot); -#endif /* _I386_CACHEFLUSH_H */ +#endif /* _CRIS_CACHEFLUSH_H */ diff --git a/include/asm-cris/checksum.h b/include/asm-cris/checksum.h index 589eb323eba..15ca8aec5c6 100644 --- a/include/asm-cris/checksum.h +++ b/include/asm-cris/checksum.h @@ -3,6 +3,8 @@ #ifndef _CRIS_CHECKSUM_H #define _CRIS_CHECKSUM_H +#include + /* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) @@ -32,7 +34,7 @@ unsigned int csum_partial_copy_nocheck(const char *src, char *dst, * Fold a partial checksum into a word */ -static inline unsigned int csum_fold(unsigned int sum) +extern inline unsigned int csum_fold(unsigned int sum) { /* the while loop is unnecessary really, it's always enough with two iterations */ @@ -43,31 +45,6 @@ static inline unsigned int csum_fold(unsigned int sum) return ~sum; } -/* Checksum some values used in TCP/UDP headers. - * - * The gain by doing this in asm is that C will not generate carry-additions - * for the 32-bit components of the checksum, so otherwise we would have had - * to split all of those into 16-bit components, then add. - */ - -static inline unsigned int -csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, - unsigned short proto, unsigned int sum) -{ - int res; - __asm__ ("add.d %2, %0\n\t" - "ax\n\t" - "add.d %3, %0\n\t" - "ax\n\t" - "add.d %4, %0\n\t" - "ax\n\t" - "addq 0, %0\n" - : "=r" (res) - : "0" (sum), "r" (daddr), "r" (saddr), "r" ((ntohs(len) << 16) + (proto << 8))); - - return res; -} - extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errptr); @@ -78,7 +55,7 @@ extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, * */ -static inline unsigned short ip_fast_csum(unsigned char * iph, +extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) { return csum_fold(csum_partial(iph, ihl * 4, 0)); @@ -89,7 +66,7 @@ static inline unsigned short ip_fast_csum(unsigned char * iph, * returns a 16-bit checksum, already complemented */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, +extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, @@ -103,7 +80,7 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, * in icmp.c */ -static inline unsigned short ip_compute_csum(unsigned char * buff, int len) { +extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) { return csum_fold (csum_partial(buff, len, 0)); } diff --git a/include/asm-cris/current.h b/include/asm-cris/current.h index c5cc44d537d..dce69c99da3 100644 --- a/include/asm-cris/current.h +++ b/include/asm-cris/current.h @@ -1,14 +1,14 @@ #ifndef _CRIS_CURRENT_H #define _CRIS_CURRENT_H +#include + struct task_struct; -static inline struct task_struct * get_current(void) +extern inline struct task_struct * get_current(void) { - struct task_struct *current; - __asm__("and.d $sp,%0; ":"=r" (current) : "0" (~8191UL)); - return current; - } + return current_thread_info()->task; +} #define current get_current() diff --git a/include/asm-cris/delay.h b/include/asm-cris/delay.h index 632c369c41b..efc41aad484 100644 --- a/include/asm-cris/delay.h +++ b/include/asm-cris/delay.h @@ -2,33 +2,12 @@ #define _CRIS_DELAY_H /* - * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB + * Copyright (C) 1998-2002 Axis Communications AB * * Delay routines, using a pre-computed "loops_per_second" value. */ -#include -#include - -#ifdef CONFIG_SMP -#include -#endif - -extern void __do_delay(void); /* Special register call calling convention */ - -extern __inline__ void __delay(int loops) -{ - __asm__ __volatile__ ( - "move.d %0,$r9\n\t" - "beq 2f\n\t" - "subq 1,$r9\n\t" - "1:\n\t" - "bne 1b\n\t" - "subq 1,$r9\n" - "2:" - : : "g" (loops) : "r9"); -} - +#include /* Use only for very small delays ( < 1 msec). */ diff --git a/include/asm-cris/div64.h b/include/asm-cris/div64.h index bf33c2e8a04..6cd978cefb2 100644 --- a/include/asm-cris/div64.h +++ b/include/asm-cris/div64.h @@ -1,16 +1 @@ -#ifndef __ASM_CRIS_DIV64 -#define __ASM_CRIS_DIV64 - -/* copy from asm-arm */ - -/* We're not 64-bit, but... */ -#define do_div(n,base) \ -({ \ - int __res; \ - __res = ((unsigned long)n) % (unsigned int)base; \ - n = ((unsigned long)n) / (unsigned int)base; \ - __res; \ -}) - -#endif - +#include diff --git a/include/asm-cris/dma.h b/include/asm-cris/dma.h dissimilarity index 86% index fde1cbf1a80..c229fac35cd 100644 --- a/include/asm-cris/dma.h +++ b/include/asm-cris/dma.h @@ -1,59 +1,13 @@ -/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - */ - -#ifndef _ASM_DMA_H -#define _ASM_DMA_H - -/* it's useless on the Etrax, but unfortunately needed by the new - bootmem allocator (but this should do it for this) */ - -#define MAX_DMA_ADDRESS PAGE_OFFSET - -/* TODO: check nbr of channels on Etrax-100LX */ - -#define MAX_DMA_CHANNELS 10 - -/* dma0 and dma1 used for network (ethernet) */ -#define NETWORK_TX_DMA_NBR 0 -#define NETWORK_RX_DMA_NBR 1 - -/* dma2 and dma3 shared by par0, scsi0, ser2 and ata */ -#define PAR0_TX_DMA_NBR 2 -#define PAR0_RX_DMA_NBR 3 -#define SCSI0_TX_DMA_NBR 2 -#define SCSI0_RX_DMA_NBR 3 -#define SER2_TX_DMA_NBR 2 -#define SER2_RX_DMA_NBR 3 -#define ATA_TX_DMA_NBR 2 -#define ATA_RX_DMA_NBR 3 - -/* dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ -#define PAR1_TX_DMA_NBR 4 -#define PAR1_RX_DMA_NBR 5 -#define SCSI1_TX_DMA_NBR 4 -#define SCSI1_RX_DMA_NBR 5 -#define SER3_TX_DMA_NBR 4 -#define SER3_RX_DMA_NBR 5 -#define EXTDMA0_TX_DMA_NBR 4 -#define EXTDMA0_RX_DMA_NBR 5 - -/* dma6 and dma7 shared by ser0, extdma1 and mem2mem */ -#define SER0_TX_DMA_NBR 6 -#define SER0_RX_DMA_NBR 7 -#define EXTDMA1_TX_DMA_NBR 6 -#define EXTDMA1_RX_DMA_NBR 7 -#define MEM2MEM_TX_DMA_NBR 6 -#define MEM2MEM_RX_DMA_NBR 7 - -/* dma8 and dma9 shared by ser1 and usb */ -#define SER1_TX_DMA_NBR 8 -#define SER1_RX_DMA_NBR 9 -#define USB_TX_DMA_NBR 8 -#define USB_RX_DMA_NBR 9 - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it */ - -#endif /* _ASM_DMA_H */ +/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ */ + +#ifndef _ASM_DMA_H +#define _ASM_DMA_H + +#include + +/* it's useless on the Etrax, but unfortunately needed by the new + bootmem allocator (but this should do it for this) */ + +#define MAX_DMA_ADDRESS PAGE_OFFSET + +#endif /* _ASM_DMA_H */ diff --git a/include/asm-cris/elf.h b/include/asm-cris/elf.h dissimilarity index 64% index 798aeaeaabd..d37fd5c4a56 100644 --- a/include/asm-cris/elf.h +++ b/include/asm-cris/elf.h @@ -1,121 +1,61 @@ -#ifndef __ASMCRIS_ELF_H -#define __ASMCRIS_ELF_H - -/* - * ELF register definitions.. - */ - -#include - -typedef unsigned long elf_greg_t; - -/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is - thus exposed to user-space. */ -#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* A placeholder; CRIS does not have any fp regs. */ -typedef unsigned long elf_fpregset_t; - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ( (x)->e_machine == EM_CRIS ) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB; -#define ELF_ARCH EM_CRIS - - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts (a register; assume first param register for CRIS) - contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. - - A value of 0 tells we have no such handler. */ - - /* Explicitly set registers to 0 to increase determinism. */ -#define ELF_PLAT_INIT(_r, load_addr) do { \ - (_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \ - (_r)->r9 = 0; (_r)->r8 = 0; (_r)->r7 = 0; (_r)->r6 = 0; \ - (_r)->r5 = 0; (_r)->r4 = 0; (_r)->r3 = 0; (_r)->r2 = 0; \ - (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ -} while (0) - -#define USE_ELF_CORE_DUMP - -/* The additional layer below is because the stack pointer is missing in - the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t, - and should be filled in according to the layout of the user_regs_struct - struct; regs is a pt_regs struct. We dump all registers, though several are - obviously unnecessary. That way there's less need for intelligence at - the receiving end (i.e. gdb). */ -#define ELF_CORE_COPY_REGS(pr_reg, regs) \ - pr_reg[0] = regs->r0; \ - pr_reg[1] = regs->r1; \ - pr_reg[2] = regs->r2; \ - pr_reg[3] = regs->r3; \ - pr_reg[4] = regs->r4; \ - pr_reg[5] = regs->r5; \ - pr_reg[6] = regs->r6; \ - pr_reg[7] = regs->r7; \ - pr_reg[8] = regs->r8; \ - pr_reg[9] = regs->r9; \ - pr_reg[10] = regs->r10; \ - pr_reg[11] = regs->r11; \ - pr_reg[12] = regs->r12; \ - pr_reg[13] = regs->r13; \ - pr_reg[14] = rdusp(); /* sp */ \ - pr_reg[15] = regs->irp; /* pc */ \ - pr_reg[16] = 0; /* p0 */ \ - pr_reg[17] = rdvr(); /* vr */ \ - pr_reg[18] = 0; /* p2 */ \ - pr_reg[19] = 0; /* p3 */ \ - pr_reg[20] = 0; /* p4 */ \ - pr_reg[21] = (regs->dccr & 0xffff); /* ccr */ \ - pr_reg[22] = 0; /* p6 */ \ - pr_reg[23] = regs->mof; /* mof */ \ - pr_reg[24] = 0; /* p8 */ \ - pr_reg[25] = 0; /* ibr */ \ - pr_reg[26] = 0; /* irp */ \ - pr_reg[27] = regs->srp; /* srp */ \ - pr_reg[28] = 0; /* bar */ \ - pr_reg[29] = regs->dccr; /* dccr */ \ - pr_reg[30] = 0; /* brp */ \ - pr_reg[31] = rdusp(); /* usp */ \ - pr_reg[32] = 0; /* csrinstr */ \ - pr_reg[33] = 0; /* csraddr */ \ - pr_reg[34] = 0; /* csrdata */ - - -#define ELF_EXEC_PAGESIZE 8192 - -/* This is the location that an ET_DYN program is loaded if exec'ed. Typical - use of this is to invoke "./ld.so someprog" to test out a new version of - the loader. We need to make sure that it is out of the way of the program - that it will "exec", and that there is sufficient room for the brk. */ - -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) - -/* This yields a mask that user programs can use to figure out what - instruction set this CPU supports. This could be done in user space, - but it's not easy, and we've already done it here. */ - -#define ELF_HWCAP (0) - -/* This yields a string that ld.so will use to load implementation - specific libraries for optimization. This is more specific in - intent than poking at uname or /proc/cpuinfo. -*/ - -#define ELF_PLATFORM (NULL) - -#ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) -#endif - -#endif +#ifndef __ASMCRIS_ELF_H +#define __ASMCRIS_ELF_H + +/* + * ELF register definitions.. + */ + +#include +#include + +typedef unsigned long elf_greg_t; + +/* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is + thus exposed to user-space. */ +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* A placeholder; CRIS does not have any fp regs. */ +typedef unsigned long elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( (x)->e_machine == EM_CRIS ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_CRIS + +#define USE_ELF_CORE_DUMP + +#define ELF_EXEC_PAGESIZE 8192 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. This could be done in user space, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. +*/ + +#define ELF_PLATFORM (NULL) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#endif + +#endif diff --git a/include/asm-cris/etraxgpio.h b/include/asm-cris/etraxgpio.h index 0395953e883..cf04af9635c 100644 --- a/include/asm-cris/etraxgpio.h +++ b/include/asm-cris/etraxgpio.h @@ -1,13 +1,54 @@ +/* $Id: etraxgpio.h,v 1.8 2002/06/17 15:53:07 johana Exp $ */ +/* + * The following devices are accessable using this driver using + * GPIO_MAJOR (120) and a couple of minor numbers: + * For ETRAX 100LX (ARCH_V10): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 8 bit GPIO, each bit can change direction + * /dev/leds minor 2, Access to leds depending on kernelconfig + * /dev/gpiog minor 3 + g0dir, g8_15dir, g16_23dir, g24 dir configurable in R_GEN_CONFIG + g1-g7 and g25-g31 is both input and outputs but on different pins + Also note that some bits change pins depending on what interfaces + are enabled. + * + * + * For ETRAX 200 (ARCH_V32): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 18 bit GPIO, each bit can change direction + * /dev/gpioc minor 2, 18 bit GPIO, each bit can change direction + * /dev/gpiod minor 3, 18 bit GPIO, each bit can change direction + * /dev/gpioe minor 4, 18 bit GPIO, each bit can change direction + * /dev/leds minor 5, Access to leds depending on kernelconfig + * + */ #ifndef _ASM_ETRAXGPIO_H #define _ASM_ETRAXGPIO_H +#include /* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ - +#ifdef CONFIG_ETRAX_ARCH_V10 +#define ETRAXGPIO_IOCTYPE 43 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_LEDS 2 +#define GPIO_MINOR_G 3 +#define GPIO_MINOR_LAST 3 +#endif +#ifdef CONFIG_ETRAX_ARCH_V32 #define ETRAXGPIO_IOCTYPE 43 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_C 2 +#define GPIO_MINOR_D 3 +#define GPIO_MINOR_E 4 +#define GPIO_MINOR_LEDS 5 +#define GPIO_MINOR_LAST 5 +#endif /* supported ioctl _IOC_NR's */ -#define IO_READBITS 0x1 /* read and return current port bits */ +#define IO_READBITS 0x1 /* read and return current port bits (obsolete) */ #define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ #define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ @@ -22,11 +63,11 @@ * 0=off, 1=green, 2=red, 3=yellow */ /* GPIO direction ioctl's */ -#define IO_READDIR 0x8 /* Read direction 0=input 1=output */ -#define IO_SETINPUT 0x9 /* Set direction 0=unchanged 1=input, - returns current dir */ -#define IO_SETOUTPUT 0xA /* Set direction 0=unchanged 1=output, - returns current dir */ +#define IO_READDIR 0x8 /* Read direction 0=input 1=output (obsolete) */ +#define IO_SETINPUT 0x9 /* Set direction for bits set, 0=unchanged 1=input, + returns mask with current inputs (obsolete) */ +#define IO_SETOUTPUT 0xA /* Set direction for bits set, 0=unchanged 1=output, + returns mask with current outputs (obsolete)*/ /* LED ioctl extended */ #define IO_LED_SETBIT 0xB @@ -45,5 +86,19 @@ #define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \ ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) ) +/* The following 4 ioctl's take a pointer as argument and handles + * 32 bit ports (port G) properly. + * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT + */ +#define IO_READ_INBITS 0x10 /* *arg is result of reading the input pins */ +#define IO_READ_OUTBITS 0x11 /* *arg is result of reading the output shadow */ +#define IO_SETGET_INPUT 0x12 /* bits set in *arg is set to input, + * *arg updated with current input pins. + */ +#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output, + * *arg updated with current output pins. + */ + + #endif diff --git a/include/asm-cris/fasttimer.h b/include/asm-cris/fasttimer.h new file mode 100644 index 00000000000..10a77064787 --- /dev/null +++ b/include/asm-cris/fasttimer.h @@ -0,0 +1,42 @@ +/* $Id: fasttimer.h,v 1.2 2002/12/11 13:03:43 starvik Exp $ + * linux/include/asm-cris/fasttimer.h + * + * Fast timers for ETRAX100LX + * This may be useful in other OS than Linux so use 2 space indentation... + * Copyright (C) 2000, 2002 Axis Communications AB + */ +#include +#include /* struct timeval */ +#include + +#ifdef CONFIG_ETRAX_FAST_TIMER + +typedef void fast_timer_function_type(unsigned long); + +struct fast_timer{ /* Close to timer_list */ + struct fast_timer *next; + struct fast_timer *prev; + struct timeval tv_set; + struct timeval tv_expires; + unsigned long delay_us; + fast_timer_function_type *function; + unsigned long data; + const char *name; +}; + +void start_one_shot_timer(struct fast_timer *t, + fast_timer_function_type *function, + unsigned long data, + unsigned long delay_us, + const char *name); + +int del_fast_timer(struct fast_timer * t); +/* return 1 if deleted */ + + +void schedule_usleep(unsigned long us); + + +void fast_timer_init(void); + +#endif diff --git a/include/asm-i386/hardirq.h b/include/asm-cris/hardirq.h similarity index 84% copy from include/asm-i386/hardirq.h copy to include/asm-cris/hardirq.h index e8b9149f0b2..c75100f8359 100644 --- a/include/asm-i386/hardirq.h +++ b/include/asm-cris/hardirq.h @@ -1,20 +1,21 @@ #ifndef __ASM_HARDIRQ_H #define __ASM_HARDIRQ_H -#include +/* only non-SMP supported */ + #include -#include +#include +/* entry.S is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; + unsigned int __local_irq_count; + unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ - unsigned long idle_timestamp; - unsigned int __nmi_count; /* arch dependent */ - unsigned int apic_timer_irqs; /* arch dependent */ } ____cacheline_aligned irq_cpustat_t; -#include /* Standard mappings for irq_cpustat_t above */ +#include /* Standard mappings for irq_cpustat_t above */ /* * We put the hardirq and softirq counter into the preemption @@ -75,8 +76,6 @@ typedef struct { #define hardirq_endlock() do { } while (0) #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#define nmi_enter() (irq_enter()) -#define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET) #ifdef CONFIG_PREEMPT # define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) @@ -93,10 +92,6 @@ do { \ preempt_enable_no_resched(); \ } while (0) -#ifndef CONFIG_SMP -# define synchronize_irq(irq) barrier() -#else - extern void synchronize_irq(unsigned int irq); -#endif /* CONFIG_SMP */ +#define synchronize_irq(irq) barrier() #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-cris/hdreg.h b/include/asm-cris/hdreg.h deleted file mode 100644 index 382a8e64ce8..00000000000 --- a/include/asm-cris/hdreg.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * linux/include/asm-cris/hdreg.h - * - */ - -#ifndef __ASMCRIS_HDREG_H -#define __ASMCRIS_HDREG_H - -typedef unsigned long ide_ioreg_t; - -#endif /* __ASMCRIS_HDREG_H */ diff --git a/include/asm-cris/ide.h b/include/asm-cris/ide.h deleted file mode 100644 index 8f4bd8c131f..00000000000 --- a/include/asm-cris/ide.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * linux/include/asm-cris/ide.h - * - * Copyright (C) 2000 Axis Communications AB - * - * Authors: Bjorn Wesen - * - */ - -/* - * This file contains the ETRAX 100LX specific IDE code. - */ - -#ifndef __ASMCRIS_IDE_H -#define __ASMCRIS_IDE_H - -#ifdef __KERNEL__ - -#include - -/* ETRAX 100 can support 4 IDE busses on the same pins (serialized) */ - -#define MAX_HWIFS 4 - -static __inline__ int ide_default_irq(ide_ioreg_t base) -{ - /* all IDE busses share the same IRQ, number 4. - * this has the side-effect that ide-probe.c will cluster our 4 interfaces - * together in a hwgroup, and will serialize accesses. this is good, because - * we can't access more than one interface at the same time on ETRAX100. - */ - return 4; -} - -static __inline__ ide_ioreg_t ide_default_io_base(int index) -{ - /* we have no real I/O base address per interface, since all go through the - * same register. but in a bitfield in that register, we have the i/f number. - * so we can use the io_base to remember that bitfield. - */ - static const unsigned long io_bases[MAX_HWIFS] = { - IO_FIELD(R_ATA_CTRL_DATA, sel, 0), - IO_FIELD(R_ATA_CTRL_DATA, sel, 1), - IO_FIELD(R_ATA_CTRL_DATA, sel, 2), - IO_FIELD(R_ATA_CTRL_DATA, sel, 3) - }; - return io_bases[index]; -} - -/* this is called once for each interface, to setup the port addresses. data_port is the result - * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us. - */ - -static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) -{ - int i; - - /* fill in ports for ATA addresses 0 to 7 */ - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = data_port | - IO_FIELD(R_ATA_CTRL_DATA, addr, i) | - IO_STATE(R_ATA_CTRL_DATA, cs0, active); - } - - /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */ - - hw->io_ports[IDE_CONTROL_OFFSET] = data_port | - IO_FIELD(R_ATA_CTRL_DATA, addr, 6) | - IO_STATE(R_ATA_CTRL_DATA, cs1, active); - - /* whats this for ? */ - - hw->io_ports[IDE_IRQ_OFFSET] = 0; -} - -static __inline__ void ide_init_default_hwifs(void) -{ - hw_regs_t hw; - int index; - - for(index = 0; index < MAX_HWIFS; index++) { - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); - hw.irq = ide_default_irq(ide_default_io_base(index)); - ide_register_hw(&hw); - } -} - -/* some configuration options we don't need */ - -#undef SUPPORT_SLOW_DATA_PORTS -#define SUPPORT_SLOW_DATA_PORTS 0 - -/* the drive addressing is done through a controller register on the Etrax CPU */ -void OUT_BYTE(unsigned char data, ide_ioreg_t reg); -unsigned char IN_BYTE(ide_ioreg_t reg); - -/* this tells ide.h not to define the standard macros */ -#define HAVE_ARCH_IN_OUT 1 - -#endif /* __KERNEL__ */ - -#endif /* __ASMCRIS_IDE_H */ diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h dissimilarity index 80% index 82a06f841c9..8604f0e9a69 100644 --- a/include/asm-cris/io.h +++ b/include/asm-cris/io.h @@ -1,265 +1,82 @@ -#ifndef _ASM_CRIS_IO_H -#define _ASM_CRIS_IO_H - -#include /* for __va, __pa */ -#include -#include - -/* Console I/O for simulated etrax100. Use #ifdef so erroneous - use will be evident. */ -#ifdef CONFIG_SVINTO_SIM - /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) \ - asm ("moveq 4,$r9 \n\t" \ - "moveq 2,$r10 \n\t" \ - "move.d %0,$r11 \n\t" \ - "move.d %1,$r12 \n\t" \ - "push $irp \n\t" \ - "move 0f,$irp \n\t" \ - "jump -6809 \n" \ - "0: \n\t" \ - "pop $irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") -#define TRACE_ON() __extension__ \ - ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ - (255)); _Foofoo; }) - -#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) -#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) -#define CRIS_CYCLES() __extension__ \ - ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) -#else /* ! defined CONFIG_SVINTO_SIM */ -/* FIXME: Is there a reliable cycle counter available in some chip? Use - that then. */ -#define CRIS_CYCLES() 0 -#endif /* ! defined CONFIG_SVINTO_SIM */ - -/* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ - -extern unsigned long port_g_data_shadow; -extern unsigned char port_pa_dir_shadow; -extern unsigned char port_pa_data_shadow; -extern unsigned char port_pb_i2c_shadow; -extern unsigned char port_pb_config_shadow; -extern unsigned char port_pb_dir_shadow; -extern unsigned char port_pb_data_shadow; -extern unsigned long r_timer_ctrl_shadow; - -extern unsigned long port_cse1_shadow; -extern unsigned long port_csp0_shadow; -extern unsigned long port_csp4_shadow; - -extern volatile unsigned long *port_cse1_addr; -extern volatile unsigned long *port_csp0_addr; -extern volatile unsigned long *port_csp4_addr; - -/* macro for setting regs through a shadow - - * r = register name (like R_PORT_PA_DATA) - * s = shadow name (like port_pa_data_shadow) - * b = bit number - * v = value (0 or 1) - */ - -#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << (b))) | ((v) << (b)) - -/* The LED's on various Etrax-based products are set differently. */ - -#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) -#undef CONFIG_ETRAX_PA_LEDS -#undef CONFIG_ETRAX_PB_LEDS -#undef CONFIG_ETRAX_CSP0_LEDS -#define LED_NETWORK_SET_G(x) -#define LED_NETWORK_SET_R(x) -#define LED_ACTIVE_SET_G(x) -#define LED_ACTIVE_SET_R(x) -#define LED_DISK_WRITE(x) -#define LED_DISK_READ(x) -#endif - -#if !defined(CONFIG_ETRAX_CSP0_LEDS) -#define LED_BIT_SET(x) -#define LED_BIT_CLR(x) -#endif - -#define LED_OFF 0x00 -#define LED_GREEN 0x01 -#define LED_RED 0x02 -#define LED_ORANGE (LED_GREEN | LED_RED) - -#if CONFIG_ETRAX_LED1G == CONFIG_ETRAX_LED1R -#define LED_NETWORK_SET(x) \ - do { \ - LED_NETWORK_SET_G((x) & LED_GREEN); \ - } while (0) -#else -#define LED_NETWORK_SET(x) \ - do { \ - LED_NETWORK_SET_G((x) & LED_GREEN); \ - LED_NETWORK_SET_R((x) & LED_RED); \ - } while (0) -#endif -#if CONFIG_ETRAX_LED2G == CONFIG_ETRAX_LED2R -#define LED_ACTIVE_SET(x) \ - do { \ - LED_ACTIVE_SET_G((x) & LED_GREEN); \ - } while (0) -#else -#define LED_ACTIVE_SET(x) \ - do { \ - LED_ACTIVE_SET_G((x) & LED_GREEN); \ - LED_ACTIVE_SET_R((x) & LED_RED); \ - } while (0) -#endif - -#ifdef CONFIG_ETRAX_PA_LEDS -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) -#endif - -#ifdef CONFIG_ETRAX_PB_LEDS -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x)) -#endif - -#ifdef CONFIG_ETRAX_CSP0_LEDS -#define CONFIGURABLE_LEDS\ - ((1 << CONFIG_ETRAX_LED1G ) | (1 << CONFIG_ETRAX_LED1R ) |\ - (1 << CONFIG_ETRAX_LED2G ) | (1 << CONFIG_ETRAX_LED2R ) |\ - (1 << CONFIG_ETRAX_LED3G ) | (1 << CONFIG_ETRAX_LED3R ) |\ - (1 << CONFIG_ETRAX_LED4G ) | (1 << CONFIG_ETRAX_LED4R ) |\ - (1 << CONFIG_ETRAX_LED5G ) | (1 << CONFIG_ETRAX_LED5R ) |\ - (1 << CONFIG_ETRAX_LED6G ) | (1 << CONFIG_ETRAX_LED6R ) |\ - (1 << CONFIG_ETRAX_LED7G ) | (1 << CONFIG_ETRAX_LED7R ) |\ - (1 << CONFIG_ETRAX_LED8Y ) | (1 << CONFIG_ETRAX_LED9Y ) |\ - (1 << CONFIG_ETRAX_LED10Y ) |(1 << CONFIG_ETRAX_LED11Y )|\ - (1 << CONFIG_ETRAX_LED12R )) - -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x)) -#define LED_BIT_SET(x)\ - do{\ - if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1);\ - }while(0) -#define LED_BIT_CLR(x)\ - do{\ - if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0);\ - }while(0) -#endif - -# -#ifdef CONFIG_ETRAX_SOFT_SHUTDOWN -#define SOFT_SHUTDOWN() \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_SHUTDOWN_BIT, 1) -#else -#define SOFT_SHUTDOWN() -#endif - -/* - * Change virtual addresses to physical addresses and vv. - */ - -static inline unsigned long virt_to_phys(volatile void * address) -{ - return __pa(address); -} - -static inline void * phys_to_virt(unsigned long address) -{ - return __va(address); -} - -extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); - -extern inline void * ioremap (unsigned long offset, unsigned long size) -{ - return __ioremap(offset, size, 0); -} - -/* - * IO bus memory addresses are also 1:1 with the physical address - */ -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt - -/* - * readX/writeX() are used to access memory mapped devices. On some - * architectures the memory mapped IO stuff needs to be accessed - * differently. On the CRIS architecture, we just read/write the - * memory location directly. - */ -#define readb(addr) (*(volatile unsigned char *) (addr)) -#define readw(addr) (*(volatile unsigned short *) (addr)) -#define readl(addr) (*(volatile unsigned int *) (addr)) - -#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) -#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) -#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b)) - -#define memset_io(a,b,c) memset((void *)(a),(b),(c)) -#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) -#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) - -/* - * Again, CRIS does not require mem IO specific function. - */ - -#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) - -/* The following is junk needed for the arch-independent code but which - * we never use in the CRIS port - */ - -#define IO_SPACE_LIMIT 0xffff -#define inb(x) (0) -#define outb(x,y) -#define outw(x,y) -#define outl(x,y) -#define insb(x,y,z) -#define insw(x,y,z) -#define insl(x,y,z) -#define outsb(x,y,z) -#define outsw(x,y,z) -#define outsl(x,y,z) - -#endif +#ifndef _ASM_CRIS_IO_H +#define _ASM_CRIS_IO_H + +#include /* for __va, __pa */ +#include + +/* + * Change virtual addresses to physical addresses and vv. + */ + +extern inline unsigned long virt_to_phys(volatile void * address) +{ + return __pa(address); +} + +extern inline void * phys_to_virt(unsigned long address) +{ + return __va(address); +} + +extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); + +extern inline void * ioremap (unsigned long offset, unsigned long size) +{ + return __ioremap(offset, size, 0); +} + +extern void iounmap(void *addr); + +/* + * IO bus memory addresses are also 1:1 with the physical address + */ +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the CRIS architecture, we just read/write the + * memory location directly. + */ +#define readb(addr) (*(volatile unsigned char *) (addr)) +#define readw(addr) (*(volatile unsigned short *) (addr)) +#define readl(addr) (*(volatile unsigned int *) (addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl + +#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) + +/* + * Again, CRIS does not require mem IO specific function. + */ + +#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) + +/* The following is junk needed for the arch-independent code but which + * we never use in the CRIS port + */ + +#define IO_SPACE_LIMIT 0xffff +#define inb(x) (0) +#define outb(x,y) +#define outw(x,y) +#define outl(x,y) +#define insb(x,y,z) +#define insw(x,y,z) +#define insl(x,y,z) +#define outsb(x,y,z) +#define outsw(x,y,z) +#define outsl(x,y,z) + +#endif diff --git a/include/asm-cris/ioctls.h b/include/asm-cris/ioctls.h index 1628ad265a8..97787c3c575 100644 --- a/include/asm-cris/ioctls.h +++ b/include/asm-cris/ioctls.h @@ -70,6 +70,9 @@ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 +#define TIOCSERSETRS485 0x5461 /* enable rs-485 */ +#define TIOCSERWRRS485 0x5462 /* write rs-485 */ + /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 diff --git a/include/asm-cris/ipc.h b/include/asm-cris/ipc.h index 07e51a11d50..f086af6fa03 100644 --- a/include/asm-cris/ipc.h +++ b/include/asm-cris/ipc.h @@ -17,6 +17,7 @@ struct ipc_kludge { #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 +#define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h dissimilarity index 96% index 5e4fb8db673..caa45facb1b 100644 --- a/include/asm-cris/irq.h +++ b/include/asm-cris/irq.h @@ -1,195 +1,19 @@ -/* - * Interrupt handling assembler and defines for Linux/CRIS - * - * Copyright (c) 2000, 2001 Axis Communications AB - * - */ - -#ifndef _ASM_IRQ_H -#define _ASM_IRQ_H - -/* - * linux/include/asm-cris/irq.h - */ - -#include -#include - -#include - -#define NR_IRQS 32 -#define SOME_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, some) /* 0 ? */ -#define NMI_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, nmi) /* 1 */ -#define TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */ -#define TIMER1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */ -/* mio, ata, par0, scsi0 on 4 */ -/* par1, scsi1 on 5 */ -#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */ - -#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */ -#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */ -/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */ -#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0) -#define EXTDMA1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma1) - -/* dma0-9 is irq 16..25 */ -/* 16,17: network */ -#define DMA0_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma0) -#define DMA1_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma1) -#define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR -#define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR - -/* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */ -#define DMA2_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma2) -#define DMA3_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma3) -#define SER2_DMA_TX_IRQ_NBR DMA2_TX_IRQ_NBR -#define SER2_DMA_RX_IRQ_NBR DMA3_RX_IRQ_NBR - -/* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ -#define DMA4_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma4) -#define DMA5_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma5) -#define SER3_DMA_TX_IRQ_NBR DMA4_TX_IRQ_NBR -#define SER3_DMA_RX_IRQ_NBR DMA5_RX_IRQ_NBR - -/* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */ -#define DMA6_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma6) -#define DMA7_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma7) -#define SER0_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR -#define SER0_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR -#define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR -#define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR - -/* 24,25: dma8 and dma9 shared by ser1 and usb */ -#define DMA8_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma8) -#define DMA9_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma9) -#define SER1_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR -#define SER1_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR -#define USB_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR -#define USB_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR - -/* usb: controller at irq 31 + uses DMA8 and DMA9 */ -#define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb) - - - - - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -#define disable_irq_nosync disable_irq -#define enable_irq_nosync enable_irq - -/* our fine, global, etrax irq vector! the pointer lives in the head.S file. */ - -typedef void (*irqvectptr)(void); - -struct etrax_interrupt_vector { - irqvectptr v[256]; -}; - -extern struct etrax_interrupt_vector *etrax_irv; -void set_int_vector(int n, irqvectptr addr, irqvectptr saddr); -void set_break_vector(int n, irqvectptr addr); - -#define __STR(x) #x -#define STR(x) __STR(x) - -/* SAVE_ALL saves registers so they match pt_regs */ - -#define SAVE_ALL \ - "move $irp,[$sp=$sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \ - "push $srp\n\t" /* push subroutine return pointer */ \ - "push $dccr\n\t" /* push condition codes */ \ - "push $mof\n\t" /* push multiply overflow reg */ \ - "di\n\t" /* need to disable irq's at this point */\ - "subq 14*4,$sp\n\t" /* make room for r0-r13 */ \ - "movem $r13,[$sp]\n\t" /* push the r0-r13 registers */ \ - "push $r10\n\t" /* push orig_r10 */ \ - "clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */ - - /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq in irq.c */ - -#define BLOCK_IRQ(mask,nr) \ - "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000d8]\n\t" - -#define UNBLOCK_IRQ(mask) \ - "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000dc]\n\t" - -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) -#define sIRQ_NAME(nr) IRQ_NAME2(sIRQ##nr) -#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) - - /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls - * do_IRQ (with irq disabled still). after that it unblocks and jumps to - * ret_from_intr (entry.S) - * - * The reason the IRQ is blocked is to allow an sti() before the handler which - * will acknowledge the interrupt is run. - */ - -#define BUILD_IRQ(nr,mask) \ -void IRQ_NAME(nr); \ -void sIRQ_NAME(nr); \ -void BAD_IRQ_NAME(nr); \ -__asm__ ( \ - ".text\n\t" \ - "IRQ" #nr "_interrupt:\n\t" \ - SAVE_ALL \ - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ - BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \ - "moveq "#nr",$r10\n\t" \ - "move.d $sp,$r11\n\t" \ - "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ - UNBLOCK_IRQ(mask) \ - "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ - "jump ret_from_intr\n\t" \ - "bad_IRQ" #nr "_interrupt:\n\t" \ - "push $r0\n\t" \ - BLOCK_IRQ(mask,nr) \ - "pop $r0\n\t" \ - "reti\n\t" \ - "nop\n"); - -/* This is subtle. The timer interrupt is crucial and it should not be disabled for - * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would - * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK. - * If the softirq's take too much time to run, the timer irq won't run and the - * watchdog will kill us. - * - * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq - * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed - * it here, we would not get the multiple_irq at all. - * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. - */ - -#define BUILD_TIMER_IRQ(nr,mask) \ -void IRQ_NAME(nr); \ -void sIRQ_NAME(nr); \ -void BAD_IRQ_NAME(nr); \ -__asm__ ( \ - ".text\n\t" \ - "IRQ" #nr "_interrupt:\n\t" \ - SAVE_ALL \ - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ - "moveq "#nr",$r10\n\t" \ - "move.d $sp,$r11\n\t" \ - "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ - "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ - "jump ret_from_intr\n\t" \ - "bad_IRQ" #nr "_interrupt:\n\t" \ - "push $r0\n\t" \ - BLOCK_IRQ(mask,nr) \ - "pop $r0\n\t" \ - "reti\n\t" \ - "nop\n"); - -#endif /* _ASM_IRQ_H */ - - +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H + +#include + +extern __inline__ int irq_canonicalize(int irq) +{ + return irq; +} + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +#define disable_irq_nosync disable_irq +#define enable_irq_nosync enable_irq + +#endif /* _ASM_IRQ_H */ + + diff --git a/include/asm-cris/kmap_types.h b/include/asm-cris/kmap_types.h new file mode 100644 index 00000000000..eec0974c241 --- /dev/null +++ b/include/asm-cris/kmap_types.h @@ -0,0 +1,25 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +/* Dummy header just to define km_type. None of this + * is actually used on cris. + */ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_CRYPTO_USER, + KM_CRYPTO_SOFTIRQ, + KM_TYPE_NR +}; + +#endif diff --git a/include/asm-cris/mman.h b/include/asm-cris/mman.h index 827849b9f7f..4de58ad6efa 100644 --- a/include/asm-cris/mman.h +++ b/include/asm-cris/mman.h @@ -6,6 +6,7 @@ #define PROT_READ 0x1 /* page can be read */ #define PROT_WRITE 0x2 /* page can be written */ #define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_SEM 0x8 /* page may be used for atomic ops */ #define PROT_NONE 0x0 /* page can not be accessed */ #define MAP_SHARED 0x01 /* Share changes */ @@ -19,6 +20,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff --git a/include/asm-cris/mmu.h b/include/asm-cris/mmu.h dissimilarity index 95% index df2d5ee85c7..c40a1bcad06 100644 --- a/include/asm-cris/mmu.h +++ b/include/asm-cris/mmu.h @@ -1,62 +1,10 @@ -/* - * CRIS MMU constants and PTE layout - */ - -#ifndef _CRIS_MMU_H -#define _CRIS_MMU_H - -/* type used in struct mm to couple an MMU context to an active mm */ - -typedef unsigned int mm_context_t; - -/* kernel memory segments */ - -#define KSEG_F 0xf0000000UL -#define KSEG_E 0xe0000000UL -#define KSEG_D 0xd0000000UL -#define KSEG_C 0xc0000000UL -#define KSEG_B 0xb0000000UL -#define KSEG_A 0xa0000000UL -#define KSEG_9 0x90000000UL -#define KSEG_8 0x80000000UL -#define KSEG_7 0x70000000UL -#define KSEG_6 0x60000000UL -#define KSEG_5 0x50000000UL -#define KSEG_4 0x40000000UL -#define KSEG_3 0x30000000UL -#define KSEG_2 0x20000000UL -#define KSEG_1 0x10000000UL -#define KSEG_0 0x00000000UL - -/* CRIS PTE bits (see R_TLB_LO in the register description) - * - * Bit: 31-13 12-------4 3 2 1 0 - * ________________________________________________ - * | pfn | reserved | global | valid | kernel | we | - * |_____|__________|________|_______|________|_____| - * - * (pfn = physical frame number) - */ - -/* Real HW-based PTE bits. We use some synonym names so that - * things become less confusing in combination with the SW-based - * bits further below. - * - */ - -#define _PAGE_WE (1<<0) /* page is write-enabled */ -#define _PAGE_SILENT_WRITE (1<<0) /* synonym */ -#define _PAGE_KERNEL (1<<1) /* page is kernel only */ -#define _PAGE_VALID (1<<2) /* page is valid */ -#define _PAGE_SILENT_READ (1<<2) /* synonym */ -#define _PAGE_GLOBAL (1<<3) /* global page - context is ignored */ - -/* Bits the HW doesn't care about but the kernel uses them in SW */ - -#define _PAGE_PRESENT (1<<4) /* page present in memory */ -#define _PAGE_ACCESSED (1<<5) /* simulated in software using valid bit */ -#define _PAGE_MODIFIED (1<<6) /* simulated in software using we bit */ -#define _PAGE_READ (1<<7) /* read-enabled */ -#define _PAGE_WRITE (1<<8) /* write-enabled */ - -#endif +/* + * CRIS MMU constants and PTE layout + */ + +#ifndef _CRIS_MMU_H +#define _CRIS_MMU_H + +#include + +#endif diff --git a/include/asm-cris/mmu_context.h b/include/asm-cris/mmu_context.h index 6a6ea71a85c..f9308c5bbd9 100644 --- a/include/asm-cris/mmu_context.h +++ b/include/asm-cris/mmu_context.h @@ -5,11 +5,11 @@ extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm); extern void get_mmu_context(struct mm_struct *mm); extern void destroy_context(struct mm_struct *mm); extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, int cpu); + struct task_struct *tsk); #define deactivate_mm(tsk,mm) do { } while (0) -#define activate_mm(prev,next) switch_mm((prev),(next),NULL,smp_processor_id()) +#define activate_mm(prev,next) switch_mm((prev),(next),NULL) /* current active pgd - this is similar to other processors pgd * registers like cr3 on the i386 @@ -17,7 +17,7 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, extern volatile pgd_t *current_pgd; /* defined in arch/cris/mm/fault.c */ -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } diff --git a/include/asm-cris/module.h b/include/asm-cris/module.h index 5853a11d616..7ee72311bd7 100644 --- a/include/asm-cris/module.h +++ b/include/asm-cris/module.h @@ -1,12 +1,9 @@ #ifndef _ASM_CRIS_MODULE_H #define _ASM_CRIS_MODULE_H -/* - * This file contains the CRIS architecture specific module code. - */ - -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) -#define module_arch_init(x) (0) -#define arch_init_modules(x) do { } while (0) +/* cris is simple */ +struct mod_arch_specific { }; +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr #endif /* _ASM_CRIS_MODULE_H */ diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h index 47c83465c2a..05dc15526aa 100644 --- a/include/asm-cris/page.h +++ b/include/asm-cris/page.h @@ -2,7 +2,7 @@ #define _CRIS_PAGE_H #include -#include +#include /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 13 @@ -14,12 +14,9 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -#define STRICT_MM_TYPECHECKS - -#ifdef STRICT_MM_TYPECHECKS /* * These are used to make use of C type-checking.. */ @@ -38,52 +35,11 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -#else -/* - * .. while these make it easier on the compiler - */ -typedef unsigned long pte_t; -typedef unsigned long pmd_t; -typedef unsigned long pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pmd_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pmd(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -#endif - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) - -/* This handles the memory map.. */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define PAGE_OFFSET KSEG_6 /* kseg_6 is mapped to physical ram */ -#else -#define PAGE_OFFSET KSEG_C /* kseg_c is mapped to physical ram */ -#endif - -/* macros to convert between really physical and virtual addresses - * by stripping a selected bit, we can convert between KSEG_x and 0x40000000 where - * the DRAM really resides - */ - -#ifdef CONFIG_CRIS_LOW_MAP -/* we have DRAM virtually at 0x6 */ -#define __pa(x) ((unsigned long)(x) & 0xdfffffff) -#define __va(x) ((void *)((unsigned long)(x) | 0x20000000)) -#else -/* we have DRAM virtually at 0xc */ -#define __pa(x) ((unsigned long)(x) & 0x7fffffff) -#define __va(x) ((void *)((unsigned long)(x) | 0x80000000)) -#endif +/* On CRIS the PFN numbers doesn't start at 0 so we have to compensate */ +/* for that before indexing into the page table starting at mem_map */ +#define pfn_to_page(pfn) (mem_map + ((pfn) - (PAGE_OFFSET >> PAGE_SHIFT))) +#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + (PAGE_OFFSET >> PAGE_SHIFT)) +#define pfn_valid(pfn) (((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)) < max_mapnr) /* to index into the page map. our pages all start at physical addr PAGE_OFFSET so * we can let the map start there. notice that we subtract PAGE_OFFSET because @@ -95,6 +51,7 @@ typedef unsigned long pgprot_t; #define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT)) #define VALID_PAGE(page) (((page) - mem_map) < max_mapnr) +#define virt_addr_valid(kaddr) pfn_valid((kaddr) >> PAGE_SHIFT) /* convert a page (based on mem_map and forward) to a physical address * do this by figuring out the virtual address and then use __pa @@ -102,9 +59,34 @@ typedef unsigned long pgprot_t; #define page_to_phys(page) __pa((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) -/* from linker script */ +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +#ifndef __ASSEMBLY__ + +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ +} while (0) + +#define PAGE_BUG(page) do { \ + BUG(); \ +} while (0) + +#endif /* __ASSEMBLY__ */ + +/* Pure 2^n version of get_order */ +static inline int get_order(unsigned long size) +{ + int order; -extern unsigned long dram_start, dram_end; + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) diff --git a/include/asm-cris/param.h b/include/asm-cris/param.h index 50fe5729b29..a9f71dbedb3 100644 --- a/include/asm-cris/param.h +++ b/include/asm-cris/param.h @@ -1,6 +1,13 @@ #ifndef _ASMCRIS_PARAM_H #define _ASMCRIS_PARAM_H +/* Currently we assume that HZ=100 is good for CRIS. */ +#ifdef __KERNEL__ +# define HZ 100 /* Internal kernel timer frequency */ +# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#endif + #ifndef HZ #define HZ 100 #endif @@ -17,8 +24,4 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ -#ifdef __KERNEL__ -# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */ -#endif - #endif diff --git a/include/asm-cris/percpu.h b/include/asm-cris/percpu.h new file mode 100644 index 00000000000..6db9b43cf80 --- /dev/null +++ b/include/asm-cris/percpu.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_PERCPU_H +#define _CRIS_PERCPU_H + +#include + +#endif /* _CRIS_PERCPU_H */ diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h dissimilarity index 90% index 75dde6f4a42..ca769e06029 100644 --- a/include/asm-cris/pgalloc.h +++ b/include/asm-cris/pgalloc.h @@ -1,115 +1,67 @@ -#ifndef _CRIS_PGALLOC_H -#define _CRIS_PGALLOC_H - -#include -#include - -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; -} quicklists; - -#define pgd_quicklist (quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (quicklists.pte_cache) -#define pgtable_cache_size (quicklists.pgtable_cache_sz) - -#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) - -/* - * Allocate and free page tables. - */ - -static inline pgd_t *get_pgd_slow(void) -{ - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); - - if (ret) { - memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } - return ret; -} - -static inline void free_pgd_slow(pgd_t *pgd) -{ - free_page((unsigned long)pgd); -} - -static inline pgd_t *get_pgd_fast(void) -{ - unsigned long *ret; - - if ((ret = pgd_quicklist) != NULL) { - pgd_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - pgtable_cache_size--; - } else - ret = (unsigned long *)get_pgd_slow(); - return (pgd_t *)ret; -} - -static inline void free_pgd_fast(pgd_t *pgd) -{ - *(unsigned long *)pgd = (unsigned long) pgd_quicklist; - pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; -} - -static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) -{ - pte_t *pte; - - pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); - if (pte) - clear_page(pte); - return pte; -} - -static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) -{ - unsigned long *ret; - - if((ret = (unsigned long *)pte_quicklist) != NULL) { - pte_quicklist = (unsigned long *)(*ret); - ret[0] = ret[1]; - pgtable_cache_size--; - } - return (pte_t *)ret; -} - -static __inline__ void pte_free_fast(pte_t *pte) -{ - *(unsigned long *)pte = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - pgtable_cache_size++; -} - -static __inline__ void pte_free_slow(pte_t *pte) -{ - free_page((unsigned long)pte); -} - -#define pte_free(pte) pte_free_slow(pte) -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc(mm) get_pgd_fast() - -/* - * We don't have any real pmd's, and this code never triggers because - * the pgd will always be present.. - */ - -#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) -#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) -#define pmd_free_slow(x) do { } while (0) -#define pmd_free_fast(x) do { } while (0) -#define pmd_free(x) do { } while (0) -#define pgd_populate(mm, pmd, pte) BUG() - -/* other stuff */ - -extern int do_check_pgt_cache(int, int); - -#endif +#ifndef _CRIS_PGALLOC_H +#define _CRIS_PGALLOC_H + +#include +#include +#include + +#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, page_address(pte)) + +/* + * Allocate and free page tables. + */ + +extern inline pgd_t *pgd_alloc (struct mm_struct *mm) +{ + return (pgd_t *)get_zeroed_page(GFP_KERNEL); +} + +extern inline void pgd_free (pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +extern inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); + if (pte) + clear_page(pte); + return pte; +} + +extern inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + struct page *pte; + pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); + if (pte) + clear_page(page_address(pte)); + return pte; +} + +extern inline void pte_free_kernel(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +extern inline void pte_free(struct page *pte) +{ + __free_page(pte); +} + + +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + +/* + * We don't have any real pmd's, and this code never triggers because + * the pgd will always be present.. + */ + +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() + +#define check_pgt_cache() do { } while (0) + +#endif diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h index d3ffca51375..25b2b51b55b 100644 --- a/include/asm-cris/pgtable.h +++ b/include/asm-cris/pgtable.h @@ -1,104 +1,14 @@ -/* CRIS pgtable.h - macros and functions to manipulate page tables - * - * HISTORY: - * - * $Log: pgtable.h,v $ - * Revision 1.14 2001/12/10 03:08:50 bjornw - * Added pgtable_cache_init dummy - * - * Revision 1.13 2001/11/12 18:05:38 pkj - * Added declaration of paging_init(). - * - * Revision 1.12 2001/08/11 00:28:00 bjornw - * PAGE_CHG_MASK and PAGE_NONE had somewhat untraditional values - * - * Revision 1.11 2001/04/04 14:38:36 bjornw - * Removed bad_pagetable handling and the _kernel functions - * - * Revision 1.10 2001/03/23 07:46:42 starvik - * Corrected according to review remarks - * - * Revision 1.9 2000/11/22 14:57:53 bjornw - * * extern inline -> static inline - * * include asm-generic/pgtable.h - * - * Revision 1.8 2000/11/21 13:56:16 bjornw - * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type - * - * Revision 1.7 2000/10/06 15:05:32 bjornw - * VMALLOC area changed in memory mapping change - * - * Revision 1.6 2000/10/04 16:59:14 bjornw - * Changed comments - * - * Revision 1.5 2000/09/13 14:39:53 bjornw - * New macros - * - * Revision 1.4 2000/08/17 15:38:48 bjornw - * 2.4.0-test6 modifications: - * * flush_dcache_page added - * * MAP_NR removed - * * virt_to_page added - * - * Plus some comments and type-clarifications. - * - * Revision 1.3 2000/08/15 16:33:35 bjornw - * pmd_bad should recognize both kernel and user page-tables - * - * Revision 1.2 2000/07/10 17:06:01 bjornw - * Fixed warnings - * - * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw - * CRIS architecture, working draft - * - * - * Revision 1.11 2000/05/29 14:55:56 bjornw - * Small tweaks of pte_mk routines - * - * Revision 1.10 2000/01/27 01:49:06 bjornw - * * Ooops. The physical frame number in a PTE entry needs to point to the - * DRAM directly, not to what the kernel thinks is DRAM (due to KSEG mapping). - * Hence we need to strip bit 31 so 0xcXXXXXXX -> 0x4XXXXXXX. - * - * Revision 1.9 2000/01/26 16:25:50 bjornw - * Fixed PAGE_KERNEL bits - * - * Revision 1.8 2000/01/23 22:53:22 bjornw - * Correct flush_tlb_* macros and externs - * - * Revision 1.7 2000/01/18 16:22:55 bjornw - * Use PAGE_MASK instead of PFN_MASK. - * - * Revision 1.6 2000/01/17 02:42:53 bjornw - * Added the pmd_set macro. - * - * Revision 1.5 2000/01/16 19:53:42 bjornw - * Removed VMALLOC_OFFSET. Changed definitions of swapper_pg_dir and zero_page. - * - * Revision 1.4 2000/01/14 16:38:20 bjornw - * PAGE_DIRTY -> PAGE_SILENT_WRITE, removed PAGE_COW from PAGE_COPY. - * - * Revision 1.3 1999/12/04 20:12:21 bjornw - * * PTE bits have moved to asm/mmu.h - * * Fixed definitions of the higher level page protection bits - * * Added the pte_* functions, including dirty/accessed SW simulation - * (these are exactly the same as for the MIPS port) - * - * Revision 1.2 1999/12/04 00:41:54 bjornw - * * Fixed page table offsets, sizes and shifts - * * Removed reference to i386 SMP stuff - * * Added stray comments about Linux/CRIS mm design - * * Include asm/mmu.h which will contain MMU details - * - * Revision 1.1 1999/12/03 15:04:02 bjornw - * Copied from include/asm-etrax100. For the new CRIS architecture. +/* + * CRIS pgtable.h - macros and functions to manipulate page tables. */ #ifndef _CRIS_PGTABLE_H #define _CRIS_PGTABLE_H #include +#include #include +#include /* * The Linux memory management assumes a three-level page table setup. On @@ -114,49 +24,6 @@ extern void paging_init(void); -/* The cache doesn't need to be flushed when TLB entries change because - * the cache is mapped to physical memory, not virtual memory - */ -#define flush_cache_all() do { } while (0) -#define flush_cache_mm(mm) do { } while (0) -#define flush_cache_range(vma, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr) do { } while (0) -#define flush_dcache_page(page) do { } while (0) -#define flush_icache_range(start, end) do { } while (0) -#define flush_icache_page(vma,pg) do { } while (0) -#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) - -/* - * TLB flushing (implemented in arch/cris/mm/tlb.c): - * - * - flush_tlb() flushes the current mm struct TLBs - * - flush_tlb_all() flushes all processes TLBs - * - flush_tlb_mm(mm) flushes the specified mm context TLB's - * - flush_tlb_page(vma, vmaddr) flushes one page - * - flush_tlb_range(vma, start, end) flushes a range of pages - * - */ - -extern void flush_tlb_all(void); -extern void flush_tlb_mm(struct mm_struct *mm); -extern void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr); -extern void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, - unsigned long end); - -static inline void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - /* CRIS does not keep any page table caches in TLB */ -} - - -static inline void flush_tlb(void) -{ - flush_tlb_mm(current->mm); -} - /* Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following * hook is made available. @@ -204,63 +71,6 @@ static inline void flush_tlb(void) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_PGD_NR 0 -/* - * Kernels own virtual memory area. - */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define VMALLOC_START KSEG_7 -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END KSEG_8 -#else -#define VMALLOC_START KSEG_D -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END KSEG_E -#endif - -/* Define some higher level generic page attributes. The PTE bits are - * defined in asm-cris/mmu.h, and these are just combinations of those. - */ - -#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED) -#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED) - -#define _PAGE_TABLE (_PAGE_PRESENT | __READABLE | __WRITEABLE) -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED) - -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_WRITE | \ - _PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | __READABLE) // | _PAGE_COW -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | __READABLE) -#define PAGE_KERNEL __pgprot(_PAGE_GLOBAL | _PAGE_KERNEL | \ - _PAGE_PRESENT | __READABLE | __WRITEABLE) -#define _KERNPG_TABLE (_PAGE_TABLE | _PAGE_KERNEL) - -/* - * CRIS can't do page protection for execute, and considers read the same. - * Also, write permissions imply read permissions. This is the closest we can - * get.. - */ - -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED - /* zero page used for uninitialized stuff */ extern unsigned long empty_zero_page; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) @@ -299,53 +109,54 @@ extern unsigned long empty_zero_page; * setup: the pgd is never bad, and a pmd always exists (as it's folded * into the pgd entry) */ -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline void pgd_clear(pgd_t * pgdp) { } +extern inline int pgd_none(pgd_t pgd) { return 0; } +extern inline int pgd_bad(pgd_t pgd) { return 0; } +extern inline int pgd_present(pgd_t pgd) { return 1; } +extern inline void pgd_clear(pgd_t * pgdp) { } /* * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } -static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } -static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } +extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline pte_t pte_wrprotect(pte_t pte) +extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); return pte; } -static inline pte_t pte_rdprotect(pte_t pte) +extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_exprotect(pte_t pte) +extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_mkclean(pte_t pte) +extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); return pte; } -static inline pte_t pte_mkold(pte_t pte) +extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_mkwrite(pte_t pte) +extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; if (pte_val(pte) & _PAGE_MODIFIED) @@ -353,7 +164,7 @@ static inline pte_t pte_mkwrite(pte_t pte) return pte; } -static inline pte_t pte_mkread(pte_t pte) +extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -361,7 +172,7 @@ static inline pte_t pte_mkread(pte_t pte) return pte; } -static inline pte_t pte_mkexec(pte_t pte) +extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -369,7 +180,7 @@ static inline pte_t pte_mkexec(pte_t pte) return pte; } -static inline pte_t pte_mkdirty(pte_t pte) +extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_MODIFIED; if (pte_val(pte) & _PAGE_WRITE) @@ -377,7 +188,7 @@ static inline pte_t pte_mkdirty(pte_t pte) return pte; } -static inline pte_t pte_mkyoung(pte_t pte) +extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; if (pte_val(pte) & _PAGE_READ) @@ -401,7 +212,7 @@ static inline pte_t pte_mkyoung(pte_t pte) * addresses (the 0xc0xxxxxx's) goes as void *'s. */ -static inline pte_t __mk_pte(void * page, pgprot_t pgprot) +extern inline pte_t __mk_pte(void * page, pgprot_t pgprot) { pte_t pte; /* the PTE needs a physical address */ @@ -419,7 +230,7 @@ static inline pte_t __mk_pte(void * page, pgprot_t pgprot) __pte; \ }) -static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } @@ -428,7 +239,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * pte_pagenr refers to the page-number counted starting from the virtual DRAM start */ -static inline unsigned long __pte_page(pte_t pte) +extern inline unsigned long __pte_page(pte_t pte) { /* the PTE contains a physical address */ return (unsigned long)__va(pte_val(pte) & PAGE_MASK); @@ -446,17 +257,17 @@ static inline unsigned long __pte_page(pte_t pte) * don't need the __pa and __va transformations. */ -static inline unsigned long pmd_page(pmd_t pmd) -{ return pmd_val(pmd) & PAGE_MASK; } - -static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) +extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; } +#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) +#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + /* to find an entry in a page-table-directory. */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) /* to find an entry in a page-table-directory */ -static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + pgd_index(address); } @@ -465,16 +276,24 @@ static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) #define pgd_offset_k(address) pgd_offset(&init_mm, address) /* Find an entry in the second-level page table.. */ -static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) { return (pmd_t *) dir; } -/* Find an entry in the third-level page table.. */ -static inline pte_t * pte_offset(pmd_t * dir, unsigned long address) -{ - return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); -} +/* Find an entry in the third-level page table.. */ +#define __pte_offset(address) \ + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) +#define pte_offset_map(dir, address) \ + ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) +#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address) + +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) +#define pte_pfn(x) ((unsigned long)(__va((x).pte)) >> PAGE_SHIFT) +#define pfn_pte(pfn, prot) __pte((__pa((pfn) << PAGE_SHIFT)) | pgprot_val(prot)) #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), pte_val(e)) @@ -483,6 +302,7 @@ static inline pte_t * pte_offset(pmd_t * dir, unsigned long address) #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ /* @@ -491,7 +311,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ * * Actually I am not sure on what this could be used for. */ -static inline void update_mmu_cache(struct vm_area_struct * vma, +extern inline void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { } @@ -514,6 +334,9 @@ static inline void update_mmu_cache(struct vm_area_struct * vma, */ #define pgtable_cache_init() do { } while (0) +#define pte_to_pgoff(x) (pte_val(x) >> 6) +#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) + typedef pte_t *pte_addr_t; #endif /* _CRIS_PGTABLE_H */ diff --git a/include/asm-cris/poll.h b/include/asm-cris/poll.h index 8699d59dad7..1c0efc3e4be 100644 --- a/include/asm-cris/poll.h +++ b/include/asm-cris/poll.h @@ -14,6 +14,7 @@ #define POLLWRNORM 256 #define POLLWRBAND 512 #define POLLMSG 1024 +#define POLLREMOVE 4096 struct pollfd { int fd; diff --git a/include/asm-cris/posix_types.h b/include/asm-cris/posix_types.h index d10e9fc65c3..d1c87c65261 100644 --- a/include/asm-cris/posix_types.h +++ b/include/asm-cris/posix_types.h @@ -23,12 +23,14 @@ typedef int __kernel_pid_t; typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_gid_t; -typedef unsigned long __kernel_size_t; +typedef __SIZE_TYPE__ __kernel_size_t; typedef long __kernel_ssize_t; typedef int __kernel_ptrdiff_t; typedef long __kernel_time_t; typedef long __kernel_suseconds_t; typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; typedef int __kernel_daddr_t; typedef char * __kernel_caddr_t; typedef unsigned short __kernel_uid16_t; diff --git a/include/asm-cris/processor.h b/include/asm-cris/processor.h dissimilarity index 62% index 0a8c08fa93b..623bdf06d91 100644 --- a/include/asm-cris/processor.h +++ b/include/asm-cris/processor.h @@ -1,146 +1,79 @@ -/* - * include/asm-cris/processor.h - * - * Copyright (C) 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen Initial version - * - */ - -#ifndef __ASM_CRIS_PROCESSOR_H -#define __ASM_CRIS_PROCESSOR_H - -#include -#include -#include -#include - -/* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). - */ -#define current_text_addr() ({void *pc; __asm__ ("move.d $pc,%0" : "=rm" (pc)); pc; }) - -/* CRIS has no problems with write protection */ - -#define wp_works_ok 1 - -/* - * User space process size. This is hardcoded into a few places, - * so don't change it unless you know what you are doing. - */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define TASK_SIZE (0x50000000UL) /* 1.25 GB */ -#else -#define TASK_SIZE (0xB0000000UL) /* 2.75 GB */ -#endif - -/* This decides where the kernel will search for a free chunk of vm - * space during mmap's. - */ -#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) - -/* THREAD_SIZE is the size of the task_struct/kernel_stack combo. - * normally, the stack is found by doing something like p + THREAD_SIZE - * in CRIS, a page is 8192 bytes, which seems like a sane size - */ - -#define THREAD_SIZE PAGE_SIZE -#define KERNEL_STACK_SIZE PAGE_SIZE - -/* CRIS thread_struct. this really has nothing to do with the processor itself, since - * CRIS does not do any hardware task-switching, but it's here for legacy reasons. - * The thread_struct here is used when task-switching using _resume defined in entry.S. - * The offsets here are hardcoded into _resume - if you change this struct, you need to - * change them as well!!! -*/ - -struct thread_struct { - unsigned long ksp; /* kernel stack pointer */ - unsigned long usp; /* user stack pointer */ - unsigned long dccr; /* saved flag register */ -}; - -/* - * At user->kernel entry, the pt_regs struct is stacked on the top of the kernel-stack. - * This macro allows us to find those regs for a task. - * Notice that subsequent pt_regs stackings, like recursive interrupts occurring while - * we're in the kernel, won't affect this - only the first user->kernel transition - * registers are reached by this. - */ - -#define user_regs(task) (((struct pt_regs *)((unsigned long)(task) + THREAD_SIZE)) - 1) - -/* - * Dito but for the currently running task - */ - -#define current_regs() user_regs(current) - -#define INIT_THREAD { \ - 0, 0, 0x20 } /* ccr = int enable, nothing else */ - -extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - -/* give the thread a program location - * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) - * switch user-stackpointer - */ - -#define start_thread(regs, ip, usp) do { \ - set_fs(USER_DS); \ - regs->irp = ip; \ - regs->dccr |= 1 << U_DCCR_BITNR; \ - wrusp(usp); \ -} while(0) - -unsigned long get_wchan(struct task_struct *p); - -#define KSTK_EIP(tsk) \ - ({ \ - unsigned long eip = 0; \ - unsigned long regs = (unsigned long)user_regs(tsk); \ - if (regs > PAGE_SIZE && \ - virt_addr_valid(regs)) \ - eip = ((struct pt_regs *)regs)->irp; \ - eip; }) - -#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) - -/* - * Free current thread data structures etc.. - */ - -static inline void exit_thread(void) -{ - /* Nothing needs to be done. */ -} - -/* Free all resources held by a thread. */ -static inline void release_thread(struct task_struct *dead_task) -{ - /* Nothing needs to be done. */ -} - -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - -/* - * Return saved PC of a blocked thread. - */ -extern inline unsigned long thread_saved_pc(struct thread_struct *t) -{ - return (unsigned long)user_regs(t)->irp; -} - -#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) -#define free_task_struct(p) free_pages((unsigned long) (p), 1) -#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) - -#define init_task (init_task_union.task) -#define init_stack (init_task_union.stack) - -#define cpu_relax() barrier() - -#endif /* __ASM_CRIS_PROCESSOR_H */ +/* + * include/asm-cris/processor.h + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen Initial version + * + */ + +#ifndef __ASM_CRIS_PROCESSOR_H +#define __ASM_CRIS_PROCESSOR_H + +#include +#include +#include +#include +#include + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) + +/* THREAD_SIZE is the size of the task_struct/kernel_stack combo. + * normally, the stack is found by doing something like p + THREAD_SIZE + * in CRIS, a page is 8192 bytes, which seems like a sane size + */ + +#define THREAD_SIZE PAGE_SIZE +#define KERNEL_STACK_SIZE PAGE_SIZE + +/* + * At user->kernel entry, the pt_regs struct is stacked on the top of the kernel-stack. + * This macro allows us to find those regs for a task. + * Notice that subsequent pt_regs stackings, like recursive interrupts occurring while + * we're in the kernel, won't affect this - only the first user->kernel transition + * registers are reached by this. + */ + +#define user_regs(thread_info) (((struct pt_regs *)((unsigned long)(thread_info) + THREAD_SIZE)) - 1) + +/* + * Dito but for the currently running task + */ + +#define current_regs() user_regs(current->thread_info) + +extern inline void prepare_to_copy(struct task_struct *tsk) +{ +} + +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +unsigned long get_wchan(struct task_struct *p); + +#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) + +/* + * Free current thread data structures etc.. + */ + +extern inline void exit_thread(void) +{ + /* Nothing needs to be done. */ +} + +extern unsigned long thread_saved_pc(struct task_struct *tsk); + +/* Free all resources held by a thread. */ +extern inline void release_thread(struct task_struct *dead_task) +{ + /* Nothing needs to be done. */ +} + +#define init_stack (init_thread_union.stack) + +#define cpu_relax() barrier() + +#endif /* __ASM_CRIS_PROCESSOR_H */ diff --git a/include/asm-cris/ptrace.h b/include/asm-cris/ptrace.h dissimilarity index 93% index b7391cc079d..79045e36d0a 100644 --- a/include/asm-cris/ptrace.h +++ b/include/asm-cris/ptrace.h @@ -1,120 +1,10 @@ -#ifndef _CRIS_PTRACE_H -#define _CRIS_PTRACE_H - -/* Register numbers in the ptrace system call interface */ - -#define PT_FRAMETYPE 0 -#define PT_ORIG_R10 1 -#define PT_R13 2 -#define PT_R12 3 -#define PT_R11 4 -#define PT_R10 5 -#define PT_R9 6 -#define PT_R8 7 -#define PT_R7 8 -#define PT_R6 9 -#define PT_R5 10 -#define PT_R4 11 -#define PT_R3 12 -#define PT_R2 13 -#define PT_R1 14 -#define PT_R0 15 -#define PT_MOF 16 -#define PT_DCCR 17 -#define PT_SRP 18 -#define PT_IRP 19 /* This is actually the debugged process' PC */ -#define PT_CSRINSTR 20 /* CPU Status record remnants - - valid if frametype == busfault */ -#define PT_CSRADDR 21 -#define PT_CSRDATA 22 -#define PT_USP 23 /* special case - USP is not in the pt_regs */ -#define PT_MAX 23 - -/* Condition code bit numbers. The same numbers apply to CCR of course, - but we use DCCR everywhere else, so let's try and be consistent. */ -#define C_DCCR_BITNR 0 -#define V_DCCR_BITNR 1 -#define Z_DCCR_BITNR 2 -#define N_DCCR_BITNR 3 -#define X_DCCR_BITNR 4 -#define I_DCCR_BITNR 5 -#define B_DCCR_BITNR 6 -#define M_DCCR_BITNR 7 -#define U_DCCR_BITNR 8 -#define P_DCCR_BITNR 9 -#define F_DCCR_BITNR 10 - -/* Frame types */ - -#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ -#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return - path */ - -/* pt_regs not only specifices the format in the user-struct during - * ptrace but is also the frame format used in the kernel prologue/epilogues - * themselves - */ - -struct pt_regs { - unsigned long frametype; /* type of stackframe */ - unsigned long orig_r10; - /* pushed by movem r13, [sp] in SAVE_ALL, movem pushes backwards */ - unsigned long r13; - unsigned long r12; - unsigned long r11; - unsigned long r10; - unsigned long r9; - unsigned long r8; - unsigned long r7; - unsigned long r6; - unsigned long r5; - unsigned long r4; - unsigned long r3; - unsigned long r2; - unsigned long r1; - unsigned long r0; - unsigned long mof; - unsigned long dccr; - unsigned long srp; - unsigned long irp; /* This is actually the debugged process' PC */ - unsigned long csrinstr; - unsigned long csraddr; - unsigned long csrdata; -}; - -/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) - * when doing a context-switch. it is used (apart from in resume) when a new - * thread is made and we need to make _resume (which is starting it for the - * first time) realise what is going on. - * - * Actually, the use is very close to the thread struct (TSS) in that both the - * switch_stack and the TSS are used to keep thread stuff when switching in - * _resume. - */ - -struct switch_stack { - unsigned long r9; - unsigned long r8; - unsigned long r7; - unsigned long r6; - unsigned long r5; - unsigned long r4; - unsigned long r3; - unsigned long r2; - unsigned long r1; - unsigned long r0; - unsigned long return_ip; /* ip that _resume will return to */ -}; - -#ifdef __KERNEL__ -/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 - -/* bit 8 is user-mode flag */ -#define user_mode(regs) (((regs)->dccr & 0x100) != 0) -#define instruction_pointer(regs) ((regs)->irp) -extern void show_regs(struct pt_regs *); -#endif - -#endif /* _CRIS_PTRACE_H */ +#ifndef _CRIS_PTRACE_H +#define _CRIS_PTRACE_H + +#include + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 + +#endif /* _CRIS_PTRACE_H */ diff --git a/include/asm-cris/rs485.h b/include/asm-cris/rs485.h new file mode 100644 index 00000000000..c331c51b0c2 --- /dev/null +++ b/include/asm-cris/rs485.h @@ -0,0 +1,20 @@ +/* RS-485 structures */ + +/* RS-485 support */ +/* Used with ioctl() TIOCSERSETRS485 */ +struct rs485_control { + unsigned short rts_on_send; + unsigned short rts_after_sent; + unsigned long delay_rts_before_send; + unsigned short enabled; +#ifdef __KERNEL__ + int disable_serial_loopback; +#endif +}; + +/* Used with ioctl() TIOCSERWRRS485 */ +struct rs485_write { + unsigned short outc_size; + unsigned char *outc; +}; + diff --git a/include/asm-cris/rtc.h b/include/asm-cris/rtc.h dissimilarity index 75% index 72ff33a48a8..382081c4ab5 100644 --- a/include/asm-cris/rtc.h +++ b/include/asm-cris/rtc.h @@ -1,70 +1,105 @@ -/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */ - -#ifndef RTC_H -#define RTC_H - -#include - -/* Dallas DS1302 clock/calendar register numbers */ - -#define RTC_SECONDS 0 -#define RTC_MINUTES 1 -#define RTC_HOURS 2 -#define RTC_DAY_OF_MONTH 3 -#define RTC_MONTH 4 -#define RTC_WEEKDAY 5 -#define RTC_YEAR 6 -#define RTC_CONTROL 7 - -/* Bits in CONTROL register */ -#define RTC_CONTROL_WRITEPROTECT 0x80 -#define RTC_TRICKLECHARGER 8 -/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */ -#define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ -#define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ -#define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ -#define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ -#define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ -#define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ -#define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ - -#ifdef CONFIG_ETRAX_DS1302 -#define CMOS_READ(x) ds1302_readreg(x) -#define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) -#define RTC_INIT() ds1302_init() -#else -/* no RTC configured so we shouldn't try to access any */ -#define CMOS_READ(x) 42 -#define CMOS_WRITE(x,y) -#define RTC_INIT() (-1) -#endif - -/* - * The struct used to pass data via the following ioctl. Similar to the - * struct tm in , but it needs to be here so that the kernel - * source is self contained, allowing cross-compiles, etc. etc. - */ - -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -/* - * ioctl calls that are permitted to the /dev/rtc interface - */ - -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ -#define RTC_SET_CHARGE _IOW('p', 0x0b, int) /* Set CHARGE mode */ - -#endif - - +/* $Id: rtc.h,v 1.7 2002/11/04 07:32:09 starvik Exp $ */ + +#ifndef __RTC_H__ +#define __RTC_H__ + + +#include + +#ifdef CONFIG_ETRAX_DS1302 + /* Dallas DS1302 clock/calendar register numbers. */ +# define RTC_SECONDS 0 +# define RTC_MINUTES 1 +# define RTC_HOURS 2 +# define RTC_DAY_OF_MONTH 3 +# define RTC_MONTH 4 +# define RTC_WEEKDAY 5 +# define RTC_YEAR 6 +# define RTC_CONTROL 7 + + /* Bits in CONTROL register. */ +# define RTC_CONTROL_WRITEPROTECT 0x80 +# define RTC_TRICKLECHARGER 8 + + /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */ +# define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ +# define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ +# define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ +# define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ +# define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ +# define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ +# define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ + +#elif defined(CONFIG_ETRAX_PCF8563) + /* I2C bus slave registers. */ +# define RTC_I2C_READ 0xa3 +# define RTC_I2C_WRITE 0xa2 + + /* Phillips PCF8563 registers. */ +# define RTC_CONTROL1 0x00 /* Control/Status register 1. */ +# define RTC_CONTROL2 0x01 /* Control/Status register 2. */ +# define RTC_CLOCKOUT_FREQ 0x0d /* CLKOUT frequency. */ +# define RTC_TIMER_CONTROL 0x0e /* Timer control. */ +# define RTC_TIMER_CNTDOWN 0x0f /* Timer countdown. */ + + /* BCD encoded clock registers. */ +# define RTC_SECONDS 0x02 +# define RTC_MINUTES 0x03 +# define RTC_HOURS 0x04 +# define RTC_DAY_OF_MONTH 0x05 +# define RTC_WEEKDAY 0x06 /* Not coded in BCD! */ +# define RTC_MONTH 0x07 +# define RTC_YEAR 0x08 +# define RTC_MINUTE_ALARM 0x09 +# define RTC_HOUR_ALARM 0x0a +# define RTC_DAY_ALARM 0x0b +# define RTC_WEEKDAY_ALARM 0x0c + +#endif + +#ifdef CONFIG_ETRAX_DS1302 +extern unsigned char ds1302_readreg(int reg); +extern void ds1302_writereg(int reg, unsigned char val); +extern int ds1302_init(void); +# define CMOS_READ(x) ds1302_readreg(x) +# define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) +# define RTC_INIT() ds1302_init() +#elif defined(CONFIG_ETRAX_PCF8563) +extern unsigned char pcf8563_readreg(int reg); +extern void pcf8563_writereg(int reg, unsigned char val); +extern int pcf8563_init(void); +# define CMOS_READ(x) pcf8563_readreg(x) +# define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val) +# define RTC_INIT() pcf8563_init() +#else + /* No RTC configured so we shouldn't try to access any. */ +# define CMOS_READ(x) 42 +# define CMOS_WRITE(x,y) +# define RTC_INIT() (-1) +#endif + +/* + * The struct used to pass data via the following ioctl. Similar to the + * struct tm in , but it needs to be here so that the kernel + * source is self contained, allowing cross-compiles, etc. etc. + */ +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +/* ioctl() calls that are permitted to the /dev/rtc interface. */ +#define RTC_MAGIC 'p' +#define RTC_RD_TIME _IOR(RTC_MAGIC, 0x09, struct rtc_time) /* Read RTC time. */ +#define RTC_SET_TIME _IOW(RTC_MAGIC, 0x0a, struct rtc_time) /* Set RTC time. */ +#define RTC_SET_CHARGE _IOW(RTC_MAGIC, 0x0b, int) +#define RTC_MAX_IOCTL 0x0b + +#endif /* __RTC_H__ */ diff --git a/include/asm-cris/scatterlist.h b/include/asm-cris/scatterlist.h index 11a64f5fe30..4bdc44c4ac3 100644 --- a/include/asm-cris/scatterlist.h +++ b/include/asm-cris/scatterlist.h @@ -11,6 +11,8 @@ struct scatterlist { }; +#define sg_dma_address(sg) ((sg)->address) +#define sg_dma_len(sg) ((sg)->length) /* i386 junk */ #define ISA_DMA_THRESHOLD (0x1fffffff) diff --git a/include/asm-cris/semaphore-helper.h b/include/asm-cris/semaphore-helper.h index 3453c88c2f2..461c5e4fc7b 100644 --- a/include/asm-cris/semaphore-helper.h +++ b/include/asm-cris/semaphore-helper.h @@ -9,6 +9,7 @@ #define _ASM_SEMAPHORE_HELPER_H #include +#include #define read(a) ((a)->counter) #define inc(a) (((a)->counter)++) @@ -19,32 +20,34 @@ /* * These two _must_ execute atomically wrt each other. */ -static inline void wake_one_more(struct semaphore * sem) +extern inline void wake_one_more(struct semaphore * sem) { atomic_inc(&sem->waking); } -static inline int waking_non_zero(struct semaphore *sem) +extern inline int waking_non_zero(struct semaphore *sem) { unsigned long flags; int ret = 0; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) > 0) { dec(&sem->waking); ret = 1; } - restore_flags(flags); + local_irq_restore(flags); return ret; } -static inline int waking_non_zero_interruptible(struct semaphore *sem, +extern inline int waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk) { int ret = 0; unsigned long flags; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) > 0) { dec(&sem->waking); ret = 1; @@ -52,23 +55,24 @@ static inline int waking_non_zero_interruptible(struct semaphore *sem, count_inc(&sem->count); ret = -EINTR; } - restore_flags(flags); + local_irq_restore(flags); return ret; } -static inline int waking_non_zero_trylock(struct semaphore *sem) +extern inline int waking_non_zero_trylock(struct semaphore *sem) { int ret = 1; unsigned long flags; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) <= 0) count_inc(&sem->count); else { dec(&sem->waking); ret = 0; } - restore_flags(flags); + local_irq_restore(flags); return ret; } diff --git a/include/asm-cris/semaphore.h b/include/asm-cris/semaphore.h index f55edcd2f8d..011a3bdc9ca 100644 --- a/include/asm-cris/semaphore.h +++ b/include/asm-cris/semaphore.h @@ -54,12 +54,12 @@ extern inline void sema_init(struct semaphore *sem, int val) *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); } -static inline void init_MUTEX (struct semaphore *sem) +extern inline void init_MUTEX (struct semaphore *sem) { sema_init(sem, 1); } -static inline void init_MUTEX_LOCKED (struct semaphore *sem) +extern inline void init_MUTEX_LOCKED (struct semaphore *sem) { sema_init(sem, 0); } @@ -81,10 +81,10 @@ extern inline void down(struct semaphore * sem) #endif /* atomically decrement the semaphores count, and if its negative, we wait */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) { __down(sem); } @@ -106,10 +106,10 @@ extern inline int down_interruptible(struct semaphore * sem) #endif /* atomically decrement the semaphores count, and if its negative, we wait */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) failed = __down_interruptible(sem); return(failed); @@ -124,10 +124,10 @@ extern inline int down_trylock(struct semaphore * sem) CHECK_MAGIC(sem->__magic); #endif - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) failed = __down_trylock(sem); return(failed); @@ -149,10 +149,10 @@ extern inline void up(struct semaphore * sem) #endif /* atomically increment the semaphores count, and if it was negative, we wake people */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); wakeup = ++(sem->count) <= 0; - restore_flags(flags); + local_irq_restore(flags); if(wakeup) { __up(sem); } diff --git a/include/asm-cris/setup.h b/include/asm-cris/setup.h dissimilarity index 99% index f382d3b4d28..832c197edf4 100644 --- a/include/asm-cris/setup.h +++ b/include/asm-cris/setup.h @@ -1,405 +1,3 @@ -/* -** asm/setup.h -- Definition of the Linux/m68k boot information structure -** -** Copyright 1992 by Greg Harp -** -** This file is subject to the terms and conditions of the GNU General Public -** License. See the file COPYING in the main directory of this archive -** for more details. -** -** Created 09/29/92 by Greg Harp -** -** 5/2/94 Roman Hodek: -** Added bi_atari part of the machine dependent union bi_un; for now it -** contains just a model field to distinguish between TT and Falcon. -** 26/7/96 Roman Zippel: -** Renamed to setup.h; added some useful macros to allow gcc some -** optimizations if possible. -*/ - -#ifndef _M68K_SETUP_H -#define _M68K_SETUP_H - -#include - -#define CL_SIZE (256) - -#if 0 - -#include - -/* - * Amiga specific part of bootinfo structure. - */ - -#define NUM_AUTO 16 - -#ifndef __ASSEMBLY__ - -#define AMIGAHW_DECLARE(name) unsigned name : 1 -#define AMIGAHW_SET(name) (boot_info.bi_amiga.hw_present.name = 1) -#define AMIGAHW_PRESENT(name) (boot_info.bi_amiga.hw_present.name) - -struct bi_Amiga { - int model; /* Amiga Model (3000?) */ - int num_autocon; /* # of autoconfig devices found */ - struct ConfigDev autocon[NUM_AUTO]; /* up to 16 autoconfig devices */ -#ifdef HACKER_KERNEL - void (*exit_func)(void); /* addr of function to exit kernel */ - unsigned long chip_addr; /* start of chip memory (bytes) */ -#endif - unsigned long chip_size; /* size of chip memory (bytes) */ - unsigned char vblank; /* VBLANK frequency */ - unsigned char psfreq; /* power supply frequency */ - unsigned long eclock; /* EClock frequency */ - unsigned long chipset; /* native chipset present */ - struct { - /* video hardware */ - AMIGAHW_DECLARE(AMI_VIDEO); /* Amiga Video */ - AMIGAHW_DECLARE(AMI_BLITTER); /* Amiga Blitter */ - AMIGAHW_DECLARE(AMBER_FF); /* Amber Flicker Fixer */ - /* sound hardware */ - AMIGAHW_DECLARE(AMI_AUDIO); /* Amiga Audio */ - /* disk storage interfaces */ - AMIGAHW_DECLARE(AMI_FLOPPY); /* Amiga Floppy */ - AMIGAHW_DECLARE(A3000_SCSI); /* SCSI (wd33c93, A3000 alike) */ - AMIGAHW_DECLARE(A4000_SCSI); /* SCSI (ncr53c710, A4000T alike) */ - AMIGAHW_DECLARE(A1200_IDE); /* IDE (A1200 alike) */ - AMIGAHW_DECLARE(A4000_IDE); /* IDE (A4000 alike) */ - AMIGAHW_DECLARE(CD_ROM); /* CD ROM drive */ - /* other I/O hardware */ - AMIGAHW_DECLARE(AMI_KEYBOARD); /* Amiga Keyboard */ - AMIGAHW_DECLARE(AMI_MOUSE); /* Amiga Mouse */ - AMIGAHW_DECLARE(AMI_SERIAL); /* Amiga Serial */ - AMIGAHW_DECLARE(AMI_PARALLEL); /* Amiga Parallel */ - /* real time clocks */ - AMIGAHW_DECLARE(A2000_CLK); /* Hardware Clock (A2000 alike) */ - AMIGAHW_DECLARE(A3000_CLK); /* Hardware Clock (A3000 alike) */ - /* supporting hardware */ - AMIGAHW_DECLARE(CHIP_RAM); /* Chip RAM */ - AMIGAHW_DECLARE(PAULA); /* Paula (8364) */ - AMIGAHW_DECLARE(DENISE); /* Denise (8362) */ - AMIGAHW_DECLARE(DENISE_HR); /* Denise (8373) */ - AMIGAHW_DECLARE(LISA); /* Lisa (8375) */ - AMIGAHW_DECLARE(AGNUS_PAL); /* Normal/Fat PAL Agnus (8367/8371) */ - AMIGAHW_DECLARE(AGNUS_NTSC); /* Normal/Fat NTSC Agnus (8361/8370) */ - AMIGAHW_DECLARE(AGNUS_HR_PAL); /* Fat Hires PAL Agnus (8372) */ - AMIGAHW_DECLARE(AGNUS_HR_NTSC); /* Fat Hires NTSC Agnus (8372) */ - AMIGAHW_DECLARE(ALICE_PAL); /* PAL Alice (8374) */ - AMIGAHW_DECLARE(ALICE_NTSC); /* NTSC Alice (8374) */ - AMIGAHW_DECLARE(MAGIC_REKICK); /* A3000 Magic Hard Rekick */ - AMIGAHW_DECLARE(ZORRO); /* Zorro AutoConfig */ - } hw_present; -}; - -#else /* __ASSEMBLY__ */ - -BI_amiga_model = BI_un -BI_amiga_num_autcon = BI_amiga_model+4 -BI_amiga_autocon = BI_amiga_num_autcon+4 -#ifdef HACKER_KERNEL -BI_amiga_exit_func = BI_amiga_autocon+(CD_sizeof*NUM_AUTO) -BI_amiga_chip_addr = BI_amiga_exit_func+4 -BI_amiga_chip_size = BI_amiga_chip_addr+4 -#else -BI_amiga_chip_size = BI_amiga_autocon+(CD_sizeof*NUM_AUTO) -#endif -BI_amiga_vblank = BI_amiga_chip_size+4 -BI_amiga_psfreq = BI_amiga_vblank+1 -BI_amiga_eclock = BI_amiga_psfreq+1 -BI_amiga_chipset = BI_amiga_eclock+4 -BI_amiga_hw_present = BI_amiga_chipset+4 - -#endif /* __ASSEMBLY__ */ - -/* Atari specific part of bootinfo */ - -/* - * Define several Hardware-Chips for indication so that for the ATARI we do - * no longer decide whether it is a Falcon or other machine . It's just - * important what hardware the machine uses - */ - -/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */ - -#ifndef __ASSEMBLY__ - -#define ATARIHW_DECLARE(name) unsigned name : 1 -#define ATARIHW_SET(name) (boot_info.bi_atari.hw_present.name = 1) -#define ATARIHW_PRESENT(name) (boot_info.bi_atari.hw_present.name) - -struct bi_Atari { - struct { - /* video hardware */ - ATARIHW_DECLARE(STND_SHIFTER); /* ST-Shifter - no base low ! */ - ATARIHW_DECLARE(EXTD_SHIFTER); /* STe-Shifter - 24 bit address */ - ATARIHW_DECLARE(TT_SHIFTER); /* TT-Shifter */ - ATARIHW_DECLARE(VIDEL_SHIFTER); /* Falcon-Shifter */ - /* sound hardware */ - ATARIHW_DECLARE(YM_2149); /* Yamaha YM 2149 */ - ATARIHW_DECLARE(PCM_8BIT); /* PCM-Sound in STe-ATARI */ - ATARIHW_DECLARE(CODEC); /* CODEC Sound (Falcon) */ - /* disk storage interfaces */ - ATARIHW_DECLARE(TT_SCSI); /* Directly mapped NCR5380 */ - ATARIHW_DECLARE(ST_SCSI); /* NCR5380 via ST-DMA (Falcon) */ - ATARIHW_DECLARE(ACSI); /* Standard ACSI like in STs */ - ATARIHW_DECLARE(IDE); /* IDE Interface */ - ATARIHW_DECLARE(FDCSPEED); /* 8/16 MHz switch for FDC */ - /* other I/O hardware */ - ATARIHW_DECLARE(ST_MFP); /* The ST-MFP (there should - be no Atari without - it... but who knows?) */ - ATARIHW_DECLARE(TT_MFP); /* 2nd MFP */ - ATARIHW_DECLARE(SCC); /* Serial Communications Contr. */ - ATARIHW_DECLARE(ST_ESCC); /* SCC Z83230 in an ST */ - ATARIHW_DECLARE(ANALOG_JOY); /* Paddle Interface for STe - and Falcon */ - ATARIHW_DECLARE(MICROWIRE); /* Microwire Interface */ - /* DMA */ - ATARIHW_DECLARE(STND_DMA); /* 24 Bit limited ST-DMA */ - ATARIHW_DECLARE(EXTD_DMA); /* 32 Bit ST-DMA */ - ATARIHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ - ATARIHW_DECLARE(SCC_DMA); /* DMA for the SCC */ - /* real time clocks */ - ATARIHW_DECLARE(TT_CLK); /* TT compatible clock chip */ - ATARIHW_DECLARE(MSTE_CLK); /* Mega ST(E) clock chip */ - /* supporting hardware */ - ATARIHW_DECLARE(SCU); /* System Control Unit */ - ATARIHW_DECLARE(BLITTER); /* Blitter */ - ATARIHW_DECLARE(VME); /* VME Bus */ - } hw_present; - unsigned long mch_cookie; /* _MCH cookie from TOS */ -}; - -/* mch_cookie values (upper word) */ -#define ATARI_MCH_ST 0 -#define ATARI_MCH_STE 1 -#define ATARI_MCH_TT 2 -#define ATARI_MCH_FALCON 3 - -struct mem_info { - unsigned long addr; /* physical address of memory chunk */ - unsigned long size; /* length of memory chunk (in bytes) */ -}; - -#else /* __ASSEMBLY__ */ - -MI_addr = 0 -MI_size = MI_addr+4 -MI_sizeof = MI_size+4 - -#endif /* __ASSEMBLY__ */ - -#define NUM_MEMINFO 4 - -#define MACH_AMIGA 1 -#define MACH_ATARI 2 -#define MACH_MAC 3 - -/* - * CPU and FPU types - */ - -#define CPUB_68020 0 -#define CPUB_68030 1 -#define CPUB_68040 2 -#define CPUB_68060 3 -#define FPUB_68881 5 -#define FPUB_68882 6 -#define FPUB_68040 7 /* Internal FPU */ -#define FPUB_68060 8 /* Internal FPU */ - -#define CPU_68020 (1<> 16) & 0xffff) -#define BI_VERSION_MINOR(v) ((v) & 0xffff) - -#ifndef __ASSEMBLY__ - -struct bootversion { - unsigned short branch; - unsigned long magic; - struct { - unsigned long machtype; - unsigned long version; - } machversions[0]; -}; - -#endif /* __ASSEMBLY__ */ - -#define AMIGA_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) -#define ATARI_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) - -#endif - - -#endif /* _M68K_SETUP_H */ +#ifndef _CRIS_SETUP_H +#define _CRIS_SETUP_H +#endif diff --git a/include/asm-cris/signal.h b/include/asm-cris/signal.h index bd6f9484dbf..1335bf27d8e 100644 --- a/include/asm-cris/signal.h +++ b/include/asm-cris/signal.h @@ -85,13 +85,13 @@ typedef unsigned long sigset_t; * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 +#define SA_NOCLDSTOP 0x00000001u +#define SA_NOCLDWAIT 0x00000002u +#define SA_SIGINFO 0x00000004u +#define SA_ONSTACK 0x08000000u +#define SA_RESTART 0x10000000u +#define SA_NODEFER 0x40000000u +#define SA_RESETHAND 0x80000000u #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND diff --git a/include/asm-cris/smp_lock.h b/include/asm-cris/smp_lock.h deleted file mode 100644 index 085543014cd..00000000000 --- a/include/asm-cris/smp_lock.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __CRIS_SMPLOCK_H -#define __CRIS_SMPLOCK_H - -#include - -#ifdef CONFIG_SMP - -#error "SMP is not supported for CRIS" - -/* - * Locking the kernel - */ - -extern __inline void lock_kernel(void) -{ - unsigned long flags; - int proc = smp_processor_id(); - - save_flags(flags); - cli(); - /* set_bit works atomic in SMP machines */ - while(set_bit(0, (void *)&kernel_flag)) - { - /* - * We just start another level if we have the lock - */ - if (proc == active_kernel_processor) - break; - do - { -#ifdef __SMP_PROF__ - smp_spins[smp_processor_id()]++; -#endif - /* - * Doing test_bit here doesn't lock the bus - */ - if (test_bit(proc, (void *)&smp_invalidate_needed)) - if (clear_bit(proc, (void *)&smp_invalidate_needed)) - local_flush_tlb(); - } - while(test_bit(0, (void *)&kernel_flag)); - } - /* - * We got the lock, so tell the world we are here and increment - * the level counter - */ - active_kernel_processor = proc; - kernel_counter++; - restore_flags(flags); -} - -extern __inline void unlock_kernel(void) -{ - unsigned long flags; - save_flags(flags); - cli(); - /* - * If it's the last level we have in the kernel, then - * free the lock - */ - if (kernel_counter == 0) - panic("Kernel counter wrong.\n"); /* FIXME: Why is kernel_counter sometimes 0 here? */ - - if(! --kernel_counter) - { - active_kernel_processor = NO_PROC_ID; - clear_bit(0, (void *)&kernel_flag); - } - restore_flags(flags); -} - -#endif -#endif diff --git a/include/asm-cris/sync_serial.h b/include/asm-cris/sync_serial.h deleted file mode 100644 index 423b46175e5..00000000000 --- a/include/asm-cris/sync_serial.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ioctl defines for synchrnous serial port driver - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Mikael Starvik - * - */ - -#ifndef SYNC_SERIAL_H -#define SYNC_SERIAL_H - -#include - -#define SSP_SPEED _IOR('S', 0, unsigned int) -#define SSP_MODE _IOR('S', 1, unsigned int) -#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) -#define SSP_IPOLARITY _IOR('S', 3, unsigned int) -#define SSP_OPOLARITY _IOR('S', 4, unsigned int) -#define SSP_SPI _IOR('S', 5, unsigned int) - -/* Values for SSP_SPEED */ -#define SSP150 0 -#define SSP300 1 -#define SSP600 2 -#define SSP1200 3 -#define SSP2400 4 -#define SSP4800 5 -#define SSP9600 6 -#define SSP19200 7 -#define SSP28800 8 -#define SSP57600 9 -#define SSP115200 10 -#define SSP230400 11 -#define SSP460800 12 -#define SSP921600 13 -#define SSP3125000 14 -#define CODEC 15 - -#define FREQ_4MHz 0 -#define FREQ_2MHz 1 -#define FREQ_1MHz 2 -#define FREQ_512kHz 3 -#define FREQ_256kHz 4 -#define FREQ_128kHz 5 -#define FREQ_64kHz 6 -#define FREQ_32kHz 7 - -/* Used by application to set CODEC divider, word rate and frame rate */ -#define CODEC_VAL(freq, word, frame) (CODEC | (freq << 8) | (word << 16) | (frame << 28)) - -/* Used by driver to extract speed */ -#define GET_SPEED(x) (x & 0xff) -#define GET_FREQ(x) ((x & 0xff00) >> 8) -#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) -#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) - -/* Values for SSP_MODE */ -#define MASTER_OUTPUT 0 -#define SLAVE_OUTPUT 1 -#define MASTER_INPUT 2 -#define SLAVE_INPUT 3 -#define MASTER_BIDIR 4 -#define SLAVE_BIDIR 5 - -/* Values for SSP_FRAME_SYNC */ -#define NORMAL_SYNC 1 -#define EARLY_SYNC 2 -#define BIT_SYNC 4 -#define WORD_SYNC 8 -#define EXTENDED_SYNC 0x10 -#define SYNC_OFF 0x20 -#define SYNC_ON 0x40 -#define WORD_SIZE_8 0x80 -#define WORD_SIZE_12 0x100 -#define WORD_SIZE_16 0x200 -#define WORD_SIZE_24 0x300 -#define WORD_SIZE_32 0x800 -#define BIT_ORDER_LSB 0x1000 -#define BIT_ORDER_MSB 0x2000 -#define FLOW_CONTROL_ENABLE 0x4000 -#define FLOW_CONTROL_DISABLE 0x8000 -#define CLOCK_GATED 0x10000 -#define CLOCK_NOT_GATED 0x20000 - -/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ -#define CLOCK_NORMAL 1 -#define CLOCK_INVERT 2 -#define FRAME_NORMAL 4 -#define FRAME_INVERT 8 -#define STATUS_NORMAL 0x10 -#define STATUS_INVERT 0x20 - -/* Values for SSP_SPI */ -#define SPI_MASTER 0 -#define SPI_SLAVE 1 -#endif diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h dissimilarity index 67% index 63d2dee8172..f9cf8026257 100644 --- a/include/asm-cris/system.h +++ b/include/asm-cris/system.h @@ -1,178 +1,72 @@ -#ifndef __ASM_CRIS_SYSTEM_H -#define __ASM_CRIS_SYSTEM_H - -#include - -#include - -/* the switch_to macro calls resume, an asm function in entry.S which does the actual - * task switching. - */ - -extern struct task_struct *resume(struct task_struct *prev, struct task_struct *next, int); -#define prepare_to_switch() do { } while(0) -#define switch_to(prev,next,last) last = resume(prev,next, \ - (int)&((struct task_struct *)0)->thread) - -/* read the CPU version register */ - -static inline unsigned long rdvr(void) { - unsigned char vr; - __asm__ volatile ("move $vr,%0" : "=rm" (vr)); - return vr; -} - -/* read/write the user-mode stackpointer */ - -static inline unsigned long rdusp(void) { - unsigned long usp; - __asm__ __volatile__("move $usp,%0" : "=rm" (usp)); - return usp; -} - -#define wrusp(usp) \ - __asm__ __volatile__("move %0,$usp" : /* no outputs */ : "rm" (usp)) - -/* read the current stackpointer */ - -static inline unsigned long rdsp(void) { - unsigned long sp; - __asm__ __volatile__("move.d $sp,%0" : "=rm" (sp)); - return sp; -} - -static inline unsigned long _get_base(char * addr) -{ - return 0; -} - -#define nop() __asm__ __volatile__ ("nop"); - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -#define tas(ptr) (xchg((ptr),1)) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) - -#if 0 -/* use these and an oscilloscope to see the fraction of time we're running with IRQ's disabled */ -/* it assumes the LED's are on port 0x90000000 of course. */ -#define sti() __asm__ __volatile__ ( "ei\n\tpush $r0\n\tmoveq 0,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0" ); -#define cli() __asm__ __volatile__ ( "di\n\tpush $r0\n\tmove.d 0x40000,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0"); -#define save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); -#define restore_flags(x) __asm__ __volatile__ ("move %0,$ccr\n\tbtstq 5,%0\n\tbpl 1f\n\tnop\n\tpush $r0\n\tmoveq 0,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0\n1:\n" : : "r" (x) : "memory"); -#else -#define local_irq_disable() __asm__ __volatile__ ( "di"); -#define local_irq_enable() __asm__ __volatile__ ( "ei" ); -#define local_save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); -#define local_irq_restore(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); - -/* For spinlocks etc */ -#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); -#define local_irq_restore(x) restore_flags(x) - -#define local_irq_disable() cli() -#define local_irq_enable() sti() - -#endif - -#define cli() local_irq_disable() -#define sti() local_irq_enable() -#define save_flags(x) local_save_flags(x) -#define restore_flags(x) local_irq_restore(x) -#define save_and_cli(x) do { local_save_flags(x); cli(); } while(0) - -static inline unsigned long __xchg(unsigned long x, void * ptr, int size) -{ - /* since Etrax doesn't have any atomic xchg instructions, we need to disable - irq's (if enabled) and do it with move.d's */ -#if 0 - unsigned int flags; - save_flags(flags); /* save flags, including irq enable bit */ - cli(); /* shut off irq's */ - switch (size) { - case 1: - __asm__ __volatile__ ( - "move.b %0,r0\n\t" - "move.b %1,%0\n\t" - "move.b r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - case 2: - __asm__ __volatile__ ( - "move.w %0,r0\n\t" - "move.w %1,%0\n\t" - "move.w r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - case 4: - __asm__ __volatile__ ( - "move.d %0,r0\n\t" - "move.d %1,%0\n\t" - "move.d r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - } - restore_flags(flags); /* restore irq enable bit */ - return x; -#else - unsigned long flags,temp; - save_flags(flags); /* save flags, including irq enable bit */ - cli(); /* shut off irq's */ - switch (size) { - case 1: - *((unsigned char *)&temp) = x; - x = *(unsigned char *)ptr; - *(unsigned char *)ptr = *((unsigned char *)&temp); - break; - case 2: - *((unsigned short *)&temp) = x; - x = *(unsigned short *)ptr; - *(unsigned short *)ptr = *((unsigned short *)&temp); - break; - case 4: - temp = x; - x = *(unsigned long *)ptr; - *(unsigned long *)ptr = temp; - break; - } - restore_flags(flags); /* restore irq enable bit */ - return x; -#endif -} - -#define mb() __asm__ __volatile__ ("" : : : "memory") -#define rmb() mb() -#define wmb() mb() -#define read_barrier_depends() do { } while(0) -#define set_mb(var, value) do { var = value; mb(); } while (0) -#define set_wmb(var, value) do { var = value; wmb(); } while (0) - -#ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() -#else -#define smp_mb() barrier() -#define smp_rmb() barrier() -#define smp_wmb() barrier() -#define smp_read_barrier_depends() do { } while(0) -#endif - -#define iret() - -/* - * disable hlt during certain critical i/o operations - */ -#define HAVE_DISABLE_HLT -void disable_hlt(void); -void enable_hlt(void); - -#endif +#ifndef __ASM_CRIS_SYSTEM_H +#define __ASM_CRIS_SYSTEM_H + +#include + +/* the switch_to macro calls resume, an asm function in entry.S which does the actual + * task switching. + */ + +extern struct task_struct *resume(struct task_struct *prev, struct task_struct *next, int); +#define prepare_to_switch() do { } while(0) +#define switch_to(prev,next,last) last = resume(prev,next, \ + (int)&((struct task_struct *)0)->thread) + +#define barrier() __asm__ __volatile__("": : :"memory") +#define mb() barrier() +#define rmb() mb() +#define wmb() mb() +#define read_barrier_depends() do { } while(0) +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) +#endif + +#define iret() + +/* + * disable hlt during certain critical i/o operations + */ +#define HAVE_DISABLE_HLT +void disable_hlt(void); +void enable_hlt(void); + +extern inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + /* since Etrax doesn't have any atomic xchg instructions, we need to disable + irq's (if enabled) and do it with move.d's */ + unsigned long flags,temp; + local_save_flags(flags); /* save flags, including irq enable bit */ + local_irq_disable(); /* shut off irq's */ + switch (size) { + case 1: + *((unsigned char *)&temp) = x; + x = *(unsigned char *)ptr; + *(unsigned char *)ptr = *((unsigned char *)&temp); + break; + case 2: + *((unsigned short *)&temp) = x; + x = *(unsigned short *)ptr; + *(unsigned short *)ptr = *((unsigned short *)&temp); + break; + case 4: + temp = x; + x = *(unsigned long *)ptr; + *(unsigned long *)ptr = temp; + break; + } + local_irq_restore(flags); /* restore irq enable bit */ + return x; +} + +#endif diff --git a/include/asm-cris/termbits.h b/include/asm-cris/termbits.h index cea712a634f..4f35a7d9544 100644 --- a/include/asm-cris/termbits.h +++ b/include/asm-cris/termbits.h @@ -88,6 +88,30 @@ struct termios { #define FF1 0100000 /* c_cflag bit meaning */ +/* + * 3 2 1 + * 10 987 654 321 098 765 432 109 876 543 210 + * | | ||| CBAUD + * obaud + * + * ||CSIZE + * + * |CSTOP + * |CREAD + * |CPARENB + * + * |CPARODD + * |HUPCL + * |CLOCAL + * |CBAUDEX + * 10 987 654 321 098 765 432 109 876 543 210 + * | || || CIBAUD, IBSHIFT=16 + * ibaud + * |CMSPAR + * | CRTSCTS + * x x xxx xxx x x xx Free bits + */ + #define CBAUD 0010017 #define B0 0000000 /* hang up */ #define B50 0000001 @@ -123,11 +147,18 @@ struct termios { #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 -/* etrax100 supports these additional three baud rates */ -#define B921600 0010005 -#define B1843200 0010006 -#define B6250000 0010007 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +/* etrax supports these additional three baud rates */ +#define B921600 0010005 +#define B1843200 0010006 +#define B6250000 0010007 +/* etrax 200 supports this as well */ +#define B12500000 0010010 +#define CIBAUD 002003600000 /* input baud rate */ +/* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX + * shifted left IBSHIFT bits. + */ +#define IBSHIFT 16 +#define CMSPAR 010000000000 /* mark or space (stick) parity - PARODD=space*/ #define CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ diff --git a/include/asm-cris/termios.h b/include/asm-cris/termios.h index cc60e3781b0..5ce1023c5d7 100644 --- a/include/asm-cris/termios.h +++ b/include/asm-cris/termios.h @@ -3,6 +3,7 @@ #include #include +#include struct winsize { unsigned short ws_row; diff --git a/include/asm-cris/thread_info.h b/include/asm-cris/thread_info.h new file mode 100644 index 00000000000..f191637ac9e --- /dev/null +++ b/include/asm-cris/thread_info.h @@ -0,0 +1,100 @@ +/* thread_info.h: CRIS low-level thread information + * + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + * + * CRIS port by Axis Communications + */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ +#include +#include +#include +#include +#endif + + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - this struct shares the supervisor stack pages + * - if the contents of this structure are changed, the assembly constants must also be changed + */ +#ifndef __ASSEMBLY__ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; /* current CPU */ + __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ + + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user-thead + 0-0xFFFFFFFF for kernel-thread + */ + struct restart_block restart_block; + __u8 supervisor_stack[0]; +}; + +#endif + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * macros/functions for gaining access to the thread information structure + * + * preempt_count needs to be 1 initially, until the scheduler is functional. + */ +#ifndef __ASSEMBLY__ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) + +/* thread information allocation */ +#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#endif /* !__ASSEMBLY__ */ + +/* + * thread information flags + * - these are process state flags that various assembly files may need to access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ + +#define _TIF_SYSCALL_TRACE (1< + +/* + * We don't have a cycle-counter.. but we do not support SMP anyway where this is + * used so it does not matter. + */ + +typedef unsigned int cycles_t; + +extern inline cycles_t get_cycles(void) +{ + return 0; +} + +#endif diff --git a/include/asm-cris/tlb.h b/include/asm-cris/tlb.h index 69c0faa9319..6cc26debe40 100644 --- a/include/asm-cris/tlb.h +++ b/include/asm-cris/tlb.h @@ -1 +1,17 @@ +#ifndef _CRIS_TLB_H +#define _CRIS_TLB_H + +#include + +/* + * cris doesn't need any special per-pte or + * per-vma handling.. + */ +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) #include + +#endif diff --git a/include/asm-cris/tlbflush.h b/include/asm-cris/tlbflush.h new file mode 100644 index 00000000000..1781fe1a32f --- /dev/null +++ b/include/asm-cris/tlbflush.h @@ -0,0 +1,43 @@ +#ifndef _CRIS_TLBFLUSH_H +#define _CRIS_TLBFLUSH_H + +#include +#include +#include +#include +#include + +/* + * TLB flushing (implemented in arch/cris/mm/tlb.c): + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(mm, start, end) flushes a range of pages + * + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr); +extern void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, + unsigned long end); + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + /* CRIS does not keep any page table caches in TLB */ +} + + +extern inline void flush_tlb(void) +{ + flush_tlb_mm(current->mm); +} + +#define flush_tlb_kernel_range(start, end) flush_tlb_all() + +#endif /* _CRIS_TLBFLUSH_H */ diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h dissimilarity index 62% index 41d66748c16..7532cd76d0a 100644 --- a/include/asm-cris/uaccess.h +++ b/include/asm-cris/uaccess.h @@ -1,1095 +1,443 @@ -/* - * Authors: Bjorn Wesen (bjornw@axis.com) - * Hans-Peter Nilsson (hp@axis.com) - * - * $Log: uaccess.h,v $ - * Revision 1.8 2001/10/29 13:01:48 bjornw - * Removed unused variable tmp2 in strnlen_user - * - * Revision 1.7 2001/10/02 12:44:52 hp - * Add support for 64-bit put_user/get_user - * - * Revision 1.6 2001/10/01 14:51:17 bjornw - * Added register prefixes and removed underscores - * - * Revision 1.5 2000/10/25 03:33:21 hp - * - Provide implementation for everything else but get_user and put_user; - * copying inline to/from user for constant length 0..16, 20, 24, and - * clearing for 0..4, 8, 12, 16, 20, 24, strncpy_from_user and strnlen_user - * always inline. - * - Constraints for destination addr in get_user cannot be memory, only reg. - * - Correct labels for PC at expected fault points. - * - Nits with assembly code. - * - Don't use statement expressions without value; use "do {} while (0)". - * - Return correct values from __generic_... functions. - * - * Revision 1.4 2000/09/12 16:28:25 bjornw - * * Removed comments from the get/put user asm code - * * Constrains for destination addr in put_user cannot be memory, only reg - * - * Revision 1.3 2000/09/12 14:30:20 bjornw - * MAX_ADDR_USER does not exist anymore - * - * Revision 1.2 2000/07/13 15:52:48 bjornw - * New user-access functions - * - * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw - * CRIS architecture, working draft - * - * - * - */ - -/* Asm:s have been tweaked (within the domain of correctness) to give - satisfactory results for "gcc version 2.96 20000427 (experimental)". - - Check regularly... - - Register $r9 is chosen for temporaries, being a call-clobbered register - first in line to be used (notably for local blocks), not colliding with - parameter registers. */ - -#ifndef _CRIS_UACCESS_H -#define _CRIS_UACCESS_H - -#ifndef __ASSEMBLY__ -#include -#include -#include -#include - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ - -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -/* addr_limit is the maximum accessible address for the task. we misuse - * the KERNEL_DS and USER_DS values to both assign and compare the - * addr_limit values through the equally misnamed get/set_fs macros. - * (see above) - */ - -#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) -#define USER_DS MAKE_MM_SEG(TASK_SIZE) - -#define get_ds() (KERNEL_DS) -#define get_fs() (current->addr_limit) -#define set_fs(x) (current->addr_limit = (x)) - -#define segment_eq(a,b) ((a).seg == (b).seg) - -#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) -#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size))) -#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) -#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) - -extern inline int verify_area(int type, const void * addr, unsigned long size) -{ - return access_ok(type,addr,size) ? 0 : -EFAULT; -} - - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry -{ - unsigned long insn, fixup; -}; - -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * This gets kind of ugly. We want to return _two_ values in "get_user()" - * and yet we don't want to do any pointers, because that is too much - * of a performance impact. Thus we have a few rather ugly macros here, - * and hide all the ugliness from the user. - * - * The "__xxx" versions of the user access functions are versions that - * do not verify the address space, that must have been done previously - * with a separate "access_ok()" call (this is used when we do multiple - * accesses to the same area of user memory). - * - * As we use the same address space for kernel and user data on - * CRIS, we can just do these as direct assignments. (Of course, the - * exception handling means that it's no longer "just"...) - */ -#define get_user(x,ptr) \ - __get_user_check((x),(ptr),sizeof(*(ptr))) -#define put_user(x,ptr) \ - __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) - -#define __get_user(x,ptr) \ - __get_user_nocheck((x),(ptr),sizeof(*(ptr))) -#define __put_user(x,ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) - -extern long __put_user_bad(void); - -#define __put_user_nocheck(x,ptr,size) \ -({ \ - long __pu_err; \ - __put_user_size((x),(ptr),(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_check(x,ptr,size) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ - __put_user_size((x),__pu_addr,(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __put_user_asm_64(x,ptr,retval); break; \ - default: __put_user_bad(); \ - } \ -} while (0) - -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct *)(x)) - -/* - * We don't tell gcc that we are accessing memory, but this is OK - * because we do not write to any memory gcc knows about, so there - * are no aliasing issues. - * - * Note that PC at a fault is the address *after* the faulting - * instruction. - */ -#define __put_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - " "op" %1,[%2]\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " jump 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .previous\n" \ - : "=r" (err) \ - : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) - -#define __put_user_asm_64(x, addr, err) \ - __asm__ __volatile__( \ - " move.d %M1,[%2]\n" \ - "2: move.d %H1,[%2+4]\n" \ - "4:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " jump 4b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .dword 4b,3b\n" \ - " .previous\n" \ - : "=r" (err) \ - : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) - - -#define __get_user_nocheck(x,ptr,size) \ -({ \ - long __gu_err, __gu_val; \ - __get_user_size(__gu_val,(ptr),(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_check(x,ptr,size) \ -({ \ - long __gu_err = -EFAULT, __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - if (access_ok(VERIFY_READ,__gu_addr,size)) \ - __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -extern long __get_user_bad(void); - -#define __get_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __get_user_asm_64(x,ptr,retval); break; \ - default: (x) = __get_user_bad(); \ - } \ -} while (0) - -/* See comment before __put_user_asm. */ - -#define __get_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - " "op" [%2],%1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " moveq 0,%1\n" \ - " jump 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .previous\n" \ - : "=r" (err), "=r" (x) \ - : "r" (addr), "g" (-EFAULT), "0" (err)) - -#define __get_user_asm_64(x, addr, err) \ - __asm__ __volatile__( \ - " move.d [%2],%M1\n" \ - "2: move.d [%2+4],%H1\n" \ - "4:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " moveq 0,%1\n" \ - " jump 4b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .dword 4b,3b\n" \ - " .previous\n" \ - : "=r" (err), "=r" (x) \ - : "r" (addr), "g" (-EFAULT), "0" (err)) - -/* More complex functions. Most are inline, but some call functions that - live in lib/usercopy.c */ - -extern unsigned long __copy_user(void *to, const void *from, unsigned long n); -extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n); -extern unsigned long __do_clear_user(void *to, unsigned long n); - -/* - * Copy a null terminated string from userspace. - * - * Must return: - * -EFAULT for an exception - * count if we hit the buffer limit - * bytes copied if we hit a null byte - * (without the null byte) - */ - -static inline long -__do_strncpy_from_user(char *dst, const char *src, long count) -{ - long res; - - if (count == 0) - return 0; - - /* - * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop. - * So do we. - * - * This code is deduced from: - * - * char tmp2; - * long tmp1, tmp3 - * tmp1 = count; - * while ((*dst++ = (tmp2 = *src++)) != 0 - * && --tmp1) - * ; - * - * res = count - tmp1; - * - * with tweaks. - */ - - __asm__ __volatile__ ( - " move.d %3,%0\n" - " move.b [%2+],$r9\n" - "1: beq 2f\n" - " move.b $r9,[%1+]\n" - - " subq 1,%0\n" - " bne 1b\n" - " move.b [%2+],$r9\n" - - "2: sub.d %3,%0\n" - " neg.d %0,%0\n" - "3:\n" - " .section .fixup,\"ax\"\n" - "4: move.d %7,%0\n" - " jump 3b\n" - - /* There's one address for a fault at the first move, and - two possible PC values for a fault at the second move, - being a delay-slot filler. However, the branch-target - for the second move is the same as the first address. - Just so you don't get confused... */ - " .previous\n" - " .section __ex_table,\"a\"\n" - " .dword 1b,4b\n" - " .dword 2b,4b\n" - " .previous" - : "=r" (res), "=r" (dst), "=r" (src), "=r" (count) - : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT) - : "r9"); - - return res; -} - -static inline unsigned long -__generic_copy_to_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - return __copy_user(to,from,n); - return n; -} - -static inline unsigned long -__generic_copy_from_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_READ, from, n)) - return __copy_user_zeroing(to,from,n); - return n; -} - -static inline unsigned long -__generic_clear_user(void *to, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - return __do_clear_user(to,n); - return n; -} - -static inline long -__strncpy_from_user(char *dst, const char *src, long count) -{ - return __do_strncpy_from_user(dst, src, count); -} - -static inline long -strncpy_from_user(char *dst, const char *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - res = __do_strncpy_from_user(dst, src, count); - return res; -} - -/* A few copy asms to build up the more complex ones from. - - Note again, a post-increment is performed regardless of whether a bus - fault occurred in that instruction, and PC for a faulted insn is the - address *after* the insn. */ - -#define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm__ __volatile__ ( \ - COPY \ - "1:\n" \ - " .section .fixup,\"ax\"\n" \ - FIXUP \ - " jump 1b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - TENTRY \ - " .previous\n" \ - : "=r" (to), "=r" (from), "=r" (ret) \ - : "0" (to), "1" (from), "2" (ret) \ - : "r9", "memory") - -#define __asm_copy_from_user_1(to, from, ret) \ - __asm_copy_user_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "2: move.b $r9,[%0+]\n", \ - "3: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 2b,3b\n") - -#define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "2: move.w $r9,[%0+]\n" COPY, \ - "3: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_from_user_2(to, from, ret) \ - __asm_copy_from_user_2x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_3(to, from, ret) \ - __asm_copy_from_user_2x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "4: move.b $r9,[%0+]\n", \ - "5: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "2: move.d $r9,[%0+]\n" COPY, \ - "3: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_from_user_4(to, from, ret) \ - __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_5(to, from, ret) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "4: move.b $r9,[%0+]\n", \ - "5: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "4: move.w $r9,[%0+]\n" COPY, \ - "5: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_from_user_6(to, from, ret) \ - __asm_copy_from_user_6x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_7(to, from, ret) \ - __asm_copy_from_user_6x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "6: move.b $r9,[%0+]\n", \ - "7: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "4: move.d $r9,[%0+]\n" COPY, \ - "5: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_from_user_8(to, from, ret) \ - __asm_copy_from_user_8x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_9(to, from, ret) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "6: move.b $r9,[%0+]\n", \ - "7: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "6: move.w $r9,[%0+]\n" COPY, \ - "7: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_from_user_10(to, from, ret) \ - __asm_copy_from_user_10x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_11(to, from, ret) \ - __asm_copy_from_user_10x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "8: move.b $r9,[%0+]\n", \ - "9: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "6: move.d $r9,[%0+]\n" COPY, \ - "7: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_from_user_12(to, from, ret) \ - __asm_copy_from_user_12x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_13(to, from, ret) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "8: move.b $r9,[%0+]\n", \ - "9: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "8: move.w $r9,[%0+]\n" COPY, \ - "9: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_from_user_14(to, from, ret) \ - __asm_copy_from_user_14x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_15(to, from, ret) \ - __asm_copy_from_user_14x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "10: move.b $r9,[%0+]\n", \ - "11: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 10b,11b\n") - -#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "8: move.d $r9,[%0+]\n" COPY, \ - "9: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_from_user_16(to, from, ret) \ - __asm_copy_from_user_16x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_16x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "10: move.d $r9,[%0+]\n" COPY, \ - "11: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_copy_from_user_20(to, from, ret) \ - __asm_copy_from_user_20x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_20x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "12: move.d $r9,[%0+]\n" COPY, \ - "13: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_copy_from_user_24(to, from, ret) \ - __asm_copy_from_user_24x_cont(to, from, ret, "", "", "") - -/* And now, the to-user ones. */ - -#define __asm_copy_to_user_1(to, from, ret) \ - __asm_copy_user_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n2:\n", \ - "3: addq 1,%2\n", \ - " .dword 2b,3b\n") - -#define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n2:\n" COPY, \ - "3: addq 2,%2\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_to_user_2(to, from, ret) \ - __asm_copy_to_user_2x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_3(to, from, ret) \ - __asm_copy_to_user_2x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n4:\n", \ - "5: addq 1,%2\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n2:\n" COPY, \ - "3: addq 4,%2\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_to_user_4(to, from, ret) \ - __asm_copy_to_user_4x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_5(to, from, ret) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n4:\n", \ - "5: addq 1,%2\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n4:\n" COPY, \ - "5: addq 2,%2\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_to_user_6(to, from, ret) \ - __asm_copy_to_user_6x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_7(to, from, ret) \ - __asm_copy_to_user_6x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n6:\n", \ - "7: addq 1,%2\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n4:\n" COPY, \ - "5: addq 4,%2\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_to_user_8(to, from, ret) \ - __asm_copy_to_user_8x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_9(to, from, ret) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n6:\n", \ - "7: addq 1,%2\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n6:\n" COPY, \ - "7: addq 2,%2\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_to_user_10(to, from, ret) \ - __asm_copy_to_user_10x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_11(to, from, ret) \ - __asm_copy_to_user_10x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n8:\n", \ - "9: addq 1,%2\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n6:\n" COPY, \ - "7: addq 4,%2\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_to_user_12(to, from, ret) \ - __asm_copy_to_user_12x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_13(to, from, ret) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n8:\n", \ - "9: addq 1,%2\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n8:\n" COPY, \ - "9: addq 2,%2\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_to_user_14(to, from, ret) \ - __asm_copy_to_user_14x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_15(to, from, ret) \ - __asm_copy_to_user_14x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n10:\n", \ - "11: addq 1,%2\n", \ - " .dword 10b,11b\n") - -#define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n8:\n" COPY, \ - "9: addq 4,%2\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_to_user_16(to, from, ret) \ - __asm_copy_to_user_16x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_16x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n10:\n" COPY, \ - "11: addq 4,%2\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_copy_to_user_20(to, from, ret) \ - __asm_copy_to_user_20x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_20x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n12:\n" COPY, \ - "13: addq 4,%2\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_copy_to_user_24(to, from, ret) \ - __asm_copy_to_user_24x_cont(to, from, ret, "", "", "") - -/* Define a few clearing asms with exception handlers. */ - -/* This frame-asm is like the __asm_copy_user_cont one, but has one less - input. */ - -#define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm__ __volatile__ ( \ - CLEAR \ - "1:\n" \ - " .section .fixup,\"ax\"\n" \ - FIXUP \ - " jump 1b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - TENTRY \ - " .previous" \ - : "=r" (to), "=r" (ret) \ - : "0" (to), "1" (ret) \ - : "r9", "memory") - -#define __asm_clear_1(to, ret) \ - __asm_clear(to, ret, \ - " clear.b [%0+]\n2:\n", \ - "3: addq 1,%1\n", \ - " .dword 2b,3b\n") - -#define __asm_clear_2(to, ret) \ - __asm_clear(to, ret, \ - " clear.w [%0+]\n2:\n", \ - "3: addq 2,%1\n", \ - " .dword 2b,3b\n") - -#define __asm_clear_3(to, ret) \ - __asm_clear(to, ret, \ - " clear.w [%0+]\n" \ - "2: clear.b [%0+]\n3:\n", \ - "4: addq 2,%1\n" \ - "5: addq 1,%1\n", \ - " .dword 2b,4b\n" \ - " .dword 3b,5b\n") - -#define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear(to, ret, \ - " clear.d [%0+]\n2:\n" CLEAR, \ - "3: addq 4,%1\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_clear_4(to, ret) \ - __asm_clear_4x_cont(to, ret, "", "", "") - -#define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_4x_cont(to, ret, \ - " clear.d [%0+]\n4:\n" CLEAR, \ - "5: addq 4,%1\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_clear_8(to, ret) \ - __asm_clear_8x_cont(to, ret, "", "", "") - -#define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_8x_cont(to, ret, \ - " clear.d [%0+]\n6:\n" CLEAR, \ - "7: addq 4,%1\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_clear_12(to, ret) \ - __asm_clear_12x_cont(to, ret, "", "", "") - -#define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_12x_cont(to, ret, \ - " clear.d [%0+]\n8:\n" CLEAR, \ - "9: addq 4,%1\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_clear_16(to, ret) \ - __asm_clear_16x_cont(to, ret, "", "", "") - -#define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_16x_cont(to, ret, \ - " clear.d [%0+]\n10:\n" CLEAR, \ - "11: addq 4,%1\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_clear_20(to, ret) \ - __asm_clear_20x_cont(to, ret, "", "", "") - -#define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_20x_cont(to, ret, \ - " clear.d [%0+]\n12:\n" CLEAR, \ - "13: addq 4,%1\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_clear_24(to, ret) \ - __asm_clear_24x_cont(to, ret, "", "", "") - -/* Note that if these expand awfully if made into switch constructs, so - don't do that. */ - -static inline unsigned long -__constant_copy_from_user(void *to, const void *from, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_copy_from_user_1(to, from, ret); - else if (n == 2) - __asm_copy_from_user_2(to, from, ret); - else if (n == 3) - __asm_copy_from_user_3(to, from, ret); - else if (n == 4) - __asm_copy_from_user_4(to, from, ret); - else if (n == 5) - __asm_copy_from_user_5(to, from, ret); - else if (n == 6) - __asm_copy_from_user_6(to, from, ret); - else if (n == 7) - __asm_copy_from_user_7(to, from, ret); - else if (n == 8) - __asm_copy_from_user_8(to, from, ret); - else if (n == 9) - __asm_copy_from_user_9(to, from, ret); - else if (n == 10) - __asm_copy_from_user_10(to, from, ret); - else if (n == 11) - __asm_copy_from_user_11(to, from, ret); - else if (n == 12) - __asm_copy_from_user_12(to, from, ret); - else if (n == 13) - __asm_copy_from_user_13(to, from, ret); - else if (n == 14) - __asm_copy_from_user_14(to, from, ret); - else if (n == 15) - __asm_copy_from_user_15(to, from, ret); - else if (n == 16) - __asm_copy_from_user_16(to, from, ret); - else if (n == 20) - __asm_copy_from_user_20(to, from, ret); - else if (n == 24) - __asm_copy_from_user_24(to, from, ret); - else - ret = __generic_copy_from_user(to, from, n); - - return ret; -} - -/* Ditto, don't make a switch out of this. */ - -static inline unsigned long -__constant_copy_to_user(void *to, const void *from, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_copy_to_user_1(to, from, ret); - else if (n == 2) - __asm_copy_to_user_2(to, from, ret); - else if (n == 3) - __asm_copy_to_user_3(to, from, ret); - else if (n == 4) - __asm_copy_to_user_4(to, from, ret); - else if (n == 5) - __asm_copy_to_user_5(to, from, ret); - else if (n == 6) - __asm_copy_to_user_6(to, from, ret); - else if (n == 7) - __asm_copy_to_user_7(to, from, ret); - else if (n == 8) - __asm_copy_to_user_8(to, from, ret); - else if (n == 9) - __asm_copy_to_user_9(to, from, ret); - else if (n == 10) - __asm_copy_to_user_10(to, from, ret); - else if (n == 11) - __asm_copy_to_user_11(to, from, ret); - else if (n == 12) - __asm_copy_to_user_12(to, from, ret); - else if (n == 13) - __asm_copy_to_user_13(to, from, ret); - else if (n == 14) - __asm_copy_to_user_14(to, from, ret); - else if (n == 15) - __asm_copy_to_user_15(to, from, ret); - else if (n == 16) - __asm_copy_to_user_16(to, from, ret); - else if (n == 20) - __asm_copy_to_user_20(to, from, ret); - else if (n == 24) - __asm_copy_to_user_24(to, from, ret); - else - ret = __generic_copy_to_user(to, from, n); - - return ret; -} - -/* No switch, please. */ - -static inline unsigned long -__constant_clear_user(void *to, unsigned long n) -{ - unsigned long ret = 0; - if (n == 0) - ; - else if (n == 1) - __asm_clear_1(to, ret); - else if (n == 2) - __asm_clear_2(to, ret); - else if (n == 3) - __asm_clear_3(to, ret); - else if (n == 4) - __asm_clear_4(to, ret); - else if (n == 8) - __asm_clear_8(to, ret); - else if (n == 12) - __asm_clear_12(to, ret); - else if (n == 16) - __asm_clear_16(to, ret); - else if (n == 20) - __asm_clear_20(to, ret); - else if (n == 24) - __asm_clear_24(to, ret); - else - ret = __generic_clear_user(to, n); - - return ret; -} - - -#define clear_user(to, n) \ -(__builtin_constant_p(n) ? \ - __constant_clear_user(to, n) : \ - __generic_clear_user(to, n)) - -#define copy_from_user(to, from, n) \ -(__builtin_constant_p(n) ? \ - __constant_copy_from_user(to, from, n) : \ - __generic_copy_from_user(to, from, n)) - -#define copy_to_user(to, from, n) \ -(__builtin_constant_p(n) ? \ - __constant_copy_to_user(to, from, n) : \ - __generic_copy_to_user(to, from, n)) - -/* We let the __ versions of copy_from/to_user inline, because they're often - * used in fast paths and have only a small space overhead. - */ - -static inline unsigned long -__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) -{ - return __copy_user_zeroing(to,from,n); -} - -static inline unsigned long -__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) -{ - return __copy_user(to,from,n); -} - -static inline unsigned long -__generic_clear_user_nocheck(void *to, unsigned long n) -{ - return __do_clear_user(to,n); -} - -/* without checking */ - -#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n)) -#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) -#define __clear_user(to,n) __generic_clear_user_nocheck((to),(n)) - -/* - * Return the size of a string (including the ending 0) - * - * Return length of string in userspace including terminating 0 - * or 0 for error. Return a value greater than N if too long. - */ - -static inline long -strnlen_user(const char *s, long n) -{ - long res, tmp1; - - if (!access_ok(VERIFY_READ, s, 0)) - return 0; - - /* - * This code is deduced from: - * - * tmp1 = n; - * while (tmp1-- > 0 && *s++) - * ; - * - * res = n - tmp1; - * - * (with tweaks). - */ - - __asm__ __volatile__ ( - " move.d %1,$r9\n" - "0:\n" - " ble 1f\n" - " subq 1,$r9\n" - - " test.b [%0+]\n" - " bne 0b\n" - " test.d $r9\n" - "1:\n" - " move.d %1,%0\n" - " sub.d $r9,%0\n" - "2:\n" - " .section .fixup,\"ax\"\n" - - "3: clear.d %0\n" - " jump 2b\n" - - /* There's one address for a fault at the first move, and - two possible PC values for a fault at the second move, - being a delay-slot filler. However, the branch-target - for the second move is the same as the first address. - Just so you don't get confused... */ - " .previous\n" - " .section __ex_table,\"a\"\n" - " .dword 0b,3b\n" - " .dword 1b,3b\n" - " .previous\n" - : "=r" (res), "=r" (tmp1) - : "0" (s), "1" (n) - : "r9"); - - return res; -} - -#define strlen_user(str) strnlen_user((str), 0x7ffffffe) - -#endif /* __ASSEMBLY__ */ - -#endif /* _CRIS_UACCESS_H */ +/* + * Authors: Bjorn Wesen (bjornw@axis.com) + * Hans-Peter Nilsson (hp@axis.com) + * + * $Log: uaccess.h,v $ + * Revision 1.8 2001/10/29 13:01:48 bjornw + * Removed unused variable tmp2 in strnlen_user + * + * Revision 1.7 2001/10/02 12:44:52 hp + * Add support for 64-bit put_user/get_user + * + * Revision 1.6 2001/10/01 14:51:17 bjornw + * Added register prefixes and removed underscores + * + * Revision 1.5 2000/10/25 03:33:21 hp + * - Provide implementation for everything else but get_user and put_user; + * copying inline to/from user for constant length 0..16, 20, 24, and + * clearing for 0..4, 8, 12, 16, 20, 24, strncpy_from_user and strnlen_user + * always inline. + * - Constraints for destination addr in get_user cannot be memory, only reg. + * - Correct labels for PC at expected fault points. + * - Nits with assembly code. + * - Don't use statement expressions without value; use "do {} while (0)". + * - Return correct values from __generic_... functions. + * + * Revision 1.4 2000/09/12 16:28:25 bjornw + * * Removed comments from the get/put user asm code + * * Constrains for destination addr in put_user cannot be memory, only reg + * + * Revision 1.3 2000/09/12 14:30:20 bjornw + * MAX_ADDR_USER does not exist anymore + * + * Revision 1.2 2000/07/13 15:52:48 bjornw + * New user-access functions + * + * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw + * CRIS architecture, working draft + * + * + * + */ + +/* Asm:s have been tweaked (within the domain of correctness) to give + satisfactory results for "gcc version 2.96 20000427 (experimental)". + + Check regularly... + + Register $r9 is chosen for temporaries, being a call-clobbered register + first in line to be used (notably for local blocks), not colliding with + parameter registers. */ + +#ifndef _CRIS_UACCESS_H +#define _CRIS_UACCESS_H + +#ifndef __ASSEMBLY__ +#include +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +/* addr_limit is the maximum accessible address for the task. we misuse + * the KERNEL_DS and USER_DS values to both assign and compare the + * addr_limit values through the equally misnamed get/set_fs macros. + * (see above) + */ + +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) +#define USER_DS MAKE_MM_SEG(TASK_SIZE) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS)) +#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size))) +#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) +#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) + +extern inline int verify_area(int type, const void __user * addr, unsigned long size) +{ + return access_ok(type,addr,size) ? 0 : -EFAULT; +} + + +#include + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + * + * This gets kind of ugly. We want to return _two_ values in "get_user()" + * and yet we don't want to do any pointers, because that is too much + * of a performance impact. Thus we have a few rather ugly macros here, + * and hide all the ugliness from the user. + * + * The "__xxx" versions of the user access functions are versions that + * do not verify the address space, that must have been done previously + * with a separate "access_ok()" call (this is used when we do multiple + * accesses to the same area of user memory). + * + * As we use the same address space for kernel and user data on + * CRIS, we can just do these as direct assignments. (Of course, the + * exception handling means that it's no longer "just"...) + */ +#define get_user(x,ptr) \ + __get_user_check((x),(ptr),sizeof(*(ptr))) +#define put_user(x,ptr) \ + __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) + +#define __get_user(x,ptr) \ + __get_user_nocheck((x),(ptr),sizeof(*(ptr))) +#define __put_user(x,ptr) \ + __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) + +extern long __put_user_bad(void); + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \ + case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \ + case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \ + case 8: __put_user_asm_64(x,ptr,retval); break; \ + default: __put_user_bad(); \ + } \ +} while (0) + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \ + case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \ + case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \ + case 8: __get_user_asm_64(x,ptr,retval); break; \ + default: (x) = __get_user_bad(); \ + } \ +} while (0) + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __put_user_size((x),(ptr),(size),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_check(x,ptr,size) \ +({ \ + long __pu_err = -EFAULT; \ + __typeof__(*(ptr)) *__pu_addr = (ptr); \ + if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ + __put_user_size((x),__pu_addr,(size),__pu_err); \ + __pu_err; \ +}) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct *)(x)) + + + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_err, __gu_val; \ + __get_user_size(__gu_val,(ptr),(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +#define __get_user_check(x,ptr,size) \ +({ \ + long __gu_err = -EFAULT, __gu_val = 0; \ + const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + if (access_ok(VERIFY_READ,__gu_addr,size)) \ + __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ + (x) = (__typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +extern long __get_user_bad(void); + +/* More complex functions. Most are inline, but some call functions that + live in lib/usercopy.c */ + +extern unsigned long __copy_user(void *to, const void *from, unsigned long n); +extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n); +extern unsigned long __do_clear_user(void *to, unsigned long n); + +extern inline unsigned long +__generic_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + return __copy_user(to,from,n); + return n; +} + +extern inline unsigned long +__generic_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + return __copy_user_zeroing(to,from,n); + return n; +} + +extern inline unsigned long +__generic_clear_user(void __user *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + return __do_clear_user(to,n); + return n; +} + +extern inline long +__strncpy_from_user(char *dst, const char __user *src, long count) +{ + return __do_strncpy_from_user(dst, src, count); +} + +extern inline long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + res = __do_strncpy_from_user(dst, src, count); + return res; +} + + +/* Note that if these expand awfully if made into switch constructs, so + don't do that. */ + +extern inline unsigned long +__constant_copy_from_user(void *to, const void __user *from, unsigned long n) +{ + unsigned long ret = 0; + if (n == 0) + ; + else if (n == 1) + __asm_copy_from_user_1(to, from, ret); + else if (n == 2) + __asm_copy_from_user_2(to, from, ret); + else if (n == 3) + __asm_copy_from_user_3(to, from, ret); + else if (n == 4) + __asm_copy_from_user_4(to, from, ret); + else if (n == 5) + __asm_copy_from_user_5(to, from, ret); + else if (n == 6) + __asm_copy_from_user_6(to, from, ret); + else if (n == 7) + __asm_copy_from_user_7(to, from, ret); + else if (n == 8) + __asm_copy_from_user_8(to, from, ret); + else if (n == 9) + __asm_copy_from_user_9(to, from, ret); + else if (n == 10) + __asm_copy_from_user_10(to, from, ret); + else if (n == 11) + __asm_copy_from_user_11(to, from, ret); + else if (n == 12) + __asm_copy_from_user_12(to, from, ret); + else if (n == 13) + __asm_copy_from_user_13(to, from, ret); + else if (n == 14) + __asm_copy_from_user_14(to, from, ret); + else if (n == 15) + __asm_copy_from_user_15(to, from, ret); + else if (n == 16) + __asm_copy_from_user_16(to, from, ret); + else if (n == 20) + __asm_copy_from_user_20(to, from, ret); + else if (n == 24) + __asm_copy_from_user_24(to, from, ret); + else + ret = __generic_copy_from_user(to, from, n); + + return ret; +} + +/* Ditto, don't make a switch out of this. */ + +extern inline unsigned long +__constant_copy_to_user(void __user *to, const void *from, unsigned long n) +{ + unsigned long ret = 0; + if (n == 0) + ; + else if (n == 1) + __asm_copy_to_user_1(to, from, ret); + else if (n == 2) + __asm_copy_to_user_2(to, from, ret); + else if (n == 3) + __asm_copy_to_user_3(to, from, ret); + else if (n == 4) + __asm_copy_to_user_4(to, from, ret); + else if (n == 5) + __asm_copy_to_user_5(to, from, ret); + else if (n == 6) + __asm_copy_to_user_6(to, from, ret); + else if (n == 7) + __asm_copy_to_user_7(to, from, ret); + else if (n == 8) + __asm_copy_to_user_8(to, from, ret); + else if (n == 9) + __asm_copy_to_user_9(to, from, ret); + else if (n == 10) + __asm_copy_to_user_10(to, from, ret); + else if (n == 11) + __asm_copy_to_user_11(to, from, ret); + else if (n == 12) + __asm_copy_to_user_12(to, from, ret); + else if (n == 13) + __asm_copy_to_user_13(to, from, ret); + else if (n == 14) + __asm_copy_to_user_14(to, from, ret); + else if (n == 15) + __asm_copy_to_user_15(to, from, ret); + else if (n == 16) + __asm_copy_to_user_16(to, from, ret); + else if (n == 20) + __asm_copy_to_user_20(to, from, ret); + else if (n == 24) + __asm_copy_to_user_24(to, from, ret); + else + ret = __generic_copy_to_user(to, from, n); + + return ret; +} + +/* No switch, please. */ + +extern inline unsigned long +__constant_clear_user(void __user *to, unsigned long n) +{ + unsigned long ret = 0; + if (n == 0) + ; + else if (n == 1) + __asm_clear_1(to, ret); + else if (n == 2) + __asm_clear_2(to, ret); + else if (n == 3) + __asm_clear_3(to, ret); + else if (n == 4) + __asm_clear_4(to, ret); + else if (n == 8) + __asm_clear_8(to, ret); + else if (n == 12) + __asm_clear_12(to, ret); + else if (n == 16) + __asm_clear_16(to, ret); + else if (n == 20) + __asm_clear_20(to, ret); + else if (n == 24) + __asm_clear_24(to, ret); + else + ret = __generic_clear_user(to, n); + + return ret; +} + + +#define clear_user(to, n) \ +(__builtin_constant_p(n) ? \ + __constant_clear_user(to, n) : \ + __generic_clear_user(to, n)) + +#define copy_from_user(to, from, n) \ +(__builtin_constant_p(n) ? \ + __constant_copy_from_user(to, from, n) : \ + __generic_copy_from_user(to, from, n)) + +#define copy_to_user(to, from, n) \ +(__builtin_constant_p(n) ? \ + __constant_copy_to_user(to, from, n) : \ + __generic_copy_to_user(to, from, n)) + +/* We let the __ versions of copy_from/to_user inline, because they're often + * used in fast paths and have only a small space overhead. + */ + +extern inline unsigned long +__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) +{ + return __copy_user_zeroing(to,from,n); +} + +extern inline unsigned long +__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) +{ + return __copy_user(to,from,n); +} + +extern inline unsigned long +__generic_clear_user_nocheck(void *to, unsigned long n) +{ + return __do_clear_user(to,n); +} + +/* without checking */ + +#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n)) +#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) +#define __clear_user(to,n) __generic_clear_user_nocheck((to),(n)) + +#define strlen_user(str) strnlen_user((str), 0x7ffffffe) + +#endif /* __ASSEMBLY__ */ + +#endif /* _CRIS_UACCESS_H */ diff --git a/include/asm-i386/unistd.h b/include/asm-cris/unistd.h similarity index 70% copy from include/asm-i386/unistd.h copy to include/asm-cris/unistd.h index b1bdc016eed..4911fee8048 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-cris/unistd.h @@ -1,8 +1,10 @@ -#ifndef _ASM_I386_UNISTD_H_ -#define _ASM_I386_UNISTD_H_ +#ifndef _ASM_CRIS_UNISTD_H_ +#define _ASM_CRIS_UNISTD_H_ + +#include /* - * This file contains the system call numbers. + * This file contains the system call numbers, and stub macros for libc. */ #define __NR_restart_syscall 0 @@ -81,7 +83,7 @@ #define __NR_sigpending 73 #define __NR_sethostname 74 #define __NR_setrlimit 75 -#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define __NR_getrlimit 76 #define __NR_getrusage 77 #define __NR_gettimeofday 78 #define __NR_settimeofday 79 @@ -118,7 +120,7 @@ #define __NR_iopl 110 #define __NR_vhangup 111 #define __NR_idle 112 -#define __NR_vm86old 113 +#define __NR_vm86 113 #define __NR_wait4 114 #define __NR_swapoff 115 #define __NR_sysinfo 116 @@ -171,7 +173,7 @@ #define __NR_mremap 163 #define __NR_setresuid 164 #define __NR_getresuid 165 -#define __NR_vm86 166 + #define __NR_query_module 167 #define __NR_poll 168 #define __NR_nfsservctl 169 @@ -225,12 +227,11 @@ #define __NR_pivot_root 217 #define __NR_mincore 218 #define __NR_madvise 219 -#define __NR_madvise1 219 /* delete when C lib stub is removed */ #define __NR_getdents64 220 #define __NR_fcntl64 221 /* 223 is unused */ -#define __NR_gettid 224 -#define __NR_readahead 225 +#define __NR_gettid 224 +#define __NR_readahead 225 #define __NR_setxattr 226 #define __NR_lsetxattr 227 #define __NR_fsetxattr 228 @@ -256,7 +257,6 @@ #define __NR_io_submit 248 #define __NR_io_cancel 249 #define __NR_fadvise64 250 - #define __NR_exit_group 252 #define __NR_lookup_dcookie 253 #define __NR_epoll_create 254 @@ -275,97 +275,11 @@ #define __NR_clock_nanosleep (__NR_timer_create+8) #define __NR_statfs64 268 #define __NR_fstatfs64 269 - + #define NR_syscalls 270 -/* user-visible error numbers are in the range -1 - -124: see */ - -#define __syscall_return(type, res) \ -do { \ - if ((unsigned long)(res) >= (unsigned long)(-125)) { \ - errno = -(res); \ - res = -1; \ - } \ - return (type) (res); \ -} while (0) - -/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ -#define _syscall0(type,name) \ -type name(void) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name)); \ -__syscall_return(type,__res); \ -} - -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1))); \ -__syscall_return(type,__res); \ -} - -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1,type2 arg2) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \ -__syscall_return(type,__res); \ -} -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1,type2 arg2,type3 arg3) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3))); \ -__syscall_return(type,__res); \ -} -#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4))); \ -__syscall_return(type,__res); \ -} - -#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ - type5,arg5) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ -{ \ -long __res; \ -__asm__ volatile ("int $0x80" \ - : "=a" (__res) \ - : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \ -__syscall_return(type,__res); \ -} - -#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ - type5,arg5,type6,arg6) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ -{ \ -long __res; \ -__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \ - : "=a" (__res) \ - : "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ - "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \ - "0" ((long)(arg6))); \ -__syscall_return(type,__res); \ -} #ifdef __KERNEL_SYSCALLS__ @@ -382,18 +296,28 @@ __syscall_return(type,__res); \ * some others too. */ #define __NR__exit __NR_exit -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +extern inline _syscall0(pid_t,setsid) +extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +extern inline _syscall1(int,dup,int,fd) +extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) +extern inline _syscall1(int,close,int,fd) +/* + * Since we define it "external", it collides with the built-in + * definition, which has the "noreturn" attribute and will cause + * complaints. We don't want to use -fno-builtin, so just use a + * different name when in the kernel. + */ +#ifdef __KERNEL__ +#define _exit kernel_syscall_exit #endif +extern inline _syscall1(int,_exit,int,exitcode) +extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +#endif + /* * "Conditional" syscalls @@ -401,8 +325,6 @@ static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) * What we want is __attribute__((weak,alias("sys_ni_syscall"))), * but it doesn't work on all toolchains, so we just do it by hand */ -#ifndef cond_syscall #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); -#endif -#endif /* _ASM_I386_UNISTD_H_ */ +#endif /* _ASM_CRIS_UNISTD_H_ */ diff --git a/include/asm-cris/user.h b/include/asm-cris/user.h index 982f4163bc9..2538e2a003d 100644 --- a/include/asm-cris/user.h +++ b/include/asm-cris/user.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * Core file format: The core file is written in such a way that gdb @@ -27,49 +28,6 @@ * current->start_stack, so we round each of these in order to be able * to write an integer number of pages. */ - -/* User mode registers, used for core dumps. In order to keep ELF_NGREG - sensible we let all registers be 32 bits. The csr registers are included - for future use. */ -struct user_regs_struct { - unsigned long r0; /* General registers. */ - unsigned long r1; - unsigned long r2; - unsigned long r3; - unsigned long r4; - unsigned long r5; - unsigned long r6; - unsigned long r7; - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long sp; /* Stack pointer. */ - unsigned long pc; /* Program counter. */ - unsigned long p0; /* Constant zero (only 8 bits). */ - unsigned long vr; /* Version register (only 8 bits). */ - unsigned long p2; /* Reserved. */ - unsigned long p3; /* Reserved. */ - unsigned long p4; /* Constant zero (only 16 bits). */ - unsigned long ccr; /* Condition code register (only 16 bits). */ - unsigned long p6; /* Reserved. */ - unsigned long mof; /* Multiply overflow register. */ - unsigned long p8; /* Constant zero. */ - unsigned long ibr; /* Not accessible. */ - unsigned long irp; /* Not accessible. */ - unsigned long srp; /* Subroutine return pointer. */ - unsigned long bar; /* Not accessible. */ - unsigned long dccr; /* Dword condition code register. */ - unsigned long brp; /* Not accessible. */ - unsigned long usp; /* User-mode stack pointer. Same as sp when - in user mode. */ - unsigned long csrinstr; /* Internal status registers. */ - unsigned long csraddr; - unsigned long csrdata; -}; - struct user { struct user_regs_struct regs; /* entire machine state */ diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h new file mode 100644 index 00000000000..b0b1805a741 --- /dev/null +++ b/include/asm-generic/div64.h @@ -0,0 +1,54 @@ +#ifndef _ASM_GENERIC_DIV64_H +#define _ASM_GENERIC_DIV64_H +/* + * Copyright (C) 2003 Bernardo Innocenti + * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h + * + * The semantics of do_div() are: + * + * uint32_t do_div(uint64_t *n, uint32_t base) + * { + * uint32_t remainder = *n % base; + * *n = *n / base; + * return remainder; + * } + * + * NOTE: macro parameter n is evaluated multiple times, + * beware of side effects! + */ + +#include +#include + +#if BITS_PER_LONG == 64 + +# define do_div(n,base) ({ \ + uint32_t __base = (base); \ + uint32_t __rem; \ + __rem = ((uint64_t)(n)) % __base; \ + (n) = ((uint64_t)(n)) / __base; \ + __rem; \ + }) + +#elif BITS_PER_LONG == 32 + +extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor) __attribute_pure__; + +# define do_div(n,base) ({ \ + uint32_t __base = (base); \ + uint32_t __rem; \ + if (likely(((n) >> 32) == 0)) { \ + __rem = (uint32_t)(n) % __base; \ + (n) = (uint32_t)(n) / __base; \ + } else \ + __rem = __div64_32(&(n), __base); \ + __rem; \ + }) + +#else /* BITS_PER_LONG == ?? */ + +# error do_div() does not yet support the C64 + +#endif /* BITS_PER_LONG */ + +#endif /* _ASM_GENERIC_DIV64_H */ diff --git a/include/asm-h8300/div64.h b/include/asm-h8300/div64.h index df5634def9d..6cd978cefb2 100644 --- a/include/asm-h8300/div64.h +++ b/include/asm-h8300/div64.h @@ -1,13 +1 @@ -#ifndef H8300_DIV64_H -#define H8300_DIV64_H - -/* n = n / base; return rem; */ - -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; \ -}) - -#endif /* _H8300_DIV64_H */ +#include diff --git a/include/asm-h8300/flat.h b/include/asm-h8300/flat.h index ac3f50610f5..61d9aaf7e0b 100644 --- a/include/asm-h8300/flat.h +++ b/include/asm-h8300/flat.h @@ -5,6 +5,21 @@ #ifndef __H8300_FLAT_H__ #define __H8300_FLAT_H__ -#define flat_argvp_envp_on_stack() 1 +#define flat_stack_align(sp) /* nothing needed */ +#define flat_argvp_envp_on_stack() 1 +#define flat_old_ram_flag(flags) 1 +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) + +/* + * on the H8 a couple of the relocations have an instruction in the + * top byte. As there can only be 24bits of address space, we just + * always preserve that 8bits at the top, when it isn't an instruction + * is is 0 (davidm@snapgear.com) + */ + +#define flat_get_relocate_addr(rel) (rel) +#define flat_get_addr_from_rp(rp, relval) (get_unaligned(rp) & 0x0ffffff) +#define flat_put_addr_at_rp(rp, addr, rel) \ + put_unaligned (((*(char *)(rp)) << 24) | ((addr) & 0x00ffffff), rp) #endif /* __H8300_FLAT_H__ */ diff --git a/include/asm-h8300/mmu_context.h b/include/asm-h8300/mmu_context.h index ffdf723191c..23b555b7b4b 100644 --- a/include/asm-h8300/mmu_context.h +++ b/include/asm-h8300/mmu_context.h @@ -6,7 +6,7 @@ #include #include -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -20,7 +20,7 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) #define destroy_context(mm) do { } while(0) #define deactivate_mm(tsk,mm) do { } while(0) -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { } diff --git a/include/asm-i386/cacheflush.h b/include/asm-i386/cacheflush.h index adc632b9754..d3ce5511dbb 100644 --- a/include/asm-i386/cacheflush.h +++ b/include/asm-i386/cacheflush.h @@ -17,4 +17,9 @@ void global_flush_tlb(void); int change_page_attr(struct page *page, int numpages, pgprot_t prot); +#ifdef CONFIG_DEBUG_PAGEALLOC +/* internal debugging function */ +void kernel_map_pages(struct page *page, int numpages, int enable); +#endif + #endif /* _I386_CACHEFLUSH_H */ diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h index e8b9149f0b2..5a14545af17 100644 --- a/include/asm-i386/hardirq.h +++ b/include/asm-i386/hardirq.h @@ -7,8 +7,6 @@ typedef struct { unsigned int __softirq_pending; - unsigned int __syscall_count; - struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ unsigned long idle_timestamp; unsigned int __nmi_count; /* arch dependent */ unsigned int apic_timer_irqs; /* arch dependent */ diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h index 14b1fa1ebef..938fc136434 100644 --- a/include/asm-i386/mmu_context.h +++ b/include/asm-i386/mmu_context.h @@ -14,16 +14,21 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { #ifdef CONFIG_SMP + unsigned cpu = smp_processor_id(); if (cpu_tlbstate[cpu].state == TLBSTATE_OK) cpu_tlbstate[cpu].state = TLBSTATE_LAZY; #endif } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) { + int cpu = smp_processor_id(); + if (likely(prev != next)) { /* stop flush ipis for the previous mm */ clear_bit(cpu, &prev->cpu_vm_mask); @@ -62,6 +67,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str asm("movl %0,%%fs ; movl %0,%%gs": :"r" (0)) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL,smp_processor_id()) + switch_mm((prev),(next),NULL) #endif diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h index b6138f07c30..d5da17912a8 100644 --- a/include/asm-i386/mmzone.h +++ b/include/asm-i386/mmzone.h @@ -32,8 +32,7 @@ extern struct pglist_data *node_data[]; #define alloc_bootmem_low_pages_node(ignore, x) \ __alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0) -#define node_size(nid) (node_data[nid]->node_size) -#define node_localnr(pfn, nid) ((pfn) - node_data[nid]->node_start_pfn) +#define node_localnr(pfn, nid) ((pfn) - node_data[nid]->node_start_pfn) /* * Following are macros that each numa implmentation must define. @@ -54,7 +53,7 @@ extern struct pglist_data *node_data[]; #define node_end_pfn(nid) \ ({ \ pg_data_t *__pgdat = NODE_DATA(nid); \ - __pgdat->node_start_pfn + __pgdat->node_size; \ + __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \ }) #define local_mapnr(kvaddr) \ diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h index 005ce2e6174..cfcfb5b7a12 100644 --- a/include/asm-i386/timer.h +++ b/include/asm-i386/timer.h @@ -21,8 +21,21 @@ struct timer_opts{ #define TICK_SIZE (tick_nsec / 1000) extern struct timer_opts* select_timer(void); +extern void clock_fallback(void); /* Modifiers for buggy PIT handling */ extern int pit_latch_buggy; + +extern struct timer_opts *cur_timer; +extern int timer_ack; + +/* list of externed timers */ +extern struct timer_opts timer_none; +extern struct timer_opts timer_pit; +extern struct timer_opts timer_tsc; +#ifdef CONFIG_X86_CYCLONE_TIMER +extern struct timer_opts timer_cyclone; +#endif + #endif diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index b1bdc016eed..f39e505e3eb 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -275,8 +275,9 @@ #define __NR_clock_nanosleep (__NR_timer_create+8) #define __NR_statfs64 268 #define __NR_fstatfs64 269 +#define __NR_tgkill 270 -#define NR_syscalls 270 +#define NR_syscalls 271 /* user-visible error numbers are in the range -1 - -124: see */ diff --git a/include/asm-ia64/div64.h b/include/asm-ia64/div64.h dissimilarity index 100% index 08c03f67204..6cd978cefb2 100644 --- a/include/asm-ia64/div64.h +++ b/include/asm-ia64/div64.h @@ -1,20 +1 @@ -#ifndef _ASM_IA64_DIV64_H -#define _ASM_IA64_DIV64_H - -/* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang - * - * vsprintf uses this to divide a 64-bit integer N by a small integer BASE. - * This is incredibly hard on IA-64... - */ - -#define do_div(n,base) \ -({ \ - int _res; \ - _res = ((unsigned long) (n)) % (unsigned) (base); \ - (n) = ((unsigned long) (n)) / (unsigned) (base); \ - _res; \ -}) - -#endif /* _ASM_IA64_DIV64_H */ +#include diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h index a614a1dbbb6..dee1cd007f5 100644 --- a/include/asm-ia64/mmu_context.h +++ b/include/asm-ia64/mmu_context.h @@ -71,7 +71,7 @@ DECLARE_PER_CPU(u8, ia64_need_tlb_flush); extern void wrap_mmu_context (struct mm_struct *mm); static inline void -enter_lazy_tlb (struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb (struct mm_struct *mm, struct task_struct *tsk) { } @@ -198,7 +198,7 @@ activate_mm (struct mm_struct *prev, struct mm_struct *next) activate_context(next); } -#define switch_mm(prev_mm,next_mm,next_task,cpu) activate_mm(prev_mm, next_mm) +#define switch_mm(prev_mm,next_mm,next_task) activate_mm(prev_mm, next_mm) # endif /* ! __ASSEMBLY__ */ #endif /* _ASM_IA64_MMU_CONTEXT_H */ diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h index 1c1bfb1f1fc..56e55b0a506 100644 --- a/include/asm-ia64/processor.h +++ b/include/asm-ia64/processor.h @@ -317,7 +317,7 @@ struct task_struct; /* * Free all resources held by a thread. This is called after the - * parent of DEAD_TASK has collected the exist status of the task via + * parent of DEAD_TASK has collected the exit status of the task via * wait(). */ #define release_thread(dead_task) diff --git a/include/asm-ia64/sn/ate_utils.h b/include/asm-ia64/sn/ate_utils.h deleted file mode 100644 index d2bc0b82095..00000000000 --- a/include/asm-ia64/sn/ate_utils.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _ASM_IA64_SN_ATE_UTILS_H -#define _ASM_IA64_SN_ATE_UTILS_H - -/* $Id: ate_utils.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * struct map X[] .m_size .m_addr - * --- ------------ ----------- - * [0] mapsize(X) unused - * # X[] unused - * [1] map lock * mapwant sv_t * - * map access wait for free map space - * - * mapstart(X)-> [2] # units unit number - * : : : - * [ ] 0 - */ - -#include - -#define ulong_t uint64_t - -struct map -{ - unsigned long m_size; /* number of units available */ - unsigned long m_addr; /* address of first available unit */ -}; - -#define mapstart(X) &X[2] /* start of map array */ - -#define mapsize(X) X[0].m_size /* number of empty slots */ - /* remaining in map array */ -#define maplock(X) (((spinlock_t *) X[1].m_size)) - -#define mapout(X) ((sv_t *) X[1].m_addr) - - -extern ulong_t atealloc(struct map *, size_t); -extern struct map *atemapalloc(ulong_t); -extern void atefree(struct map *, size_t, ulong_t); -extern void atemapfree(struct map *); - -#endif /* _ASM_IA64_SN_ATE_UTILS_H */ - diff --git a/include/asm-ia64/sn/clksupport.h b/include/asm-ia64/sn/clksupport.h index f619c692c81..029eeae1939 100644 --- a/include/asm-ia64/sn/clksupport.h +++ b/include/asm-ia64/sn/clksupport.h @@ -29,12 +29,18 @@ #include typedef long clkreg_t; + extern unsigned long sn_rtc_cycles_per_second; +extern unsigned long sn_rtc_usec_per_cyc; +extern unsigned long sn_rtc_per_itc; +extern unsigned long sn_rtc_delta; + #include #include #include #include +#define RTC_MASK SH_RTC_MASK #define RTC_COUNTER_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) @@ -43,6 +49,7 @@ extern unsigned long sn_rtc_cycles_per_second; #define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) +#define SN_RTC_PER_ITC_SHIFT 34 #define GET_RTC_COUNTER() (*RTC_COUNTER_ADDR) #define rtc_time() GET_RTC_COUNTER() diff --git a/include/asm-ia64/sn/fetchop.h b/include/asm-ia64/sn/fetchop.h index 9a5b9a06b5b..2fb5cfc774b 100644 --- a/include/asm-ia64/sn/fetchop.h +++ b/include/asm-ia64/sn/fetchop.h @@ -68,13 +68,15 @@ typedef struct { /* - * The following APIs are externalized to the kernel to allocate/free fetchop variables. - * fetchop_kalloc_one - Allocate/initialize 1 fetchop variable on the specified cnode. - * fetchop_kfree_one - Free a previously allocated fetchop variable + * The following APIs are externalized to the kernel to allocate/free pages of + * fetchop variables. + * fetchop_kalloc_page - Allocate/initialize 1 fetchop page on the + * specified cnode. + * fetchop_kfree_page - Free a previously allocated fetchop page */ -unsigned long fetchop_kalloc_one(int nid); -void fetchop_kfree_one(unsigned long maddr); +unsigned long fetchop_kalloc_page(int nid); +void fetchop_kfree_page(unsigned long maddr); #endif /* __KERNEL__ */ diff --git a/include/asm-ia64/sn/module.h b/include/asm-ia64/sn/module.h index df95417bf33..3a819fe427c 100644 --- a/include/asm-ia64/sn/module.h +++ b/include/asm-ia64/sn/module.h @@ -14,7 +14,6 @@ extern "C" { #include -#include #include #include @@ -193,8 +192,6 @@ extern int nummodules; extern module_t *module_lookup(moduleid_t id); -extern int get_kmod_info(cmoduleid_t cmod, - module_info_t *mod_info); extern int get_kmod_sys_snum(cmoduleid_t cmod, char *snum); diff --git a/include/asm-ia64/sn/pci/pcibr_private.h b/include/asm-ia64/sn/pci/pcibr_private.h index 86c7ba69184..6e1cfde2c99 100644 --- a/include/asm-ia64/sn/pci/pcibr_private.h +++ b/include/asm-ia64/sn/pci/pcibr_private.h @@ -307,7 +307,7 @@ struct pcibr_intr_wrap_s { */ #define PV854697 (~0) /* PIC: write 64bit regs as 64bits. permanent */ #define PV854827 (~0) /* PIC: fake widget 0xf presence bit. permanent */ -#define PV855271 (~0) /* PIC: use virt chan iff 64-bit device. permanent */ +#define PV855271 (1 << 1) /* PIC: PIC: use virt chan iff 64-bit device. */ #define PV855272 (1 << 1) /* PIC: runaway interrupt WAR */ #define PV856155 (1 << 1) /* PIC: arbitration WAR */ #define PV856864 (1 << 1) /* PIC: lower timeout to free TNUMs quicker */ @@ -367,8 +367,9 @@ struct pcibr_soft_s { iopaddr_t bs_dir_xbase; /* xtalk address for 32-bit PCI direct map */ xwidgetnum_t bs_dir_xport; /* xtalk port for 32-bit PCI direct map */ - struct map *bs_int_ate_map; /* rmalloc map for internal ATEs */ - struct map *bs_ext_ate_map; /* rmalloc map for external ATEs */ + struct resource bs_int_ate_resource;/* root resource for internal ATEs */ + struct resource bs_ext_ate_resource;/* root resource for external ATEs */ + void *bs_allocated_ate_res;/* resource struct allocated */ short bs_int_ate_size; /* number of internal ates */ short bs_bridge_type; /* see defines above */ short bs_bridge_mode; /* see defines above */ @@ -592,6 +593,10 @@ struct pcibr_soft_s { struct pciio_win_map_s bs_swin_map; /* Small window addr space */ struct pciio_win_map_s bs_mem_win_map; /* Memory addr space */ + struct resource bs_io_win_root_resource; /* I/O addr space */ + struct resource bs_swin_root_resource; /* Small window addr space */ + struct resource bs_mem_win_root_resource; /* Memory addr space */ + int bs_bus_addr_status; /* Bus space status */ #define PCIBR_BUS_ADDR_MEM_FREED 1 /* Reserved PROM mem addr freed */ diff --git a/include/asm-ia64/sn/pci/pciio.h b/include/asm-ia64/sn/pci/pciio.h index e7f47d3240b..bb03dc1a6ac 100644 --- a/include/asm-ia64/sn/pci/pciio.h +++ b/include/asm-ia64/sn/pci/pciio.h @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -632,7 +633,7 @@ pciio_device_win_populate(pciio_win_map_t win_map, /* win map */ /* allocate window from mapping resource */ extern iopaddr_t -pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ +pciio_device_win_alloc(struct resource * res, pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ size_t start, /* start unit, or 0 */ size_t size, /* size of allocation */ diff --git a/include/asm-ia64/sn/pci/pciio_private.h b/include/asm-ia64/sn/pci/pciio_private.h index 4ae63322d60..84e3174fc54 100644 --- a/include/asm-ia64/sn/pci/pciio_private.h +++ b/include/asm-ia64/sn/pci/pciio_private.h @@ -89,7 +89,7 @@ struct pciio_win_map_s { * Opaque structure used to keep track of window allocation information. */ struct pciio_win_alloc_s { - pciio_win_map_t wa_map; /* window map allocation is from */ + struct resource *wa_resource; /* window map allocation resource */ unsigned long wa_base; /* allocation starting page number */ size_t wa_pages; /* number of pages in allocation */ }; diff --git a/include/asm-ia64/sn/sn2/io.h b/include/asm-ia64/sn/sn2/io.h index eff4f8641b1..fc30f1f4c5c 100644 --- a/include/asm-ia64/sn/sn2/io.h +++ b/include/asm-ia64/sn/sn2/io.h @@ -28,64 +28,76 @@ extern void sn_dma_flush(unsigned long); static inline unsigned int __sn_inb (unsigned long port) { - volatile unsigned char *addr = sn_io_addr(port); - unsigned char ret; - - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); + volatile unsigned char *addr; + unsigned char ret = -1; + + if ((addr = sn_io_addr(port))) { + ret = *addr; + __sn_mf_a(); + sn_dma_flush((unsigned long)addr); + } return ret; } static inline unsigned int __sn_inw (unsigned long port) { - volatile unsigned short *addr = sn_io_addr(port); - unsigned short ret; + volatile unsigned short *addr; + unsigned short ret = -1; - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); + if ((addr = sn_io_addr(port))) { + ret = *addr; + __sn_mf_a(); + sn_dma_flush((unsigned long)addr); + } return ret; } static inline unsigned int __sn_inl (unsigned long port) { - volatile unsigned int *addr = sn_io_addr(port); - unsigned int ret; + volatile unsigned int *addr; + unsigned int ret = -1; - ret = *addr; - __sn_mf_a(); - sn_dma_flush((unsigned long)addr); + if ((addr = sn_io_addr(port))) { + ret = *addr; + __sn_mf_a(); + sn_dma_flush((unsigned long)addr); + } return ret; } static inline void __sn_outb (unsigned char val, unsigned long port) { - volatile unsigned char *addr = sn_io_addr(port); + volatile unsigned char *addr; - *addr = val; - sn_mmiob(); + if ((addr = sn_io_addr(port))) { + *addr = val; + sn_mmiob(); + } } static inline void __sn_outw (unsigned short val, unsigned long port) { - volatile unsigned short *addr = sn_io_addr(port); + volatile unsigned short *addr; - *addr = val; - sn_mmiob(); + if ((addr = sn_io_addr(port))) { + *addr = val; + sn_mmiob(); + } } static inline void __sn_outl (unsigned int val, unsigned long port) { - volatile unsigned int *addr = sn_io_addr(port); + volatile unsigned int *addr; - *addr = val; - sn_mmiob(); + if ((addr = sn_io_addr(port))) { + *addr = val; + sn_mmiob(); + } } /* diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 66fd8ef46c7..5b0ccbe3e0c 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -27,6 +27,9 @@ #define SN_SAL_LOG_CE 0x02000006 #define SN_SAL_REGISTER_CE 0x02000007 #define SN_SAL_GET_PARTITION_ADDR 0x02000009 +#define SN_SAL_XP_ADDR_REGION 0x0200000f +#define SN_SAL_NO_FAULT_ZONE_VIRTUAL 0x02000010 +#define SN_SAL_NO_FAULT_ZONE_PHYSICAL 0x02000011 #define SN_SAL_PRINT_ERROR 0x02000012 #define SN_SAL_CONSOLE_PUTC 0x02000021 #define SN_SAL_CONSOLE_GETC 0x02000022 @@ -50,6 +53,7 @@ #define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b #define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c #define SN_SAL_COHERENCE 0x0200003d +#define SN_SAL_MEMPROTECT 0x0200003e #define SN_SAL_SYSCTL_FRU_CAPTURE 0x0200003f @@ -514,15 +518,66 @@ sn_local_partid(void) { } /* + * Register or unregister a physical address range being referenced across + * a partition boundary for which certain SAL errors should be scanned for, + * cleaned up and ignored. This is of value for kernel partitioning code only. + * Values for the operation argument: + * 1 = register this address range with SAL + * 0 = unregister this address range with SAL + * + * SAL maintains a reference count on an address range in case it is registered + * multiple times. + * + * On success, returns the reference count of the address range after the SAL + * call has performed the current registration/unregistration. Returns a + * negative value if an error occurred. + */ +static inline int +sn_register_xp_addr_region(u64 paddr, u64 len, int operation) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_XP_ADDR_REGION, paddr, len, (u64)operation, + 0, 0, 0, 0); + return ret_stuff.status; +} + +/* + * Register or unregister an instruction range for which SAL errors should + * be ignored. If an error occurs while in the registered range, SAL jumps + * to return_addr after ignoring the error. Values for the operation argument: + * 1 = register this instruction range with SAL + * 0 = unregister this instruction range with SAL + * + * Returns 0 on success, or a negative value if an error occurred. + */ +static inline int +sn_register_nofault_code(u64 start_addr, u64 end_addr, u64 return_addr, + int virtual, int operation) +{ + struct ia64_sal_retval ret_stuff; + u64 call; + if (virtual) { + call = SN_SAL_NO_FAULT_ZONE_VIRTUAL; + } else { + call = SN_SAL_NO_FAULT_ZONE_PHYSICAL; + } + SAL_CALL(ret_stuff, call, start_addr, end_addr, return_addr, (u64)1, + 0, 0, 0); + return ret_stuff.status; +} + +/* * Change or query the coherence domain for this partition. Each cpu-based * nasid is represented by a bit in an array of 64-bit words: * 0 = not in this partition's coherency domain * 1 = in this partition's coherency domain - * It is not possible for the local system's nasids to be removed from - * the coherency domain. * + * It is not possible for the local system's nasids to be removed from + * the coherency domain. Purpose of the domain arguments: * new_domain = set the coherence domain to the given nasids * old_domain = return the current coherence domain + * + * Returns 0 on success, or a negative value if an error occurred. */ static inline int sn_change_coherence(u64 *new_domain, u64 *old_domain) @@ -534,6 +589,26 @@ sn_change_coherence(u64 *new_domain, u64 *old_domain) } /* + * Change memory access protections for a physical address range. + * nasid_array is not used on Altix, but may be in future architectures. + * Available memory protection access classes are defined after the function. + */ +static inline int +sn_change_memprotect(u64 paddr, u64 len, u64 perms, u64 *nasid_array) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_MEMPROTECT, paddr, len, nasid_array, + perms, 0, 0, 0); + return ret_stuff.status; +} +#define SN_MEMPROT_ACCESS_CLASS_0 0x14a080 +#define SN_MEMPROT_ACCESS_CLASS_1 0x2520c2 +#define SN_MEMPROT_ACCESS_CLASS_2 0x14a1ca +#define SN_MEMPROT_ACCESS_CLASS_3 0x14a290 +#define SN_MEMPROT_ACCESS_CLASS_6 0x084080 +#define SN_MEMPROT_ACCESS_CLASS_7 0x021080 + +/* * Turns off system power. */ static inline void diff --git a/include/asm-ia64/sn/systeminfo.h b/include/asm-ia64/sn/systeminfo.h deleted file mode 100644 index b8d85db1c54..00000000000 --- a/include/asm-ia64/sn/systeminfo.h +++ /dev/null @@ -1,73 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SYSTEMINFO_H -#define _ASM_IA64_SN_SYSTEMINFO_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_SERIAL_SIZE 16 - -typedef struct module_info_s { - uint64_t serial_num; - int mod_num; - char serial_str[MAX_SERIAL_SIZE]; -} module_info_t; - - - -/* - * Commands to sysinfo() - */ - -#define SI_SYSNAME 1 /* return name of operating system */ -#define SI_HOSTNAME 2 /* return name of node */ -#define SI_RELEASE 3 /* return release of operating system */ -#define SI_VERSION 4 /* return version field of utsname */ -#define SI_MACHINE 5 /* return kind of machine */ -#define SI_ARCHITECTURE 6 /* return instruction set arch */ -#define SI_HW_SERIAL 7 /* return hardware serial number */ -#define SI_HW_PROVIDER 8 /* return hardware manufacturer */ -#define SI_SRPC_DOMAIN 9 /* return secure RPC domain */ -#define SI_INITTAB_NAME 10 /* return name of inittab file used */ - -#define _MIPS_SI_VENDOR 100 /* return system provider */ -#define _MIPS_SI_OS_PROVIDER 101 /* return OS manufacturer */ -#define _MIPS_SI_OS_NAME 102 /* return OS name */ -#define _MIPS_SI_HW_NAME 103 /* return system name */ -#define _MIPS_SI_NUM_PROCESSORS 104 /* return number of processors */ -#define _MIPS_SI_HOSTID 105 /* return hostid */ -#define _MIPS_SI_OSREL_MAJ 106 /* return OS major release number */ -#define _MIPS_SI_OSREL_MIN 107 /* return OS minor release number */ -#define _MIPS_SI_OSREL_PATCH 108 /* return OS release number */ -#define _MIPS_SI_PROCESSORS 109 /* return CPU revison id */ -#define _MIPS_SI_AVAIL_PROCESSORS 110 /* return number of available processors */ -#define _MIPS_SI_SERIAL 111 -/* - * These commands are unpublished interfaces to sysinfo(). - */ -#define SI_SET_HOSTNAME 258 /* set name of node */ - /* -unpublished option */ -#define SI_SET_SRPC_DOMAIN 265 /* set secure RPC domain */ - /* -unpublished option */ - -#if !defined(__KERNEL__) -int sysinfo(int, char *, long); -int get_num_modules(void); -int get_module_info(int, module_info_t *, size_t); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _ASM_IA64_SN_SYSTEMINFO_H */ diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 8a254dbd5e1..db02239d44b 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -224,7 +224,7 @@ #define __NR_sched_getaffinity 1232 #define __NR_set_tid_address 1233 #define __NR_fadvise64 1234 -/* 1235 available for reuse */ +#define __NR_tgkill 1235 #define __NR_exit_group 1236 #define __NR_lookup_dcookie 1237 #define __NR_io_setup 1238 diff --git a/include/asm-m68k/div64.h b/include/asm-m68k/div64.h index 16bf1f88d40..9f65de1a248 100644 --- a/include/asm-m68k/div64.h +++ b/include/asm-m68k/div64.h @@ -3,7 +3,6 @@ /* n = n / base; return rem; */ -#if 1 #define do_div(n, base) ({ \ union { \ unsigned long n32[2]; \ @@ -23,13 +22,5 @@ (n) = __n.n64; \ __rem; \ }) -#else -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; \ -}) -#endif #endif /* _M68K_DIV64_H */ diff --git a/include/asm-m68k/mmu_context.h b/include/asm-m68k/mmu_context.h index 04cfa101eb7..4983fb7b6a0 100644 --- a/include/asm-m68k/mmu_context.h +++ b/include/asm-m68k/mmu_context.h @@ -3,7 +3,7 @@ #include -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -79,7 +79,7 @@ extern inline void switch_mm_0460(struct mm_struct *mm) asm volatile (".chip 68k"); } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { if (prev != next) { if (CPU_IS_020_OR_030) @@ -137,7 +137,7 @@ static inline void activate_context(struct mm_struct *mm) sun3_put_context(mm->context); } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { activate_context(tsk->mm); } diff --git a/include/asm-m68knommu/div64.h b/include/asm-m68knommu/div64.h index b41200162d8..6cd978cefb2 100644 --- a/include/asm-m68knommu/div64.h +++ b/include/asm-m68knommu/div64.h @@ -1,13 +1 @@ -#ifndef _M68KNOMMU_DIV64_H -#define _M68KNOMMU_DIV64_H - -/* n = n / base; return rem; */ - -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; \ -}) - -#endif /* _M68K_DIV64_H */ +#include diff --git a/include/asm-m68knommu/flat.h b/include/asm-m68knommu/flat.h index fe805aaa33d..73712f276cc 100644 --- a/include/asm-m68knommu/flat.h +++ b/include/asm-m68knommu/flat.h @@ -5,6 +5,12 @@ #ifndef __M68KNOMMU_FLAT_H__ #define __M68KNOMMU_FLAT_H__ -#define flat_argvp_envp_on_stack() 1 +#define flat_stack_align(sp) /* nothing needed */ +#define flat_argvp_envp_on_stack() 1 +#define flat_old_ram_flag(flags) (flags) +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_get_addr_from_rp(rp, relval) get_unaligned(rp) +#define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp) +#define flat_get_relocate_addr(rel) (rel) #endif /* __M68KNOMMU_FLAT_H__ */ diff --git a/include/asm-m68knommu/io.h b/include/asm-m68knommu/io.h index d0dbd4c796c..f42645e4a2d 100644 --- a/include/asm-m68knommu/io.h +++ b/include/asm-m68knommu/io.h @@ -43,6 +43,13 @@ static inline unsigned int _swapl(volatile unsigned long v) #define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b)) #define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + static inline void io_outsb(unsigned int addr, void *buf, int len) { volatile unsigned char *ap = (volatile unsigned char *) addr; @@ -100,7 +107,7 @@ static inline void io_insl(unsigned int addr, void *buf, int len) #define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) #define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) -#define inb(addr) readb(addr) +#define inb(addr) readb(addr) #define inw(addr) readw(addr) #define inl(addr) readl(addr) #define outb(x,addr) ((void) writeb(x,addr)) diff --git a/include/asm-m68knommu/mmu_context.h b/include/asm-m68knommu/mmu_context.h index a4286176513..9bc0fd49b8a 100644 --- a/include/asm-m68knommu/mmu_context.h +++ b/include/asm-m68knommu/mmu_context.h @@ -6,7 +6,7 @@ #include #include -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -19,7 +19,7 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) #define destroy_context(mm) do { } while(0) -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { } diff --git a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h index 7defa6391f0..0d063a97f1c 100644 --- a/include/asm-m68knommu/page.h +++ b/include/asm-m68knommu/page.h @@ -6,7 +6,7 @@ /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT (12) -#define PAGE_SIZE (4096) +#define PAGE_SIZE (1UL << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #ifdef __KERNEL__ diff --git a/include/asm-m68knommu/semaphore.h b/include/asm-m68knommu/semaphore.h index f6cfb9f4900..4720a09e619 100644 --- a/include/asm-m68knommu/semaphore.h +++ b/include/asm-m68knommu/semaphore.h @@ -145,7 +145,7 @@ extern inline int down_trylock(struct semaphore * sem) ".previous" : "=d" (result) : "a" (sem1) - : "%d0", "memory"); + : "memory"); return result; } diff --git a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h index 6ff1747b02e..9f890ed45b4 100644 --- a/include/asm-m68knommu/uaccess.h +++ b/include/asm-m68knommu/uaccess.h @@ -13,21 +13,14 @@ #define VERIFY_READ 0 #define VERIFY_WRITE 1 -/* We let the MMU do all checking */ -extern inline int access_ok(int type, const void * addr, unsigned long size) +#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size)) + +static inline int _access_ok(unsigned long addr, unsigned long size) { -#define RANGE_CHECK_OK(addr, size, lower, upper) \ - (((addr) >= (lower)) && (((addr) + (size)) < (upper))) - -#ifdef CONFIG_COLDFIRE - extern unsigned long _ramend; - return(RANGE_CHECK_OK((unsigned long) addr, size, 0L, _ramend) || - (is_in_rom((unsigned long) addr) && - is_in_rom((unsigned long) addr + size))); -#else - /* DAVIDM - this could be restricted a lot more */ - return(RANGE_CHECK_OK((unsigned long)addr, size, 0, 0x10f00000)); -#endif + extern unsigned long memory_start, memory_end; + + return (((addr >= memory_start) && (addr+size < memory_end)) || + (is_in_rom(addr) && is_in_rom(addr+size))); } extern inline int verify_area(int type, const void * addr, unsigned long size) diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index 6e586c25ff1..6090877e6f6 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h @@ -6,8 +6,8 @@ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 by Ralf Baechle * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ -#ifndef __ASM_CACHEFLUSH_H -#define __ASM_CACHEFLUSH_H +#ifndef _ASM_CACHEFLUSH_H +#define _ASM_CACHEFLUSH_H #include @@ -62,4 +62,4 @@ extern void (*flush_data_cache_page)(unsigned long addr); #define ClearPageDcacheDirty(page) \ clear_bit(PG_dcache_dirty, &(page)->flags) -#endif /* __ASM_CACHEFLUSH_H */ +#endif /* _ASM_CACHEFLUSH_H */ diff --git a/include/asm-mips/hardirq.h b/include/asm-mips/hardirq.h index 530c7fc80eb..b6fa5ddc8ff 100644 --- a/include/asm-mips/hardirq.h +++ b/include/asm-mips/hardirq.h @@ -16,8 +16,6 @@ typedef struct { unsigned int __softirq_pending; - unsigned int __syscall_count; - struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h index cf19cd768f9..97deb9b0d67 100644 --- a/include/asm-mips/mmu_context.h +++ b/include/asm-mips/mmu_context.h @@ -49,7 +49,7 @@ extern unsigned long pgd_current[]; #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) #define asid_cache(cpu) (cpu_data[cpu].asid_cache) -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -92,8 +92,9 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { + unsigned cpu = smp_processor_id(); unsigned long flags; local_irq_save(flags); diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index 893fb058432..ba91dbc3ce0 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -275,11 +275,12 @@ #define __NR_clock_gettime (__NR_Linux + 263) #define __NR_clock_getres (__NR_Linux + 264) #define __NR_clock_nanosleep (__NR_Linux + 265) +#define __NR_tgkill (__NR_Linux + 266) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 265 +#define __NR_Linux_syscalls 266 #ifndef __ASSEMBLY__ diff --git a/include/asm-mips64/cacheflush.h b/include/asm-mips64/cacheflush.h index 6e586c25ff1..6090877e6f6 100644 --- a/include/asm-mips64/cacheflush.h +++ b/include/asm-mips64/cacheflush.h @@ -6,8 +6,8 @@ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 01, 02, 03 by Ralf Baechle * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. */ -#ifndef __ASM_CACHEFLUSH_H -#define __ASM_CACHEFLUSH_H +#ifndef _ASM_CACHEFLUSH_H +#define _ASM_CACHEFLUSH_H #include @@ -62,4 +62,4 @@ extern void (*flush_data_cache_page)(unsigned long addr); #define ClearPageDcacheDirty(page) \ clear_bit(PG_dcache_dirty, &(page)->flags) -#endif /* __ASM_CACHEFLUSH_H */ +#endif /* _ASM_CACHEFLUSH_H */ diff --git a/include/asm-mips64/hardirq.h b/include/asm-mips64/hardirq.h index 530c7fc80eb..b6fa5ddc8ff 100644 --- a/include/asm-mips64/hardirq.h +++ b/include/asm-mips64/hardirq.h @@ -16,8 +16,6 @@ typedef struct { unsigned int __softirq_pending; - unsigned int __syscall_count; - struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/include/asm-mips64/mmu_context.h b/include/asm-mips64/mmu_context.h index 107e2459ccd..05cd8dba96a 100644 --- a/include/asm-mips64/mmu_context.h +++ b/include/asm-mips64/mmu_context.h @@ -40,7 +40,7 @@ extern unsigned long pgd_current[]; #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) #define asid_cache(cpu) (cpu_data[cpu].asid_cache) -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -83,8 +83,9 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { + int cpu = smp_processor_id(); unsigned long flags; local_irq_save(flags); diff --git a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h index 25a42752b18..cba337b07be 100644 --- a/include/asm-mips64/mmzone.h +++ b/include/asm-mips64/mmzone.h @@ -24,7 +24,7 @@ extern plat_pg_data_t *plat_node_data[]; #define PHYSADDR_TO_NID(pa) NASID_TO_COMPACT_NODEID(NASID_GET(pa)) #define PLAT_NODE_DATA(n) (plat_node_data[n]) -#define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_size) +#define PLAT_NODE_DATA_SIZE(n) (PLAT_NODE_DATA(n)->gendata.node_spanned_pages) #define PLAT_NODE_DATA_LOCALNR(p, n) \ (((p) >> PAGE_SHIFT) - PLAT_NODE_DATA(n)->gendata.node_start_pfn) diff --git a/include/asm-mips64/r4kcache.h b/include/asm-mips64/r4kcache.h index b3814e2c262..84aa8535bc2 100644 --- a/include/asm-mips64/r4kcache.h +++ b/include/asm-mips64/r4kcache.h @@ -140,7 +140,7 @@ static inline void invalidate_tcache_page(unsigned long addr) static inline void blast_dcache16(void) { unsigned long start = KSEG0; - unsigned long end = start + dcache_way_size; + unsigned long end = start + current_cpu_data.dcache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; unsigned long ws_end = current_cpu_data.dcache.ways << current_cpu_data.dcache.waybit; @@ -179,7 +179,7 @@ static inline void blast_dcache16_page_indexed(unsigned long page) static inline void blast_icache16(void) { unsigned long start = KSEG0; - unsigned long end = start + icache_way_size; + unsigned long end = start + current_cpu_data.icache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; unsigned long ws_end = current_cpu_data.icache.ways << current_cpu_data.icache.waybit; @@ -218,7 +218,7 @@ static inline void blast_icache16_page_indexed(unsigned long page) static inline void blast_scache16(void) { unsigned long start = KSEG0; - unsigned long end = start + scache_way_size; + unsigned long end = start + current_cpu_data.scache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit; unsigned long ws_end = current_cpu_data.scache.ways << current_cpu_data.scache.waybit; @@ -283,7 +283,7 @@ static inline void blast_scache16_page_indexed(unsigned long page) static inline void blast_dcache32(void) { unsigned long start = KSEG0; - unsigned long end = start + dcache_way_size; + unsigned long end = start + current_cpu_data.dcache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit; unsigned long ws_end = current_cpu_data.dcache.ways << current_cpu_data.dcache.waybit; @@ -322,7 +322,7 @@ static inline void blast_dcache32_page_indexed(unsigned long page) static inline void blast_icache32(void) { unsigned long start = KSEG0; - unsigned long end = start + icache_way_size; + unsigned long end = start + current_cpu_data.icache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; unsigned long ws_end = current_cpu_data.icache.ways << current_cpu_data.icache.waybit; @@ -361,7 +361,7 @@ static inline void blast_icache32_page_indexed(unsigned long page) static inline void blast_scache32(void) { unsigned long start = KSEG0; - unsigned long end = start + scache_way_size; + unsigned long end = start + current_cpu_data.scache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit; unsigned long ws_end = current_cpu_data.scache.ways << current_cpu_data.scache.waybit; @@ -426,7 +426,7 @@ static inline void blast_scache32_page_indexed(unsigned long page) static inline void blast_icache64(void) { unsigned long start = KSEG0; - unsigned long end = start + icache_way_size; + unsigned long end = start + current_cpu_data.icache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.icache.waybit; unsigned long ws_end = current_cpu_data.icache.ways << current_cpu_data.icache.waybit; @@ -465,7 +465,7 @@ static inline void blast_icache64_page_indexed(unsigned long page) static inline void blast_scache64(void) { unsigned long start = KSEG0; - unsigned long end = start + scache_way_size; + unsigned long end = start + current_cpu_data.scache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit; unsigned long ws_end = current_cpu_data.scache.ways << current_cpu_data.scache.waybit; @@ -530,7 +530,7 @@ static inline void blast_scache64_page_indexed(unsigned long page) static inline void blast_scache128(void) { unsigned long start = KSEG0; - unsigned long end = start + scache_way_size; + unsigned long end = start + current_cpu_data.scache.waysize; unsigned long ws_inc = 1UL << current_cpu_data.scache.waybit; unsigned long ws_end = current_cpu_data.scache.ways << current_cpu_data.scache.waybit; diff --git a/include/asm-mips64/unistd.h b/include/asm-mips64/unistd.h index 6ab8e7c811d..6cb5d460ba2 100644 --- a/include/asm-mips64/unistd.h +++ b/include/asm-mips64/unistd.h @@ -282,11 +282,12 @@ #define __NR_O32_clock_gettime (__NR_O32_Linux + 263) #define __NR_O32_clock_getres (__NR_O32_Linux + 264) #define __NR_O32_clock_nanosleep (__NR_O32_Linux + 265) +#define __NR_O32_tgkill (__NR_O32_Linux + 266) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_O32_Linux_syscalls 265 +#define __NR_O32_Linux_syscalls 266 /* @@ -518,11 +519,12 @@ #define __NR_clock_gettime (__NR_Linux + 222) #define __NR_clock_getres (__NR_Linux + 223) #define __NR_clock_nanosleep (__NR_Linux + 224) +#define __NR_tgkill (__NR_Linux + 225) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 224 +#define __NR_Linux_syscalls 225 /* * Linux N32 syscalls are in the range from 6000 to 6999. @@ -757,11 +759,12 @@ #define __NR_N32_clock_gettime (__NR_N32_Linux + 227) #define __NR_N32_clock_getres (__NR_N32_Linux + 228) #define __NR_N32_clock_nanosleep (__NR_N32_Linux + 229) +#define __NR_N32_tgkill (__NR_N32_Linux + 230) /* * Offset of the last N32 flavoured syscall */ -#define __NR_N32_Linux_syscalls 229 +#define __NR_N32_Linux_syscalls 230 #ifndef __ASSEMBLY__ diff --git a/include/asm-parisc/div64.h b/include/asm-parisc/div64.h dissimilarity index 100% index e86e35e8a27..6cd978cefb2 100644 --- a/include/asm-parisc/div64.h +++ b/include/asm-parisc/div64.h @@ -1,54 +1 @@ -#ifndef __ASM_PARISC_DIV64 -#define __ASM_PARISC_DIV64 - -#ifdef __LP64__ - -/* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang - * - * vsprintf uses this to divide a 64-bit integer N by a small integer BASE. - * This is incredibly hard on IA-64 and HPPA - */ - -#define do_div(n,base) \ -({ \ - int _res; \ - _res = ((unsigned long) (n)) % (unsigned) (base); \ - (n) = ((unsigned long) (n)) / (unsigned) (base); \ - _res; \ -}) - -#else -/* - * unsigned long long division. Yuck Yuck! What is Linux coming to? - * This is 100% disgusting - */ -#define do_div(n,base) \ -({ \ - unsigned long __low, __low2, __high, __rem; \ - __low = (n) & 0xffffffff; \ - __high = (n) >> 32; \ - if (__high) { \ - __rem = __high % (unsigned long)base; \ - __high = __high / (unsigned long)base; \ - __low2 = __low >> 16; \ - __low2 += __rem << 16; \ - __rem = __low2 % (unsigned long)base; \ - __low2 = __low2 / (unsigned long)base; \ - __low = __low & 0xffff; \ - __low += __rem << 16; \ - __rem = __low % (unsigned long)base; \ - __low = __low / (unsigned long)base; \ - n = __low + ((long long)__low2 << 16) + \ - ((long long) __high << 32); \ - } else { \ - __rem = __low % (unsigned long)base; \ - n = (__low / (unsigned long)base); \ - } \ - __rem; \ -}) -#endif - -#endif - +#include diff --git a/include/asm-parisc/mmu_context.h b/include/asm-parisc/mmu_context.h index 1ff9e5f0582..6327156282f 100644 --- a/include/asm-parisc/mmu_context.h +++ b/include/asm-parisc/mmu_context.h @@ -6,7 +6,7 @@ #include #include -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -43,7 +43,7 @@ static inline void load_context(mm_context_t context) #endif } -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { if (prev != next) { @@ -69,6 +69,6 @@ static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) if (next->context == 0) next->context = alloc_sid(); - switch_mm(prev,next,current,0); + switch_mm(prev,next,current); } #endif diff --git a/include/asm-ppc/div64.h b/include/asm-ppc/div64.h dissimilarity index 100% index ec3ae5bcb3d..6cd978cefb2 100644 --- a/include/asm-ppc/div64.h +++ b/include/asm-ppc/div64.h @@ -1,23 +1 @@ -#ifndef __PPC_DIV64 -#define __PPC_DIV64 - -#include - -extern u32 __div64_32(u64 *dividend, u32 div); - -#define do_div(n, div) ({ \ - u64 __n = (n); \ - u32 __d = (div); \ - u32 __q, __r; \ - if ((__n >> 32) == 0) { \ - __q = (u32)__n / __d; \ - __r = (u32)__n - __q * __d; \ - (n) = __q; \ - } else { \ - __r = __div64_32(&__n, __d); \ - (n) = __n; \ - } \ - __r; \ -}) - -#endif +#include diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h index 13126986330..1e8176b2d12 100644 --- a/include/asm-ppc/mmu_context.h +++ b/include/asm-ppc/mmu_context.h @@ -48,7 +48,7 @@ -- Dan */ -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -153,7 +153,7 @@ static inline void destroy_context(struct mm_struct *mm) } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, int cpu) + struct task_struct *tsk) { tsk->thread.pgdir = next->pgd; get_mmu_context(next); diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h index 887fa5302a9..5d121448d3c 100644 --- a/include/asm-ppc/serial.h +++ b/include/asm-ppc/serial.h @@ -25,11 +25,9 @@ #elif defined(CONFIG_PRPMC800) #include #elif defined(CONFIG_SANDPOINT) -#include +#include #elif defined(CONFIG_SPRUCE) #include -#elif defined(CONFIG_ZX4500) -#include #elif defined(CONFIG_40x) #include #else diff --git a/include/asm-ppc64/div64.h b/include/asm-ppc64/div64.h dissimilarity index 100% index 22ba8703345..6cd978cefb2 100644 --- a/include/asm-ppc64/div64.h +++ b/include/asm-ppc64/div64.h @@ -1,18 +1 @@ -#ifndef __PPC_DIV64 -#define __PPC_DIV64 - -/* Copyright 2001 PPC64 Team, IBM Corp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) (n)) % (unsigned) (base); \ - (n) = ((unsigned long) (n)) / (unsigned) (base); \ - __res; }) - -#endif +#include diff --git a/include/asm-ppc64/mmu_context.h b/include/asm-ppc64/mmu_context.h index 1014f086e5e..a84ee5812e9 100644 --- a/include/asm-ppc64/mmu_context.h +++ b/include/asm-ppc64/mmu_context.h @@ -56,7 +56,7 @@ struct mmu_context_queue_t { extern struct mmu_context_queue_t mmu_context_queue; static inline void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -140,10 +140,10 @@ extern void flush_stab(struct task_struct *tsk, struct mm_struct *mm); */ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, int cpu) + struct task_struct *tsk) { flush_stab(tsk, next); - set_bit(cpu, &next->cpu_vm_mask); + set_bit(smp_processor_id(), &next->cpu_vm_mask); } #define deactivate_mm(tsk,mm) do { } while (0) @@ -153,7 +153,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, * the context for the new mm so we see the new mappings. */ #define activate_mm(active_mm, mm) \ - switch_mm(active_mm, mm, current, smp_processor_id()); + switch_mm(active_mm, mm, current); #define VSID_RANDOMIZER 42470972311 #define VSID_MASK 0xfffffffff diff --git a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h index 8503e25b17b..2e513601284 100644 --- a/include/asm-ppc64/mmzone.h +++ b/include/asm-ppc64/mmzone.h @@ -54,7 +54,6 @@ static inline int pa_to_nid(unsigned long pa) */ #define NODE_DATA(nid) (&node_data[nid]) -#define node_size(nid) (NODE_DATA(nid)->node_size) #define node_localnr(pfn, nid) ((pfn) - NODE_DATA(nid)->node_start_pfn) /* diff --git a/include/asm-s390/div64.h b/include/asm-s390/div64.h index 79b5f06fa17..0c5f739832f 100644 --- a/include/asm-s390/div64.h +++ b/include/asm-s390/div64.h @@ -43,13 +43,7 @@ }) #else /* __s390x__ */ - -#define do_div(n,base) ({ \ -int __res; \ -__res = ((unsigned long) n) % (unsigned) base; \ -n = ((unsigned long) n) / (unsigned) base; \ -__res; }) - +#include #endif /* __s390x__ */ #endif diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index 87be0aab702..0e63fd52189 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -17,12 +17,12 @@ #define destroy_context(mm) flush_tlb_mm(mm) static inline void enter_lazy_tlb(struct mm_struct *mm, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { unsigned long pgd; @@ -42,7 +42,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, : : "m" (pgd) ); #endif /* __s390x__ */ } - set_bit(cpu, &next->cpu_vm_mask); + set_bit(smp_processor_id(), &next->cpu_vm_mask); } #define deactivate_mm(tsk,mm) do { } while (0) @@ -50,7 +50,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, extern inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { - switch_mm(prev, next, current, smp_processor_id()); + switch_mm(prev, next, current); } #endif diff --git a/include/asm-sh/div64.h b/include/asm-sh/div64.h dissimilarity index 100% index dd4665af4fb..6cd978cefb2 100644 --- a/include/asm-sh/div64.h +++ b/include/asm-sh/div64.h @@ -1,20 +1 @@ -#ifndef __ASM_SH_DIV64 -#define __ASM_SH_DIV64 - -extern u64 __div64_32(u64 n, u32 d); - -#define do_div(n,base) ({ \ -u64 __n = (n), __q; \ -u32 __base = (base); \ -u32 __res; \ -if ((__n >> 32) == 0) { \ - __res = ((unsigned long) __n) % (unsigned) __base; \ - (n) = ((unsigned long) __n) / (unsigned) __base; \ -} else { \ - __q = __div64_32(__n, __base); \ - __res = __n - __q * __base; \ - (n) = __q; \ -} \ -__res; }) - -#endif /* __ASM_SH_DIV64 */ +#include diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h index 17775400498..c956ddea556 100644 --- a/include/asm-sh/mmu_context.h +++ b/include/asm-sh/mmu_context.h @@ -129,7 +129,7 @@ static __inline__ void activate_context(struct mm_struct *mm) (Currently not used) */ static __inline__ void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned int cpu) + struct task_struct *tsk) { if (likely(prev != next)) { unsigned long __pgdir = (unsigned long)next->pgd; @@ -144,10 +144,10 @@ static __inline__ void switch_mm(struct mm_struct *prev, #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL,smp_processor_id()) + switch_mm((prev),(next),NULL) static __inline__ void -enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } #else /* !CONFIG_MMU */ @@ -157,10 +157,10 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) #define set_asid(asid) do { } while (0) #define get_asid() (0) #define activate_context(mm) do { } while (0) -#define switch_mm(prev,next,tsk,cpu) do { } while (0) +#define switch_mm(prev,next,tsk) do { } while (0) #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev,next) do { } while (0) -#define enter_lazy_tlb(mm,tsk,cpu) do { } while (0) +#define enter_lazy_tlb(mm,tsk) do { } while (0) #endif /* CONFIG_MMU */ #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4) diff --git a/include/asm-sparc/div64.h b/include/asm-sparc/div64.h index 167260a9c95..6cd978cefb2 100644 --- a/include/asm-sparc/div64.h +++ b/include/asm-sparc/div64.h @@ -1,11 +1 @@ -#ifndef __SPARC_DIV64 -#define __SPARC_DIV64 - -/* We're not 64-bit, but... */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; }) - -#endif /* __SPARC_DIV64 */ +#include diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h index f386a8f4bbe..ed1e01d04d2 100644 --- a/include/asm-sparc/mmu_context.h +++ b/include/asm-sparc/mmu_context.h @@ -5,7 +5,7 @@ #ifndef __ASSEMBLY__ -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -26,14 +26,14 @@ BTFIXUPDEF_CALL(void, destroy_context, struct mm_struct *) #define destroy_context(mm) BTFIXUP_CALL(destroy_context)(mm) /* Switch the current MM context. */ -BTFIXUPDEF_CALL(void, switch_mm, struct mm_struct *, struct mm_struct *, struct task_struct *, int) +BTFIXUPDEF_CALL(void, switch_mm, struct mm_struct *, struct mm_struct *, struct task_struct *) -#define switch_mm(old_mm, mm, tsk, cpu) BTFIXUP_CALL(switch_mm)(old_mm, mm, tsk, cpu) +#define switch_mm(old_mm, mm, tsk) BTFIXUP_CALL(switch_mm)(old_mm, mm, tsk) #define deactivate_mm(tsk,mm) do { } while (0) /* Activate a new MM instance for the current task. */ -#define activate_mm(active_mm, mm) switch_mm((active_mm), (mm), NULL, smp_processor_id()) +#define activate_mm(active_mm, mm) switch_mm((active_mm), (mm), NULL) #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc64/div64.h b/include/asm-sparc64/div64.h index a36d2443d20..6cd978cefb2 100644 --- a/include/asm-sparc64/div64.h +++ b/include/asm-sparc64/div64.h @@ -1,14 +1 @@ -#ifndef __SPARC64_DIV64 -#define __SPARC64_DIV64 - -/* - * Hey, we're already 64-bit, no - * need to play games.. - */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; }) - -#endif /* __SPARC64_DIV64 */ +#include diff --git a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h index 44a4e97f479..97e43a160b3 100644 --- a/include/asm-sparc64/hardirq.h +++ b/include/asm-sparc64/hardirq.h @@ -11,15 +11,9 @@ #include #include -/* entry.S is sensitive to the offsets of these fields */ -/* rtrap.S is sensitive to the size of this structure */ +/* rtrap.S is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; - unsigned int __unused_1; - unsigned int __unused_2; - unsigned int __unused_3; - unsigned int __syscall_count; - struct task_struct * __ksoftirqd_task; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index ab9eedf2286..292757aa317 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -27,7 +27,7 @@ #include #include -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } @@ -106,7 +106,7 @@ do { \ extern void __flush_tlb_mm(unsigned long, unsigned long); /* Switch the current MM context. */ -static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) +static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { unsigned long ctx_valid; @@ -125,7 +125,7 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str } { - unsigned long vm_mask = (1UL << cpu); + unsigned long vm_mask = (1UL << smp_processor_id()); /* Even if (mm == old_mm) we _must_ check * the cpu_vm_mask. If we do not we could diff --git a/include/asm-sparc64/xor.h b/include/asm-sparc64/xor.h dissimilarity index 85% index 9ecc98f667d..8b3a7e4b606 100644 --- a/include/asm-sparc64/xor.h +++ b/include/asm-sparc64/xor.h @@ -1,398 +1,40 @@ -/* - * include/asm-sparc64/xor.h - * - * High speed xor_block operation for RAID4/5 utilizing the - * UltraSparc Visual Instruction Set. - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Requirements: - * !(((long)dest | (long)sourceN) & (64 - 1)) && - * !(len & 127) && len >= 256 - * - * It is done in pure assembly, as otherwise gcc makes it a non-leaf - * function, which is not what we want. - */ - -#include -#include - -extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); - -#define _S(x) __S(x) -#define __S(x) #x -#define DEF(x) __asm__(#x " = " _S(x)) - -DEF(FPRS_FEF); -DEF(FPRS_DU); -DEF(ASI_BLK_P); - -/* ??? We set and use %asi instead of using ASI_BLK_P directly because gas - currently does not accept symbolic constants for the ASI specifier. */ - -__asm__ (" - .text - .globl xor_vis_2 - .type xor_vis_2,@function -xor_vis_2: - rd %fprs, %o5 - andcc %o5, FPRS_FEF|FPRS_DU, %g0 - be,pt %icc, 0f - sethi %hi(VISenter), %g1 - jmpl %g1 + %lo(VISenter), %g7 - add %g7, 8, %g7 -0: wr %g0, FPRS_FEF, %fprs - rd %asi, %g1 - wr %g0, ASI_BLK_P, %asi - membar #LoadStore|#StoreLoad|#StoreStore - sub %o0, 128, %o0 - ldda [%o1] %asi, %f0 - ldda [%o2] %asi, %f16 - -2: ldda [%o1 + 64] %asi, %f32 - fxor %f0, %f16, %f16 - fxor %f2, %f18, %f18 - fxor %f4, %f20, %f20 - fxor %f6, %f22, %f22 - fxor %f8, %f24, %f24 - fxor %f10, %f26, %f26 - fxor %f12, %f28, %f28 - fxor %f14, %f30, %f30 - stda %f16, [%o1] %asi - ldda [%o2 + 64] %asi, %f48 - ldda [%o1 + 128] %asi, %f0 - fxor %f32, %f48, %f48 - fxor %f34, %f50, %f50 - add %o1, 128, %o1 - fxor %f36, %f52, %f52 - add %o2, 128, %o2 - fxor %f38, %f54, %f54 - subcc %o0, 128, %o0 - fxor %f40, %f56, %f56 - fxor %f42, %f58, %f58 - fxor %f44, %f60, %f60 - fxor %f46, %f62, %f62 - stda %f48, [%o1 - 64] %asi - bne,pt %xcc, 2b - ldda [%o2] %asi, %f16 - - ldda [%o1 + 64] %asi, %f32 - fxor %f0, %f16, %f16 - fxor %f2, %f18, %f18 - fxor %f4, %f20, %f20 - fxor %f6, %f22, %f22 - fxor %f8, %f24, %f24 - fxor %f10, %f26, %f26 - fxor %f12, %f28, %f28 - fxor %f14, %f30, %f30 - stda %f16, [%o1] %asi - ldda [%o2 + 64] %asi, %f48 - membar #Sync - fxor %f32, %f48, %f48 - fxor %f34, %f50, %f50 - fxor %f36, %f52, %f52 - fxor %f38, %f54, %f54 - fxor %f40, %f56, %f56 - fxor %f42, %f58, %f58 - fxor %f44, %f60, %f60 - fxor %f46, %f62, %f62 - stda %f48, [%o1 + 64] %asi - membar #Sync|#StoreStore|#StoreLoad - wr %g1, %g0, %asi - retl - wr %g0, 0, %fprs - .size xor_vis_2, .-xor_vis_2 - - - .globl xor_vis_3 - .type xor_vis_3,@function -xor_vis_3: - rd %fprs, %o5 - andcc %o5, FPRS_FEF|FPRS_DU, %g0 - be,pt %icc, 0f - sethi %hi(VISenter), %g1 - jmpl %g1 + %lo(VISenter), %g7 - add %g7, 8, %g7 -0: wr %g0, FPRS_FEF, %fprs - rd %asi, %g1 - wr %g0, ASI_BLK_P, %asi - membar #LoadStore|#StoreLoad|#StoreStore - sub %o0, 64, %o0 - ldda [%o1] %asi, %f0 - ldda [%o2] %asi, %f16 - -3: ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f48 - fxor %f2, %f18, %f50 - add %o1, 64, %o1 - fxor %f4, %f20, %f52 - fxor %f6, %f22, %f54 - add %o2, 64, %o2 - fxor %f8, %f24, %f56 - fxor %f10, %f26, %f58 - fxor %f12, %f28, %f60 - fxor %f14, %f30, %f62 - ldda [%o1] %asi, %f0 - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - add %o3, 64, %o3 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - subcc %o0, 64, %o0 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - stda %f48, [%o1 - 64] %asi - bne,pt %xcc, 3b - ldda [%o2] %asi, %f16 - - ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f48 - fxor %f2, %f18, %f50 - fxor %f4, %f20, %f52 - fxor %f6, %f22, %f54 - fxor %f8, %f24, %f56 - fxor %f10, %f26, %f58 - fxor %f12, %f28, %f60 - fxor %f14, %f30, %f62 - membar #Sync - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - stda %f48, [%o1] %asi - membar #Sync|#StoreStore|#StoreLoad - wr %g1, %g0, %asi - retl - wr %g0, 0, %fprs - .size xor_vis_3, .-xor_vis_3 - - - .globl xor_vis_4 - .type xor_vis_4,@function -xor_vis_4: - rd %fprs, %o5 - andcc %o5, FPRS_FEF|FPRS_DU, %g0 - be,pt %icc, 0f - sethi %hi(VISenter), %g1 - jmpl %g1 + %lo(VISenter), %g7 - add %g7, 8, %g7 -0: wr %g0, FPRS_FEF, %fprs - rd %asi, %g1 - wr %g0, ASI_BLK_P, %asi - membar #LoadStore|#StoreLoad|#StoreStore - sub %o0, 64, %o0 - ldda [%o1] %asi, %f0 - ldda [%o2] %asi, %f16 - -4: ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f16 - fxor %f2, %f18, %f18 - add %o1, 64, %o1 - fxor %f4, %f20, %f20 - fxor %f6, %f22, %f22 - add %o2, 64, %o2 - fxor %f8, %f24, %f24 - fxor %f10, %f26, %f26 - fxor %f12, %f28, %f28 - fxor %f14, %f30, %f30 - ldda [%o4] %asi, %f48 - fxor %f16, %f32, %f32 - fxor %f18, %f34, %f34 - fxor %f20, %f36, %f36 - fxor %f22, %f38, %f38 - add %o3, 64, %o3 - fxor %f24, %f40, %f40 - fxor %f26, %f42, %f42 - fxor %f28, %f44, %f44 - fxor %f30, %f46, %f46 - ldda [%o1] %asi, %f0 - fxor %f32, %f48, %f48 - fxor %f34, %f50, %f50 - fxor %f36, %f52, %f52 - add %o4, 64, %o4 - fxor %f38, %f54, %f54 - fxor %f40, %f56, %f56 - fxor %f42, %f58, %f58 - subcc %o0, 64, %o0 - fxor %f44, %f60, %f60 - fxor %f46, %f62, %f62 - stda %f48, [%o1 - 64] %asi - bne,pt %xcc, 4b - ldda [%o2] %asi, %f16 - - ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f16 - fxor %f2, %f18, %f18 - fxor %f4, %f20, %f20 - fxor %f6, %f22, %f22 - fxor %f8, %f24, %f24 - fxor %f10, %f26, %f26 - fxor %f12, %f28, %f28 - fxor %f14, %f30, %f30 - ldda [%o4] %asi, %f48 - fxor %f16, %f32, %f32 - fxor %f18, %f34, %f34 - fxor %f20, %f36, %f36 - fxor %f22, %f38, %f38 - fxor %f24, %f40, %f40 - fxor %f26, %f42, %f42 - fxor %f28, %f44, %f44 - fxor %f30, %f46, %f46 - membar #Sync - fxor %f32, %f48, %f48 - fxor %f34, %f50, %f50 - fxor %f36, %f52, %f52 - fxor %f38, %f54, %f54 - fxor %f40, %f56, %f56 - fxor %f42, %f58, %f58 - fxor %f44, %f60, %f60 - fxor %f46, %f62, %f62 - stda %f48, [%o1] %asi - membar #Sync|#StoreStore|#StoreLoad - wr %g1, %g0, %asi - retl - wr %g0, 0, %fprs - .size xor_vis_4, .-xor_vis_4 - - - .globl xor_vis_5 - .type xor_vis_5,@function -xor_vis_5: - mov %o5, %g5 - rd %fprs, %o5 - andcc %o5, FPRS_FEF|FPRS_DU, %g0 - be,pt %icc, 0f - sethi %hi(VISenter), %g1 - jmpl %g1 + %lo(VISenter), %g7 - add %g7, 8, %g7 -0: wr %g0, FPRS_FEF, %fprs - mov %g5, %o5 - rd %asi, %g1 - wr %g0, ASI_BLK_P, %asi - membar #LoadStore|#StoreLoad|#StoreStore - sub %o0, 64, %o0 - ldda [%o1] %asi, %f0 - ldda [%o2] %asi, %f16 - -5: ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f48 - fxor %f2, %f18, %f50 - add %o1, 64, %o1 - fxor %f4, %f20, %f52 - fxor %f6, %f22, %f54 - add %o2, 64, %o2 - fxor %f8, %f24, %f56 - fxor %f10, %f26, %f58 - fxor %f12, %f28, %f60 - fxor %f14, %f30, %f62 - ldda [%o4] %asi, %f16 - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - add %o3, 64, %o3 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - ldda [%o5] %asi, %f32 - fxor %f48, %f16, %f48 - fxor %f50, %f18, %f50 - add %o4, 64, %o4 - fxor %f52, %f20, %f52 - fxor %f54, %f22, %f54 - add %o5, 64, %o5 - fxor %f56, %f24, %f56 - fxor %f58, %f26, %f58 - fxor %f60, %f28, %f60 - fxor %f62, %f30, %f62 - ldda [%o1] %asi, %f0 - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - subcc %o0, 64, %o0 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - stda %f48, [%o1 - 64] %asi - bne,pt %xcc, 5b - ldda [%o2] %asi, %f16 - - ldda [%o3] %asi, %f32 - fxor %f0, %f16, %f48 - fxor %f2, %f18, %f50 - fxor %f4, %f20, %f52 - fxor %f6, %f22, %f54 - fxor %f8, %f24, %f56 - fxor %f10, %f26, %f58 - fxor %f12, %f28, %f60 - fxor %f14, %f30, %f62 - ldda [%o4] %asi, %f16 - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - ldda [%o5] %asi, %f32 - fxor %f48, %f16, %f48 - fxor %f50, %f18, %f50 - fxor %f52, %f20, %f52 - fxor %f54, %f22, %f54 - fxor %f56, %f24, %f56 - fxor %f58, %f26, %f58 - fxor %f60, %f28, %f60 - fxor %f62, %f30, %f62 - membar #Sync - fxor %f48, %f32, %f48 - fxor %f50, %f34, %f50 - fxor %f52, %f36, %f52 - fxor %f54, %f38, %f54 - fxor %f56, %f40, %f56 - fxor %f58, %f42, %f58 - fxor %f60, %f44, %f60 - fxor %f62, %f46, %f62 - stda %f48, [%o1] %asi - membar #Sync|#StoreStore|#StoreLoad - wr %g1, %g0, %asi - retl - wr %g0, 0, %fprs - .size xor_vis_5, .-xor_vis_5 -"); - -static struct xor_block_template xor_block_VIS = { - .name = "VIS", - .do_2 = xor_vis_2, - .do_3 = xor_vis_3, - .do_4 = xor_vis_4, - .do_5 = xor_vis_5, -}; - -#define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) +/* + * include/asm-sparc64/xor.h + * + * High speed xor_block operation for RAID4/5 utilizing the + * UltraSparc Visual Instruction Set. + * + * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *); +extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *, + unsigned long *); +extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *); +extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *, unsigned long *); + +/* XXX Ugh, write cheetah versions... -DaveM */ + +static struct xor_block_template xor_block_VIS = { + .name = "VIS", + .do_2 = xor_vis_2, + .do_3 = xor_vis_3, + .do_4 = xor_vis_4, + .do_5 = xor_vis_5, +}; + +#define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h index 14ca8b2a462..4ddffc1a783 100644 --- a/include/asm-um/mmu_context.h +++ b/include/asm-um/mmu_context.h @@ -21,8 +21,10 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) extern void switch_mm_skas(int mm_fd); static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { + unsigned cpu = smp_processor_id(); + if(prev != next){ clear_bit(cpu, &prev->cpu_vm_mask); set_bit(cpu, &next->cpu_vm_mask); @@ -33,7 +35,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, } static inline void enter_lazy_tlb(struct mm_struct *mm, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { } diff --git a/include/asm-v850/div64.h b/include/asm-v850/div64.h index 165518b4623..6cd978cefb2 100644 --- a/include/asm-v850/div64.h +++ b/include/asm-v850/div64.h @@ -1,11 +1 @@ -#ifndef __V850_DIV64_H__ -#define __V850_DIV64_H__ - -/* We're not 64-bit, but... */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) n) % (unsigned) base; \ - n = ((unsigned long) n) / (unsigned) base; \ - __res; }) - -#endif /* __V850_DIV64_H__ */ +#include diff --git a/include/asm-v850/flat.h b/include/asm-v850/flat.h index 94a42a41e84..17106c894ab 100644 --- a/include/asm-v850/flat.h +++ b/include/asm-v850/flat.h @@ -1,8 +1,8 @@ /* * include/asm-v850/flat.h -- uClinux flat-format executables * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -14,6 +14,117 @@ #ifndef __V850_FLAT_H__ #define __V850_FLAT_H__ -#define flat_argvp_envp_on_stack() 0 +/* The amount by which a relocation can exceed the program image limits + without being regarded as an error. On the v850, the relocations of + some base-pointers can be offset by 0x8000 (to allow better usage of the + space offered by 16-bit signed offsets -- in most cases the offsets used + with such a base-pointer will be negative). */ + +#define flat_reloc_valid(reloc, size) ((reloc) <= (size + 0x8000)) + +#define flat_stack_align(sp) /* nothing needed */ +#define flat_argvp_envp_on_stack() 0 +#define flat_old_ram_flag(flags) (flags) + +/* We store the type of relocation in the top 4 bits of the `relval.' */ + +/* Convert a relocation entry into an address. */ +static inline unsigned long +flat_get_relocate_addr (unsigned long relval) +{ + return relval & 0x0fffffff; /* Mask out top 4-bits */ +} + +#define flat_v850_get_reloc_type(relval) ((relval) >> 28) + +#define FLAT_V850_R_32 0 /* Normal 32-bit reloc */ +#define FLAT_V850_R_HI16S_LO15 1 /* High 16-bits + signed 15-bit low field */ +#define FLAT_V850_R_HI16S_LO16 2 /* High 16-bits + signed 16-bit low field */ + +/* Extract the address to be relocated from the symbol reference at RP; + RELVAL is the raw relocation-table entry from which RP is derived. + For the v850, RP should always be half-word aligned. */ +static inline unsigned long flat_get_addr_from_rp (unsigned long *rp, + unsigned long relval) +{ + short *srp = (short *)rp; + + switch (flat_v850_get_reloc_type (relval)) + { + case FLAT_V850_R_32: + /* Simple 32-bit address. */ + return srp[0] | (srp[1] << 16); + + case FLAT_V850_R_HI16S_LO16: + /* The high and low halves of the address are in the 16 + bits at RP, and the 2nd word of the 32-bit instruction + following that, respectively. The low half is _signed_ + so we have to sign-extend it and add it to the upper + half instead of simply or-ing them together. + + Unlike most relocated address, this one is stored in + native (little-endian) byte-order to avoid problems with + trashing the low-order bit, so we have to convert to + network-byte-order before returning, as that's what the + caller expects. */ + return htonl ((srp[0] << 16) + srp[2]); + + case FLAT_V850_R_HI16S_LO15: + /* The high and low halves of the address are in the 16 + bits at RP, and the upper 15 bits of the 2nd word of the + 32-bit instruction following that, respectively. The + low half is _signed_ so we have to sign-extend it and + add it to the upper half instead of simply or-ing them + together. The lowest bit is always zero. + + Unlike most relocated address, this one is stored in + native (little-endian) byte-order to avoid problems with + trashing the low-order bit, so we have to convert to + network-byte-order before returning, as that's what the + caller expects. */ + return htonl ((srp[0] << 16) + (srp[2] & ~0x1)); + + default: + return ~0; /* bogus value */ + } +} + +/* Insert the address ADDR into the symbol reference at RP; + RELVAL is the raw relocation-table entry from which RP is derived. + For the v850, RP should always be half-word aligned. */ +static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr, + unsigned long relval) +{ + short *srp = (short *)rp; + + switch (flat_v850_get_reloc_type (relval)) { + case FLAT_V850_R_32: + /* Simple 32-bit address. */ + srp[0] = addr & 0xFFFF; + srp[1] = (addr >> 16); + break; + + case FLAT_V850_R_HI16S_LO16: + /* The high and low halves of the address are in the 16 + bits at RP, and the 2nd word of the 32-bit instruction + following that, respectively. The low half is _signed_ + so we must carry its sign bit to the upper half before + writing the upper half. */ + srp[0] = (addr >> 16) + ((addr >> 15) & 0x1); + srp[2] = addr & 0xFFFF; + break; + + case FLAT_V850_R_HI16S_LO15: + /* The high and low halves of the address are in the 16 + bits at RP, and the upper 15 bits of the 2nd word of the + 32-bit instruction following that, respectively. The + low half is _signed_ so we must carry its sign bit to + the upper half before writing the upper half. The + lowest bit we preserve from the existing instruction. */ + srp[0] = (addr >> 16) + ((addr >> 15) & 0x1); + srp[2] = (addr & 0xFFFE) | (srp[2] & 0x1); + break; + } +} #endif /* __V850_FLAT_H__ */ diff --git a/include/asm-v850/mmu_context.h b/include/asm-v850/mmu_context.h index 24301a46a92..f521c8050d3 100644 --- a/include/asm-v850/mmu_context.h +++ b/include/asm-v850/mmu_context.h @@ -3,9 +3,9 @@ #define destroy_context(mm) ((void)0) #define init_new_context(tsk,mm) 0 -#define switch_mm(prev,next,tsk,cpu) ((void)0) +#define switch_mm(prev,next,tsk) ((void)0) #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev,next) ((void)0) -#define enter_lazy_tlb(mm,tsk,cpu) ((void)0) +#define enter_lazy_tlb(mm,tsk) ((void)0) #endif /* __V850_MMU_CONTEXT_H__ */ diff --git a/include/asm-x86_64/div64.h b/include/asm-x86_64/div64.h index 2c94d0762fe..6cd978cefb2 100644 --- a/include/asm-x86_64/div64.h +++ b/include/asm-x86_64/div64.h @@ -1,14 +1 @@ -#ifndef __X86_64_DIV64 -#define __X86_64_DIV64 - -/* - * Hey, we're already 64-bit, no - * need to play games.. - */ -#define do_div(n,base) ({ \ - int __res; \ - __res = ((unsigned long) (n)) % (unsigned) (base); \ - (n) = ((unsigned long) (n)) / (unsigned) (base); \ - __res; }) - -#endif +#include diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h index 41fc9820ee9..8f80f157035 100644 --- a/include/asm-x86_64/mmu_context.h +++ b/include/asm-x86_64/mmu_context.h @@ -17,20 +17,21 @@ void destroy_context(struct mm_struct *mm); #ifdef CONFIG_SMP -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { if (read_pda(mmu_state) == TLBSTATE_OK) write_pda(mmu_state, TLBSTATE_LAZY); } #else -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } #endif static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, unsigned cpu) + struct task_struct *tsk) { + unsigned cpu = smp_processor_id(); if (likely(prev != next)) { /* stop flush ipis for the previous mm */ clear_bit(cpu, &prev->cpu_vm_mask); @@ -68,7 +69,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, } while(0) #define activate_mm(prev, next) \ - switch_mm((prev),(next),NULL,smp_processor_id()) + switch_mm((prev),(next),NULL) #endif diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h index c1a69000c8d..398c530270c 100644 --- a/include/asm-x86_64/mmzone.h +++ b/include/asm-x86_64/mmzone.h @@ -40,8 +40,7 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr) #define node_mem_map(nid) (NODE_DATA(nid)->node_mem_map) #define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) #define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \ - NODE_DATA(nid)->node_size) -#define node_size(nid) (NODE_DATA(nid)->node_size) + NODE_DATA(nid)->node_spanned_pages) #define local_mapnr(kvaddr) \ ( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) ) diff --git a/include/linux/acct.h b/include/linux/acct.h index 0b4ae8298a0..69389c4af8e 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -78,7 +78,7 @@ struct acct #ifdef CONFIG_BSD_PROCESS_ACCT struct super_block; extern void acct_auto_close(struct super_block *sb); -extern int acct_process(long exitcode); +extern void acct_process(long exitcode); #else #define acct_auto_close(x) do { } while (0) #define acct_process(x) do { } while (0) diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h index 47ed05c8b74..c849309b113 100644 --- a/include/linux/affs_fs.h +++ b/include/linux/affs_fs.h @@ -41,9 +41,9 @@ extern int affs_init_bitmap(struct super_block *sb); /* namei.c */ extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len); -extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry); +extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); extern int affs_unlink(struct inode *dir, struct dentry *dentry); -extern int affs_create(struct inode *dir, struct dentry *dentry, int mode); +extern int affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *); extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); extern int affs_rmdir(struct inode *dir, struct dentry *dentry); extern int affs_link(struct dentry *olddentry, struct inode *dir, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 786ea356375..2e7f92aa1dc 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -22,11 +22,62 @@ typedef struct elevator_s elevator_t; struct request_pm_state; #define BLKDEV_MIN_RQ 4 -#define BLKDEV_MAX_RQ 128 +#define BLKDEV_MAX_RQ 128 /* Default maximum */ + +/* + * This is the per-process anticipatory I/O scheduler state. + */ +struct as_io_context { + spinlock_t lock; + + void (*dtor)(struct as_io_context *aic); /* destructor */ + void (*exit)(struct as_io_context *aic); /* called on task exit */ + + unsigned long state; + atomic_t nr_queued; /* queued reads & sync writes */ + atomic_t nr_dispatched; /* number of requests gone to the drivers */ + + /* IO History tracking */ + /* Thinktime */ + unsigned long last_end_request; + unsigned long ttime_total; + unsigned long ttime_samples; + unsigned long ttime_mean; + /* Layout pattern */ + long seek_samples; + sector_t last_request_pos; + sector_t seek_total; + sector_t seek_mean; +}; + +/* + * This is the per-process I/O subsystem state. It is refcounted and + * kmalloc'ed. Currently all fields are modified in process io context + * (apart from the atomic refcount), so require no locking. + */ +struct io_context { + atomic_t refcount; + pid_t pid; + + /* + * For request batching + */ + unsigned long last_waited; /* Time last woken after wait for request */ + int nr_batch_requests; /* Number of requests left in the batch */ + + struct as_io_context *aic; +}; + +void put_io_context(struct io_context *ioc); +void exit_io_context(void); +struct io_context *get_io_context(int gfp_flags); +void copy_io_context(struct io_context **pdst, struct io_context **psrc); +void swap_io_context(struct io_context **ioc1, struct io_context **ioc2); struct request_list { int count[2]; mempool_t *rq_pool; + wait_queue_head_t wait[2]; }; /* @@ -268,8 +319,15 @@ struct request_queue spinlock_t *queue_lock; /* + * queue kobject + */ + struct kobject kobj; + + /* * queue settings */ + unsigned long nr_requests; /* Max # of requests */ + unsigned short max_sectors; unsigned short max_phys_segments; unsigned short max_hw_segments; @@ -299,6 +357,8 @@ struct request_queue #define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */ #define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ #define QUEUE_FLAG_STOPPED 2 /* queue is stopped */ +#define QUEUE_FLAG_READFULL 3 /* write queue has been filled */ +#define QUEUE_FLAG_WRITEFULL 4 /* read queue has been filled */ #define blk_queue_plugged(q) !list_empty(&(q)->plug_list) #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) @@ -314,6 +374,30 @@ struct request_queue #define rq_data_dir(rq) ((rq)->flags & 1) +static inline int blk_queue_full(struct request_queue *q, int rw) +{ + if (rw == READ) + return test_bit(QUEUE_FLAG_READFULL, &q->queue_flags); + return test_bit(QUEUE_FLAG_WRITEFULL, &q->queue_flags); +} + +static inline void blk_set_queue_full(struct request_queue *q, int rw) +{ + if (rw == READ) + set_bit(QUEUE_FLAG_READFULL, &q->queue_flags); + else + set_bit(QUEUE_FLAG_WRITEFULL, &q->queue_flags); +} + +static inline void blk_clear_queue_full(struct request_queue *q, int rw) +{ + if (rw == READ) + clear_bit(QUEUE_FLAG_READFULL, &q->queue_flags); + else + clear_bit(QUEUE_FLAG_WRITEFULL, &q->queue_flags); +} + + /* * mergeable request must not have _NOMERGE or _BARRIER bit set, nor may * it already be started by driver. @@ -397,6 +481,8 @@ struct sec_size { unsigned block_size_bits; }; +extern int blk_register_queue(struct gendisk *disk); +extern void blk_unregister_queue(struct gendisk *disk); extern void register_disk(struct gendisk *dev); extern void generic_make_request(struct bio *bio); extern void blk_put_request(struct request *); @@ -560,6 +646,10 @@ static inline void put_dev_sector(Sector p) page_cache_release(p.v); } +struct work_struct; +int kblockd_schedule_work(struct work_struct *work); +void kblockd_flush(void); + #ifdef CONFIG_LBD # include # define sector_div(a, b) do_div(a, b) diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 22d3ac8efc6..1f468b0491e 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -167,6 +167,7 @@ struct buffer_head *__find_get_block(struct block_device *, sector_t, int); struct buffer_head * __getblk(struct block_device *, sector_t, int); void __brelse(struct buffer_head *); void __bforget(struct buffer_head *); +void __breadahead(struct block_device *, sector_t block, int size); struct buffer_head *__bread(struct block_device *, sector_t block, int size); struct buffer_head *alloc_buffer_head(int gfp_flags); void free_buffer_head(struct buffer_head * bh); @@ -241,6 +242,12 @@ sb_bread(struct super_block *sb, sector_t block) return __bread(sb->s_bdev, block, sb->s_blocksize); } +static inline void +sb_breadahead(struct super_block *sb, sector_t block) +{ + __breadahead(sb->s_bdev, block, sb->s_blocksize); +} + static inline struct buffer_head * sb_getblk(struct super_block *sb, sector_t block) { diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h index b22d34fcfb6..650a6f997f8 100644 --- a/include/linux/coda_linux.h +++ b/include/linux/coda_linux.h @@ -38,7 +38,7 @@ extern struct file_operations coda_ioctl_operations; int coda_open(struct inode *i, struct file *f); int coda_flush(struct file *f); int coda_release(struct inode *i, struct file *f); -int coda_permission(struct inode *inode, int mask); +int coda_permission(struct inode *inode, int mask, struct nameidata *nd); int coda_revalidate_inode(struct dentry *); int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); int coda_setattr(struct dentry *, struct iattr *); diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 076b1b268c7..3fb888cc0c3 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -117,7 +117,7 @@ COMPATIBLE_IOCTL(START_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY) COMPATIBLE_IOCTL(STOP_ARRAY_RO) COMPATIBLE_IOCTL(RESTART_ARRAY_RW) -#ifdef CONFIG_DM +#ifdef CONFIG_BLK_DEV_DM /* DM */ COMPATIBLE_IOCTL(DM_VERSION) COMPATIBLE_IOCTL(DM_REMOVE_ALL) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 4ef20f517d2..79e1773251f 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -56,6 +56,24 @@ #define __attribute_used__ __attribute__((__unused__)) #endif +/* + * From the GCC manual: + * + * Many functions have no effects except the return value and their + * return value depends only on the parameters and/or global + * variables. Such a function can be subject to common subexpression + * elimination and loop optimization just as an arithmetic operator + * would be. + * [...] + * The attribute `pure' is not implemented in GCC versions earlier + * than 2.96. + */ +#if (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || __GNUC__ > 2 +#define __attribute_pure__ __attribute__((pure)) +#else +#define __attribute_pure__ /* unimplemented */ +#endif + /* This macro obfuscates arithmetic on a variable address so that gcc shouldn't recognize the original var, and make assumptions about it */ #define RELOC_HIDE(ptr, off) \ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 1bdb797bf9b..dc29d5c4e71 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -20,6 +20,7 @@ #include #include #include +#include #define CPUFREQ_NAME_LEN 16 @@ -31,17 +32,15 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); -#define CPUFREQ_TRANSITION_NOTIFIER (0) -#define CPUFREQ_POLICY_NOTIFIER (1) - -#define CPUFREQ_ALL_CPUS ((NR_CPUS)) +#define CPUFREQ_TRANSITION_NOTIFIER (0) +#define CPUFREQ_POLICY_NOTIFIER (1) /********************** cpufreq policy notifiers *********************/ -#define CPUFREQ_POLICY_POWERSAVE (1) -#define CPUFREQ_POLICY_PERFORMANCE (2) -#define CPUFREQ_POLICY_GOVERNOR (3) +#define CPUFREQ_POLICY_POWERSAVE (1) +#define CPUFREQ_POLICY_PERFORMANCE (2) +#define CPUFREQ_POLICY_GOVERNOR (3) /* Frequency values here are CPU kHz so that hardware which doesn't run * with some frequencies can complain without having to guess what per @@ -52,30 +51,34 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); struct cpufreq_governor; -#define CPUFREQ_ETERNAL (-1) +#define CPUFREQ_ETERNAL (-1) struct cpufreq_cpuinfo { - unsigned int max_freq; - unsigned int min_freq; - unsigned int transition_latency; + unsigned int max_freq; + unsigned int min_freq; + unsigned int transition_latency; /* in 10^(-9) s */ }; struct cpufreq_policy { - unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ - unsigned int min; /* in kHz */ - unsigned int max; /* in kHz */ - unsigned int cur; /* in kHz, only needed if cpufreq + unsigned int cpu; /* cpu nr */ + struct cpufreq_cpuinfo cpuinfo;/* see above */ + + unsigned int min; /* in kHz */ + unsigned int max; /* in kHz */ + unsigned int cur; /* in kHz, only needed if cpufreq * governors are used */ - unsigned int policy; /* see above */ - struct cpufreq_governor *governor; /* see below */ - struct cpufreq_cpuinfo cpuinfo; /* see above */ - struct kobject kobj; + unsigned int policy; /* see above */ + struct cpufreq_governor *governor; /* see below */ + struct semaphore lock; /* CPU ->setpolicy or ->target may only be called once a time */ + + struct kobject kobj; + struct completion kobj_unregister; }; -#define CPUFREQ_ADJUST (0) -#define CPUFREQ_INCOMPATIBLE (1) -#define CPUFREQ_NOTIFY (2) +#define CPUFREQ_ADJUST (0) +#define CPUFREQ_INCOMPATIBLE (1) +#define CPUFREQ_NOTIFY (2) /******************** cpufreq transition notifiers *******************/ @@ -84,7 +87,7 @@ struct cpufreq_policy { #define CPUFREQ_POSTCHANGE (1) struct cpufreq_freqs { - unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ + unsigned int cpu; /* cpu nr */ unsigned int old; unsigned int new; }; @@ -125,11 +128,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu #define CPUFREQ_GOV_LIMITS 3 struct cpufreq_governor { - char name[CPUFREQ_NAME_LEN]; - int (*governor) (struct cpufreq_policy *policy, + char name[CPUFREQ_NAME_LEN]; + int (*governor) (struct cpufreq_policy *policy, unsigned int event); struct list_head governor_list; - struct module *owner; + struct module *owner; }; /* pass a target to the cpufreq driver @@ -154,18 +157,22 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor); struct freq_attr; struct cpufreq_driver { + struct module *owner; + char name[CPUFREQ_NAME_LEN]; + + struct cpufreq_policy *policy; + /* needed by all drivers */ + int (*init) (struct cpufreq_policy *policy); int (*verify) (struct cpufreq_policy *policy); - struct cpufreq_policy *policy; - char name[CPUFREQ_NAME_LEN]; + /* define one out of two */ int (*setpolicy) (struct cpufreq_policy *policy); int (*target) (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation); - struct module *owner; - /* optional, for the moment */ - int (*init) (struct cpufreq_policy *policy); + + /* optional */ int (*exit) (struct cpufreq_policy *policy); struct freq_attr **attr; }; @@ -306,8 +313,4 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu); #endif /* CONFIG_CPU_FREQ_TABLE */ - -/* Currently exported only for the proc interface, remove when that goes */ -extern struct cpufreq_driver *cpufreq_driver; - #endif /* _LINUX_CPUFREQ_H */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 1442779bd89..a25d9f0443a 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -10,6 +10,7 @@ #include #include +struct nameidata; struct vfsmount; /* @@ -106,7 +107,7 @@ struct dentry { #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) struct dentry_operations { - int (*d_revalidate)(struct dentry *, int); + int (*d_revalidate)(struct dentry *, struct nameidata *); int (*d_hash) (struct dentry *, struct qstr *); int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); int (*d_delete)(struct dentry *); diff --git a/include/linux/device.h b/include/linux/device.h index 1bd92551c07..2795b85ac6f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,7 @@ struct bus_attribute { #define BUS_ATTR(_name,_mode,_show,_store) \ struct bus_attribute bus_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ }; @@ -136,7 +137,7 @@ struct driver_attribute { #define DRIVER_ATTR(_name,_mode,_show,_store) \ struct driver_attribute driver_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ }; @@ -176,7 +177,7 @@ struct class_attribute { #define CLASS_ATTR(_name,_mode,_show,_store) \ struct class_attribute class_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ }; @@ -215,6 +216,8 @@ extern void class_device_initialize(struct class_device *); extern int class_device_add(struct class_device *); extern void class_device_del(struct class_device *); +extern int class_device_rename(struct class_device *, char *); + extern struct class_device * class_device_get(struct class_device *); extern void class_device_put(struct class_device *); @@ -226,7 +229,7 @@ struct class_device_attribute { #define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ struct class_device_attribute class_device_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ }; @@ -324,7 +327,7 @@ struct device_attribute { #define DEVICE_ATTR(_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ }; diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h index c78e9c2a7b3..1640eb875d4 100644 --- a/include/linux/efs_fs.h +++ b/include/linux/efs_fs.h @@ -46,7 +46,7 @@ extern int efs_statfs(struct super_block *, struct kstatfs *); extern void efs_read_inode(struct inode *); extern efs_block_t efs_map_block(struct inode *, efs_block_t); -extern struct dentry *efs_lookup(struct inode *, struct dentry *); +extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *); extern int efs_bmap(struct inode *, int); #endif /* __EFS_FS_H__ */ diff --git a/include/linux/eisa.h b/include/linux/eisa.h index d77fdf0f9f0..93e4c5503d4 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -4,6 +4,8 @@ #define EISA_SIG_LEN 8 #define EISA_MAX_SLOTS 8 +#define EISA_MAX_RESOURCES 4 + /* A few EISA constants/offsets... */ #define EISA_DMA1_STATUS 8 @@ -17,6 +19,10 @@ #define EISA_INT1_EDGE_LEVEL 0x4D0 #define EISA_INT2_EDGE_LEVEL 0x4D1 #define EISA_VENDOR_ID_OFFSET 0xC80 +#define EISA_CONFIG_OFFSET 0xC84 + +#define EISA_CONFIG_ENABLED 1 +#define EISA_CONFIG_FORCED 2 /* The EISA signature, in ASCII form, null terminated */ struct eisa_device_id { @@ -26,19 +32,28 @@ struct eisa_device_id { /* There is not much we can say about an EISA device, apart from * signature, slot number, and base address. dma_mask is set by - * default to 32 bits.*/ + * default to parent device mask..*/ struct eisa_device { struct eisa_device_id id; int slot; + int state; unsigned long base_addr; - struct resource res; + struct resource res[EISA_MAX_RESOURCES]; u64 dma_mask; struct device dev; /* generic device */ }; #define to_eisa_device(n) container_of(n, struct eisa_device, dev) +static inline int eisa_get_region_index (void *addr) +{ + unsigned long x = (unsigned long) addr; + + x &= 0xc00; + return (x >> 12); +} + struct eisa_driver { const struct eisa_device_id *id_table; struct device_driver driver; @@ -69,6 +84,8 @@ struct eisa_root_device { struct resource *res; unsigned long bus_base_addr; int slots; /* Max slot number */ + int force_probe; /* Probe even when no slot 0 */ + u64 dma_mask; /* from bridge device */ int bus_nr; /* Set by eisa_root_register */ struct resource eisa_root_res; /* ditto */ }; diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 522e51609ef..b0e70562be9 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -15,6 +15,9 @@ typedef int (elevator_queue_empty_fn) (request_queue_t *); typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *); typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *); +typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *); +typedef int (elevator_may_queue_fn) (request_queue_t *, int); + typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int); typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); @@ -32,6 +35,7 @@ struct elevator_s elevator_remove_req_fn *elevator_remove_req_fn; elevator_queue_empty_fn *elevator_queue_empty_fn; + elevator_completed_req_fn *elevator_completed_req_fn; elevator_request_list_fn *elevator_former_req_fn; elevator_request_list_fn *elevator_latter_req_fn; @@ -39,6 +43,8 @@ struct elevator_s elevator_set_req_fn *elevator_set_req_fn; elevator_put_req_fn *elevator_put_req_fn; + elevator_may_queue_fn *elevator_may_queue_fn; + elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; @@ -62,8 +68,10 @@ extern int elv_queue_empty(request_queue_t *); extern struct request *elv_next_request(struct request_queue *q); extern struct request *elv_former_request(request_queue_t *, struct request *); extern struct request *elv_latter_request(request_queue_t *, struct request *); -extern int elv_register_queue(struct gendisk *); -extern void elv_unregister_queue(struct gendisk *); +extern int elv_register_queue(request_queue_t *q); +extern void elv_unregister_queue(request_queue_t *q); +extern int elv_may_queue(request_queue_t *, int); +extern void elv_completed_request(request_queue_t *, struct request *); extern int elv_set_request(request_queue_t *, struct request *, int); extern void elv_put_request(request_queue_t *, struct request *); @@ -81,6 +89,11 @@ extern elevator_t elevator_noop; */ extern elevator_t iosched_deadline; +/* + * anticipatory I/O scheduler + */ +extern elevator_t iosched_as; + extern int elevator_init(request_queue_t *, elevator_t *); extern void elevator_exit(request_queue_t *); extern inline int elv_rq_merge_ok(struct request *, struct bio *); diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 60f8cadb1f5..f89acbe8183 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -14,6 +14,8 @@ #ifndef _LINUX_EVENTPOLL_H #define _LINUX_EVENTPOLL_H +#include + /* Valid opcodes to issue to sys_epoll_ctl() */ #define EPOLL_CTL_ADD 1 @@ -55,8 +57,37 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event *events, int maxeven /* Used to initialize the epoll bits inside the "struct file" */ void eventpoll_init_file(struct file *file); -/* Used in fs/file_table.c:__fput() to unlink files from the eventpoll interface */ -void eventpoll_release(struct file *file); +/* Used to release the epoll bits inside the "struct file" */ +void eventpoll_release_file(struct file *file); + +/* + * This is called from inside fs/file_table.c:__fput() to unlink files + * from the eventpoll interface. We need to have this facility to cleanup + * correctly files that are closed without being removed from the eventpoll + * interface. + */ +static inline void eventpoll_release(struct file *file) +{ + + /* + * Fast check to avoid the get/release of the semaphore. Since + * we're doing this outside the semaphore lock, it might return + * false negatives, but we don't care. It'll help in 99.99% of cases + * to avoid the semaphore lock. False positives simply cannot happen + * because the file in on the way to be removed and nobody ( but + * eventpoll ) has still a reference to this file. + */ + if (likely(list_empty(&file->f_ep_links))) + return; + + /* + * The file is being closed while it is still linked to an epoll + * descriptor. We need to handle this by correctly unlinking it + * from its containers. + */ + eventpoll_release_file(file); +} + #else diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index f077563bcfc..c360f84fed3 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -636,10 +636,14 @@ struct dx_hash_info struct ext3_iloc { struct buffer_head *bh; - struct ext3_inode *raw_inode; + unsigned long offset; unsigned long block_group; }; +static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc) +{ + return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset); +} /* * This structure is stuffed into the struct file's private_data field diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 1a6a6c5922f..1181cfae714 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -62,6 +62,16 @@ struct ext3_inode_info { __u32 i_prealloc_count; #endif __u32 i_dir_start_lookup; +#ifdef CONFIG_EXT3_FS_XATTR + /* + * Extended attributes can be read independently of the main file + * data. Taking i_sem even when reading would cause contention + * between readers of EAs and writers of regular file data, so + * instead we synchronize on xattr_sem when reading or changing + * EAs. + */ + struct rw_semaphore xattr_sem; +#endif #ifdef CONFIG_EXT3_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl; diff --git a/include/linux/flat.h b/include/linux/flat.h index 7643a3f9d3f..ec56852e265 100644 --- a/include/linux/flat.h +++ b/include/linux/flat.h @@ -1,7 +1,7 @@ - -/* Copyright (C) 1998 Kenneth Albanowski - * The Silver Hammer Group, Ltd. - * Copyright (C) 2002 David McCullough +/* + * Copyright (C) 2002-2003 David McCullough + * Copyright (C) 1998 Kenneth Albanowski + * The Silver Hammer Group, Ltd. * * This file provides the definitions and structures needed to * support uClinux flat-format executables. @@ -10,10 +10,18 @@ #ifndef _LINUX_FLAT_H #define _LINUX_FLAT_H +#ifdef __KERNEL__ #include +#endif #define FLAT_VERSION 0x00000004L +#ifdef CONFIG_BINFMT_SHARED_FLAT +#define MAX_SHARED_LIBS (4) +#else +#define MAX_SHARED_LIBS (1) +#endif + /* * To make everything easier to port and manage cross platform * development, all fields are in network byte order. @@ -46,8 +54,10 @@ struct flat_hdr { #define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */ #define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */ #define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */ +#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */ +#ifdef __KERNEL__ /* so systems without linux headers can compile the apps */ /* * While it would be nice to keep this header clean, users of older * tools still need this support in the kernel. So this section is @@ -85,4 +95,6 @@ typedef union { } reloc; } flat_v2_reloc_t; +#endif /* __KERNEL__ */ + #endif /* _LINUX_FLAT_H */ diff --git a/include/linux/fs.h b/include/linux/fs.h index c3bda88631b..77dd4b13dc4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -420,6 +420,8 @@ struct file_ra_state { unsigned long ahead_start; /* Ahead window */ unsigned long ahead_size; unsigned long ra_pages; /* Maximum readahead window */ + unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ + unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ }; struct file { @@ -639,7 +641,7 @@ static inline void unlock_super(struct super_block * sb) /* * VFS helper functions.. */ -extern int vfs_create(struct inode *, struct dentry *, int); +extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *); extern int vfs_mkdir(struct inode *, struct dentry *, int); extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t); extern int vfs_symlink(struct inode *, struct dentry *, const char *); @@ -730,8 +732,8 @@ struct file_operations { }; struct inode_operations { - int (*create) (struct inode *,struct dentry *,int); - struct dentry * (*lookup) (struct inode *,struct dentry *); + int (*create) (struct inode *,struct dentry *,int, struct nameidata *); + struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct inode *,struct dentry *,const char *); @@ -743,7 +745,7 @@ struct inode_operations { int (*readlink) (struct dentry *, char __user *,int); int (*follow_link) (struct dentry *, struct nameidata *); void (*truncate) (struct inode *); - int (*permission) (struct inode *, int); + int (*permission) (struct inode *, int, struct nameidata *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); @@ -1121,7 +1123,7 @@ extern int do_remount_sb(struct super_block *sb, int flags, extern sector_t bmap(struct inode *, sector_t); extern int setattr_mask(unsigned int); extern int notify_change(struct dentry *, struct iattr *); -extern int permission(struct inode *, int); +extern int permission(struct inode *, int, struct nameidata *); extern int vfs_permission(struct inode *, int); extern int get_write_access(struct inode *); extern int deny_write_access(struct file *); @@ -1291,7 +1293,7 @@ extern int simple_prepare_write(struct file *file, struct page *page, extern int simple_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to); -extern struct dentry *simple_lookup(struct inode *, struct dentry *); +extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata *); extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); extern struct file_operations simple_dir_operations; extern struct inode_operations simple_dir_inode_operations; diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h index 40971822e3e..7bebd13150d 100644 --- a/include/linux/hfs_fs.h +++ b/include/linux/hfs_fs.h @@ -234,7 +234,7 @@ extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *, const struct hfs_cat_key *); /* dir.c */ -extern int hfs_create(struct inode *, struct dentry *, int); +extern int hfs_create(struct inode *, struct dentry *, int, struct nameidata *); extern int hfs_mkdir(struct inode *, struct dentry *, int); extern int hfs_unlink(struct inode *, struct dentry *); extern int hfs_rmdir(struct inode *, struct dentry *); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index da2eaeb1811..21e48723b38 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -94,8 +94,8 @@ struct softirq_action asmlinkage void do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); extern void softirq_init(void); -#define __cpu_raise_softirq(cpu, nr) do { softirq_pending(cpu) |= 1UL << (nr); } while (0) -extern void FASTCALL(cpu_raise_softirq(unsigned int cpu, unsigned int nr)); +#define __raise_softirq_irqoff(nr) do { local_softirq_pending() |= 1UL << (nr); } while (0) +extern void FASTCALL(raise_softirq_irqoff(unsigned int nr)); extern void FASTCALL(raise_softirq(unsigned int nr)); #ifndef invoke_softirq diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 9193a8df012..26d6293ed4c 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -43,6 +43,7 @@ struct resource_list { #define IORESOURCE_SHADOWABLE 0x00010000 #define IORESOURCE_BUS_HAS_VGA 0x00080000 +#define IORESOURCE_DISABLED 0x10000000 #define IORESOURCE_UNSET 0x20000000 #define IORESOURCE_AUTO 0x40000000 #define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ diff --git a/include/linux/irq_cpustat.h b/include/linux/irq_cpustat.h index 3f49c2ba63e..03b3e17de80 100644 --- a/include/linux/irq_cpustat.h +++ b/include/linux/irq_cpustat.h @@ -29,10 +29,6 @@ extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */ /* arch independent irq_stat fields */ #define softirq_pending(cpu) __IRQ_STAT((cpu), __softirq_pending) #define local_softirq_pending() softirq_pending(smp_processor_id()) -#define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) -#define local_syscall_count() syscall_count(smp_processor_id()) -#define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) -#define local_ksoftirqd_task() ksoftirqd_task(smp_processor_id()) /* arch dependent irq_stat fields */ #define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386 */ diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h index 4763b595287..223f161da01 100644 --- a/include/linux/iso_fs.h +++ b/include/linux/iso_fs.h @@ -227,7 +227,7 @@ extern int isofs_name_translate(struct iso_directory_record *, char *, struct in int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *); int get_acorn_filename(struct iso_directory_record *, char *, struct inode *); -extern struct dentry *isofs_lookup(struct inode *, struct dentry *); +extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *); extern struct buffer_head *isofs_bread(struct inode *, sector_t); extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 88425e94cdc..9971827a3c4 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -31,7 +31,8 @@ struct kernel_stat { DECLARE_PER_CPU(struct kernel_stat, kstat); #define kstat_cpu(cpu) per_cpu(kstat, cpu) -#define kstat_this_cpu kstat_cpu(smp_processor_id()) +/* Must have preemption disabled for this to be meaningful. */ +#define kstat_this_cpu __get_cpu_var(kstat) extern unsigned long nr_context_switches(void); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 5d42248dd95..e744a55d07d 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -39,6 +39,8 @@ extern void kobject_cleanup(struct kobject *); extern int kobject_add(struct kobject *); extern void kobject_del(struct kobject *); +extern void kobject_rename(struct kobject *, char *new_name); + extern int kobject_register(struct kobject *); extern void kobject_unregister(struct kobject *); diff --git a/include/linux/mm.h b/include/linux/mm.h index 492bc8aeb05..858914b2dbd 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -339,9 +339,14 @@ static inline void set_page_zone(struct page *page, unsigned long zone_num) page->flags |= zone_num << ZONE_SHIFT; } -static inline void * lowmem_page_address(struct page *page) +#ifndef CONFIG_DISCONTIGMEM +/* The array of struct pages - for discontigmem use pgdat->lmem_map */ +extern struct page *mem_map; +#endif + +static inline void *lowmem_page_address(struct page *page) { - return __va( ( (page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn) << PAGE_SHIFT); + return __va(page_to_pfn(page) << PAGE_SHIFT); } #if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) @@ -395,11 +400,6 @@ static inline int page_mapped(struct page *page) #define VM_FAULT_MINOR 1 #define VM_FAULT_MAJOR 2 -#ifndef CONFIG_DISCONTIGMEM -/* The array of struct pages - for discontigmem use pgdat->lmem_map */ -extern struct page *mem_map; -#endif - extern void show_free_areas(void); struct page *shmem_nopage(struct vm_area_struct * vma, @@ -571,10 +571,6 @@ void page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *filp, unsigned long offset); -void page_cache_readaround(struct address_space *mapping, - struct file_ra_state *ra, - struct file *filp, - unsigned long offset); void handle_ra_miss(struct address_space *mapping, struct file_ra_state *ra, pgoff_t offset); unsigned long max_sane_readahead(unsigned long nr); @@ -609,5 +605,13 @@ extern struct page * follow_page(struct mm_struct *mm, unsigned long address, int write); extern int remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot); + +#ifndef CONFIG_DEBUG_PAGEALLOC +static inline void +kernel_map_pages(struct page *page, int numpages, int enable) +{ +} +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ diff --git a/include/linux/mman.h b/include/linux/mman.h index 474d1c04643..a8956f6588a 100644 --- a/include/linux/mman.h +++ b/include/linux/mman.h @@ -9,7 +9,8 @@ #define MREMAP_MAYMOVE 1 #define MREMAP_FIXED 2 -extern int vm_enough_memory(long pages); +extern int sysctl_overcommit_memory; +extern int sysctl_overcommit_ratio; extern atomic_t vm_committed_space; #ifdef CONFIG_SMP diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 21e95664fdf..e768f7ab896 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -184,12 +184,17 @@ typedef struct pglist_data { unsigned long *valid_addr_bitmap; struct bootmem_data *bdata; unsigned long node_start_pfn; - unsigned long node_size; + unsigned long node_present_pages; /* total number of physical pages */ + unsigned long node_spanned_pages; /* total size of physical page + range, including holes */ int node_id; struct pglist_data *pgdat_next; wait_queue_head_t kswapd_wait; } pg_data_t; +#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages) +#define node_spanned_pages(nid) (NODE_DATA(nid)->node_spanned_pages) + extern int numnodes; extern struct pglist_data *pgdat_list; diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 4268ed11243..1ce9ba2f57b 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -307,8 +307,8 @@ extern int fat_scan(struct inode *dir, const char *name, struct msdos_dir_entry **res_de, loff_t *i_pos); /* msdos/namei.c - these are for Umsdos */ -extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *); -extern int msdos_create(struct inode *dir, struct dentry *dentry, int mode); +extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *, struct nameidata *); +extern int msdos_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *); extern int msdos_rmdir(struct inode *dir, struct dentry *dentry); extern int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode); extern int msdos_unlink(struct inode *dir, struct dentry *dentry); @@ -317,8 +317,8 @@ extern int msdos_rename(struct inode *old_dir, struct dentry *old_dentry, extern int msdos_fill_super(struct super_block *sb, void *data, int silent); /* vfat/namei.c - these are for dmsdos */ -extern struct dentry *vfat_lookup(struct inode *dir, struct dentry *); -extern int vfat_create(struct inode *dir, struct dentry *dentry, int mode); +extern struct dentry *vfat_lookup(struct inode *dir, struct dentry *, struct nameidata *); +extern int vfat_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *); extern int vfat_rmdir(struct inode *dir, struct dentry *dentry); extern int vfat_unlink(struct inode *dir, struct dentry *dentry); extern int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode); diff --git a/include/linux/namei.h b/include/linux/namei.h index 16baf5cdb9c..4117cd90a34 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -5,12 +5,22 @@ struct vfsmount; +struct open_intent { + int flags; + int create_mode; +}; + struct nameidata { struct dentry *dentry; struct vfsmount *mnt; struct qstr last; unsigned int flags; int last_type; + + /* Intent data */ + union { + struct open_intent open; + } intent; }; /* @@ -31,7 +41,12 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_CONTINUE 4 #define LOOKUP_PARENT 16 #define LOOKUP_NOALT 32 - +/* + * Intent data + */ +#define LOOKUP_OPEN (0x0100) +#define LOOKUP_CREATE (0x0200) +#define LOOKUP_ACCESS (0x0400) extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *)); #define user_path_walk(name,nd) \ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d79375c3327..3aef822b449 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -561,7 +561,7 @@ static inline void __netif_schedule(struct net_device *dev) cpu = smp_processor_id(); dev->next_sched = softnet_data[cpu].output_queue; softnet_data[cpu].output_queue = dev; - cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); + raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); } } @@ -612,7 +612,7 @@ static inline void dev_kfree_skb_irq(struct sk_buff *skb) cpu = smp_processor_id(); skb->next = softnet_data[cpu].completion_queue; softnet_data[cpu].completion_queue = skb; - cpu_raise_softirq(cpu, NET_TX_SOFTIRQ); + raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); } } @@ -779,7 +779,7 @@ static inline void __netif_rx_schedule(struct net_device *dev) dev->quota += dev->weight; else dev->quota = dev->weight; - __cpu_raise_softirq(cpu, NET_RX_SOFTIRQ); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); local_irq_restore(flags); } @@ -805,7 +805,7 @@ static inline int netif_rx_reschedule(struct net_device *dev, int undo) local_irq_save(flags); cpu = smp_processor_id(); list_add_tail(&dev->poll_list, &softnet_data[cpu].poll_list); - __cpu_raise_softirq(cpu, NET_RX_SOFTIRQ); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); local_irq_restore(flags); return 1; } diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 3d752599853..a6d594bb252 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -240,7 +240,7 @@ extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *, struct nfs_fattr *); extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int nfs_permission(struct inode *, int); +extern int nfs_permission(struct inode *, int, struct nameidata *); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); diff --git a/include/linux/pci.h b/include/linux/pci.h index 3ceb5d7da82..a219c58ad88 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -543,7 +543,7 @@ void pcibios_update_irq(struct pci_dev *, int irq); /* Generic PCI functions used internally */ -int pci_bus_exists(const struct list_head *list, int nr); +extern struct pci_bus *pci_find_bus(int domain, int busnr); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 0e007ab6322..9cdf307268e 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -574,6 +574,7 @@ #define PCI_DEVICE_ID_SI_750 0x0750 #define PCI_DEVICE_ID_SI_751 0x0751 #define PCI_DEVICE_ID_SI_752 0x0752 +#define PCI_DEVICE_ID_SI_755 0x0755 #define PCI_DEVICE_ID_SI_900 0x0900 #define PCI_DEVICE_ID_SI_961 0x0961 #define PCI_DEVICE_ID_SI_962 0x0962 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index c0144a1ba4c..e2e54ee6186 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -92,7 +92,7 @@ extern struct proc_dir_entry *proc_root_kcore; extern void proc_root_init(void); extern void proc_misc_init(void); -struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry); +struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *); struct dentry *proc_pid_unhash(struct task_struct *p); void proc_pid_flush(struct dentry *proc_dentry); int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); @@ -115,7 +115,7 @@ extern int proc_match(int, const char *,struct proc_dir_entry *); * of the /proc/ subdirectories. */ extern int proc_readdir(struct file *, void *, filldir_t); -extern struct dentry *proc_lookup(struct inode *, struct dentry *); +extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *); extern struct file_operations proc_kcore_operations; extern struct file_operations proc_kmsg_operations; diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h index 5710620989d..53233c8fb3e 100644 --- a/include/linux/qnx4_fs.h +++ b/include/linux/qnx4_fs.h @@ -110,21 +110,20 @@ struct qnx4_inode_info { struct inode vfs_inode; }; -extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry); +extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); extern unsigned long qnx4_count_free_blocks(struct super_block *sb); extern unsigned long qnx4_block_map(struct inode *inode, long iblock); extern struct buffer_head *qnx4_getblk(struct inode *, int, int); extern struct buffer_head *qnx4_bread(struct inode *, int, int); -extern int qnx4_create(struct inode *dir, struct dentry *dentry, int mode); extern struct inode_operations qnx4_file_inode_operations; extern struct inode_operations qnx4_dir_inode_operations; extern struct file_operations qnx4_file_operations; extern struct file_operations qnx4_dir_operations; extern int qnx4_is_free(struct super_block *sb, long block); extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy); -extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode); +extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode, struct nameidata *nd); extern void qnx4_truncate(struct inode *inode); extern void qnx4_free_inode(struct inode *inode); extern int qnx4_unlink(struct inode *dir, struct dentry *dentry); diff --git a/include/linux/quota.h b/include/linux/quota.h index 77d017472dc..fbf2d2b2a5b 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -306,6 +306,16 @@ int register_quota_format(struct quota_format_type *fmt); void unregister_quota_format(struct quota_format_type *fmt); void init_dquot_operations(struct dquot_operations *fsdqops); +struct quota_module_name { + int qm_fmt_id; + char *qm_mod_name; +}; + +#define INIT_QUOTA_MODULE_NAMES {\ + {QFMT_VFS_OLD, "quota_v1"},\ + {QFMT_VFS_V0, "quota_v2"},\ + {0, NULL}} + #else # /* nodep */ include diff --git a/include/linux/sched.h b/include/linux/sched.h index 5fa14591c73..41edb1cac2b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -321,6 +321,8 @@ struct k_itimer { }; +struct io_context; /* See blkdev.h */ +void exit_io_context(void); struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ @@ -450,6 +452,8 @@ struct task_struct { struct dentry *proc_dentry; struct backing_dev_info *backing_dev_info; + struct io_context *io_context; + unsigned long ptrace_message; siginfo_t *last_siginfo; /* For ptrace use. */ }; @@ -481,6 +485,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_KSWAPD 0x00040000 /* I am kswapd */ #define PF_SWAPOFF 0x00080000 /* I am in swapoff */ #define PF_LESS_THROTTLE 0x01000000 /* Throttle me less: I clena memory */ +#define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ #ifdef CONFIG_SMP extern int set_cpus_allowed(task_t *p, unsigned long new_mask); diff --git a/include/linux/security.h b/include/linux/security.h index 9589f99c3ef..4d91dfc52c5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -49,6 +49,7 @@ extern int cap_bprm_secureexec(struct linux_binprm *bprm); extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); extern void cap_task_reparent_to_init (struct task_struct *p); extern int cap_syslog (int type); +extern int cap_vm_enough_memory (long pages); static inline int cap_netlink_send (struct sk_buff *skb) { @@ -958,6 +959,10 @@ struct swap_info_struct; * See the syslog(2) manual page for an explanation of the @type values. * @type contains the type of action. * Return 0 if permission is granted. + * @vm_enough_memory: + * Check permissions for allocating a new virtual mapping. + * @pages contains the number of pages. + * Return 0 if permission is granted. * * @register_security: * allow module stacking. @@ -989,6 +994,7 @@ struct security_operations { int (*quotactl) (int cmds, int type, int id, struct super_block * sb); int (*quota_on) (struct file * f); int (*syslog) (int type); + int (*vm_enough_memory) (long pages); int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); @@ -1238,6 +1244,11 @@ static inline int security_syslog(int type) return security_ops->syslog(type); } +static inline int security_vm_enough_memory(long pages) +{ + return security_ops->vm_enough_memory(pages); +} + static inline int security_bprm_alloc (struct linux_binprm *bprm) { return security_ops->bprm_alloc_security (bprm); @@ -1898,6 +1909,11 @@ static inline int security_syslog(int type) return cap_syslog(type); } +static inline int security_vm_enough_memory(long pages) +{ + return cap_vm_enough_memory(pages); +} + static inline int security_bprm_alloc (struct linux_binprm *bprm) { return 0; diff --git a/include/linux/sem.h b/include/linux/sem.h index 2821bc07f64..6e13e5efc16 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h @@ -109,7 +109,6 @@ struct sem_queue { int id; /* internal sem id */ struct sembuf * sops; /* array of pending operations */ int nsops; /* number of operations */ - int alter; /* operation will alter semaphore */ }; /* Each task has a list of undo requests. They are executed automatically diff --git a/include/linux/slab.h b/include/linux/slab.h index 843c8d638d2..d797c981f37 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -114,6 +114,10 @@ extern kmem_cache_t *signal_cachep; extern kmem_cache_t *sighand_cachep; extern kmem_cache_t *bio_cachep; +void ptrinfo(unsigned long addr); + +extern atomic_t slab_reclaim_pages; + #endif /* __KERNEL__ */ #endif /* _LINUX_SLAB_H */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index f054416c814..441c0d91f58 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -10,9 +10,11 @@ #define _SYSFS_H_ struct kobject; +struct module; struct attribute { char * name; + struct module * owner; mode_t mode; }; @@ -37,6 +39,9 @@ sysfs_create_dir(struct kobject *); extern void sysfs_remove_dir(struct kobject *); +extern void +sysfs_rename_dir(struct kobject *, char *new_name); + extern int sysfs_create_file(struct kobject *, struct attribute *); diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index 7034b7eb6b1..1c284c5a7ae 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -10,7 +10,7 @@ char * umsdos_d_path(struct dentry *, char *, int); void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *); int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo); -struct dentry *UMSDOS_lookup(struct inode *, struct dentry *); +struct dentry *UMSDOS_lookup(struct inode *, struct dentry *, struct nameidata *); struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); struct dentry *umsdos_covered(struct dentry *, char *, int); @@ -92,7 +92,7 @@ int UMSDOS_rename (struct inode *old_dir, /* rdir.c 22/03/95 03.31.42 */ struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo); -struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry); +struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry, struct nameidata *nd); static inline struct umsdos_inode_info *UMSDOS_I(struct inode *inode) { diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 45de6f510fc..d660c5f97c5 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -119,7 +119,9 @@ enum #define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9) #define XFRM_MSG_UPDSA (XFRM_MSG_BASE + 10) -#define XFRM_MSG_MAX (XFRM_MSG_UPDSA+1) +#define XFRM_MSG_POLEXPIRE (XFRM_MSG_BASE + 11) + +#define XFRM_MSG_MAX (XFRM_MSG_POLEXPIRE+1) struct xfrm_user_tmpl { struct xfrm_id id; @@ -217,6 +219,11 @@ struct xfrm_user_expire { __u8 hard; }; +struct xfrm_user_polexpire { + struct xfrm_userpolicy_info pol; + __u8 hard; +}; + #define XFRMGRP_ACQUIRE 1 #define XFRMGRP_EXPIRE 2 diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 6c653f98fca..2537a6fc4bc 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -6,6 +6,8 @@ #define MAX_RTR_SOLICITATIONS 3 #define RTR_SOLICITATION_INTERVAL (4*HZ) +#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ + #define TEMP_VALID_LIFETIME (7*86400) #define TEMP_PREFERRED_LIFETIME (86400) #define REGEN_MAX_RETRY (5) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8c11fb6a036..5c6546accda 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -276,8 +276,10 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx, b = plen & 0x7; memcpy(pfx->s6_addr, addr, o); - if (b != 0) + if (b != 0) { pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); + o++; + } if (o < 16) memset(pfx->s6_addr + o, 0, 16 - o); } diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index eca2baddbc2..4c9ed3ad418 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -61,7 +61,7 @@ struct Qdisc_ops int (*enqueue)(struct sk_buff *, struct Qdisc *); struct sk_buff * (*dequeue)(struct Qdisc *); int (*requeue)(struct sk_buff *, struct Qdisc *); - int (*drop)(struct Qdisc *); + unsigned int (*drop)(struct Qdisc *); int (*init)(struct Qdisc *, struct rtattr *arg); void (*reset)(struct Qdisc *); diff --git a/include/net/tcp.h b/include/net/tcp.h index 2a189df12a8..d4e9c07f86d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -628,13 +628,6 @@ static inline void tcp_openreq_free(struct open_request *req) /* * Pointers to address related TCP functions * (i.e. things that depend on the address family) - * - * BUGGG_FUTURE: all the idea behind this struct is wrong. - * It mixes socket frontend with transport function. - * With port sharing between IPv6/v4 it gives the only advantage, - * only poor IPv6 needs to permanently recheck, that it - * is still IPv6 8)8) It must be cleaned up as soon as possible. - * --ANK (980802) */ struct tcp_func { diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 515f8890960..4cb71a1e031 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -287,6 +287,8 @@ struct xfrm_policy struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; }; +#define XFRM_KM_TIMEOUT 30 + struct xfrm_mgr { struct list_head list; @@ -295,6 +297,7 @@ struct xfrm_mgr int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); + int (*notify_policy)(struct xfrm_policy *x, int dir, int event); }; extern int xfrm_register_km(struct xfrm_mgr *km); @@ -635,16 +638,16 @@ static inline int xfrm_sk_clone_policy(struct sock *sk) return 0; } -extern void __xfrm_sk_free_policy(struct xfrm_policy *, int dir); +extern void xfrm_policy_delete(struct xfrm_policy *pol, int dir); static inline void xfrm_sk_free_policy(struct sock *sk) { if (unlikely(sk->sk_policy[0] != NULL)) { - __xfrm_sk_free_policy(sk->sk_policy[0], 0); + xfrm_policy_delete(sk->sk_policy[0], XFRM_POLICY_MAX); sk->sk_policy[0] = NULL; } if (unlikely(sk->sk_policy[1] != NULL)) { - __xfrm_sk_free_policy(sk->sk_policy[1], 1); + xfrm_policy_delete(sk->sk_policy[1], XFRM_POLICY_MAX+1); sk->sk_policy[1] = NULL; } } @@ -809,10 +812,10 @@ extern int xfrm_flush_bundles(struct xfrm_state *x); extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family); extern wait_queue_head_t km_waitq; -extern void km_warn_expired(struct xfrm_state *x); -extern void km_expired(struct xfrm_state *x); +extern void km_state_expired(struct xfrm_state *x, int hard); extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol); extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); +extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard); extern void xfrm4_input_init(void); extern void xfrm6_input_init(void); diff --git a/init/Kconfig b/init/Kconfig index d3a9874335a..ab6212b4820 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -93,7 +93,8 @@ config SYSCTL limited in memory. config LOG_BUF_SHIFT - int "Kernel log buffer size" if DEBUG_KERNEL + int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL + range 12 20 default 17 if ARCH_S390 default 16 if X86_NUMAQ || IA64 default 15 if SMP diff --git a/ipc/sem.c b/ipc/sem.c index 07d9a2e054b..d1a54864f75 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -49,6 +49,10 @@ * increase. If there are decrement operations in the operations * array we do the same as before. * + * With the incarnation of O(1) scheduler, it becomes unnecessary to perform + * check/retry algorithm for waking up blocked processes as the new scheduler + * is better at handling thread switch than the old one. + * * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie * * SMP-threaded, sysctl's added @@ -258,8 +262,7 @@ static inline void remove_from_queue (struct sem_array * sma, */ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, - int nsops, struct sem_undo *un, int pid, - int do_undo) + int nsops, struct sem_undo *un, int pid) { int result, sem_op; struct sembuf *sop; @@ -289,10 +292,6 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops, curr->semval = result; } - if (do_undo) { - result = 0; - goto undo; - } sop--; while (sop >= sops) { sma->sem_base[sop->sem_num].sempid = pid; @@ -334,23 +333,14 @@ static void update_queue (struct sem_array * sma) for (q = sma->sem_pending; q; q = q->next) { - if (q->status == 1) - continue; /* this one was woken up before */ - error = try_atomic_semop(sma, q->sops, q->nsops, - q->undo, q->pid, q->alter); + q->undo, q->pid); /* Does q->sleeper still need to sleep? */ if (error <= 0) { - /* Found one, wake it up */ - wake_up_process(q->sleeper); - if (error == 0 && q->alter) { - /* if q-> alter let it self try */ - q->status = 1; - return; - } q->status = error; remove_from_queue(sma,q); + wake_up_process(q->sleeper); } } } @@ -1062,7 +1052,7 @@ retry_undos: if (error) goto out_unlock_free; - error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0); + error = try_atomic_semop (sma, sops, nsops, un, current->pid); if (error <= 0) goto update; @@ -1075,55 +1065,46 @@ retry_undos: queue.nsops = nsops; queue.undo = un; queue.pid = current->pid; - queue.alter = decrease; queue.id = semid; if (alter) append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); - for (;;) { - queue.status = -EINTR; - queue.sleeper = current; - current->state = TASK_INTERRUPTIBLE; - sem_unlock(sma); + queue.status = -EINTR; + queue.sleeper = current; + current->state = TASK_INTERRUPTIBLE; + sem_unlock(sma); - if (timeout) - jiffies_left = schedule_timeout(jiffies_left); - else - schedule(); + if (timeout) + jiffies_left = schedule_timeout(jiffies_left); + else + schedule(); - sma = sem_lock(semid); - if(sma==NULL) { - if(queue.prev != NULL) - BUG(); - error = -EIDRM; - goto out_free; - } - /* - * If queue.status == 1 we where woken up and - * have to retry else we simply return. - * If an interrupt occurred we have to clean up the - * queue - * - */ - if (queue.status == 1) - { - error = try_atomic_semop (sma, sops, nsops, un, - current->pid,0); - if (error <= 0) - break; - } else { - error = queue.status; - if (error == -EINTR && timeout && jiffies_left == 0) - error = -EAGAIN; - if (queue.prev) /* got Interrupt */ - break; - /* Everything done by update_queue */ - goto out_unlock_free; - } + sma = sem_lock(semid); + if(sma==NULL) { + if(queue.prev != NULL) + BUG(); + error = -EIDRM; + goto out_free; + } + + /* + * If queue.status != -EINTR we are woken up by another process + */ + error = queue.status; + if (queue.status != -EINTR) { + goto out_unlock_free; } + + /* + * If an interrupt occurred we have to clean up the queue + */ + if (timeout && jiffies_left == 0) + error = -EAGAIN; remove_from_queue(sma,&queue); + goto out_unlock_free; + update: if (alter) update_queue (sma); diff --git a/kernel/acct.c b/kernel/acct.c index e63095525ac..0009dfb25dc 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -394,17 +394,25 @@ static void do_acct_process(long exitcode, struct file *file) /* * acct_process - now just a wrapper around do_acct_process */ -int acct_process(long exitcode) +void acct_process(long exitcode) { struct file *file = NULL; + + /* + * accelerate the common fastpath: + */ + if (!acct_globals.file) + return; + spin_lock(&acct_globals.lock); - if (acct_globals.file) { - file = acct_globals.file; - get_file(file); + file = acct_globals.file; + if (unlikely(!file)) { spin_unlock(&acct_globals.lock); - do_acct_process(exitcode, file); - fput(file); - } else - spin_unlock(&acct_globals.lock); - return 0; + return; + } + get_file(file); + spin_unlock(&acct_globals.lock); + + do_acct_process(exitcode, file); + fput(file); } diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c index 6ae2b821830..f4864ce54aa 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -23,6 +23,7 @@ #include #include #include +#include /** * The "cpufreq driver" - the arch- or hardware-dependend low @@ -297,6 +298,12 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, return ret; } +static void cpufreq_sysfs_release(struct kobject * kobj) +{ + struct cpufreq_policy * policy = to_policy(kobj); + complete(&policy->kobj_unregister); +} + static struct sysfs_ops sysfs_ops = { .show = show, .store = store, @@ -305,6 +312,7 @@ static struct sysfs_ops sysfs_ops = { static struct kobj_type ktype_cpufreq = { .sysfs_ops = &sysfs_ops, .default_attrs = default_attrs, + .release = cpufreq_sysfs_release, }; @@ -329,11 +337,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) */ policy = &cpufreq_driver->policy[cpu]; policy->cpu = cpu; - if (cpufreq_driver->init) { - ret = cpufreq_driver->init(policy); - if (ret) - goto out; - } + ret = cpufreq_driver->init(policy); + if (ret) + goto out; /* set default policy on this CPU */ down(&cpufreq_driver_sem); @@ -343,6 +349,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) up(&cpufreq_driver_sem); init_MUTEX(&policy->lock); + init_completion(&policy->kobj_unregister); + /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; @@ -352,18 +360,19 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) if (ret) goto out; + /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; while ((drv_attr) && (*drv_attr)) { sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); drv_attr++; } - /* set up files for this cpu device */ - /* set default policy */ ret = cpufreq_set_policy(&new_policy); - if (ret) + if (ret) { kobject_unregister(&policy->kobj); + wait_for_completion(&policy->kobj_unregister); + } out: module_put(cpufreq_driver->owner); @@ -401,10 +410,39 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) up(&cpufreq_driver_sem); kobject_put(&cpufreq_driver->policy[cpu].kobj); + + /* we need to make sure that the underlying kobj is actually + * destroyed before we proceed e.g. with cpufreq driver module + * unloading + */ + wait_for_completion(&cpufreq_driver->policy[cpu].kobj_unregister); + return 0; } -static int cpufreq_restore(struct sys_device *); +/** + * cpufreq_restore - restore the CPU clock frequency after resume + * + * Restore the CPU clock frequency so that our idea of the current + * frequency reflects the actual hardware. + */ +static int cpufreq_restore(struct sys_device * sysdev) +{ + int cpu = sysdev->id; + unsigned int ret = 0; + struct cpufreq_policy policy; + + if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) { + down(&cpufreq_driver_sem); + memcpy(&policy, &cpufreq_driver->policy[cpu], + sizeof(struct cpufreq_policy)); + up(&cpufreq_driver_sem); + ret = cpufreq_set_policy(&policy); + cpufreq_cpu_put(cpu); + } + + return ret; +} static struct sysdev_driver cpufreq_sysdev_driver = { .add = cpufreq_add_dev, @@ -587,33 +625,10 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor); void cpufreq_unregister_governor(struct cpufreq_governor *governor) { - unsigned int i; - if (!governor) return; down(&cpufreq_governor_sem); - - /* - * Unless the user uses rmmod -f, we can be safe. But we never - * know, so check whether if it's currently used. If so, - * stop it and replace it with the default governor. - */ - for (i=0; ipolicy[i].policy == CPUFREQ_POLICY_GOVERNOR) && - (cpufreq_driver->policy[i].governor == governor)) { - cpufreq_governor(i, CPUFREQ_GOV_STOP); - cpufreq_driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE; - cpufreq_governor(i, CPUFREQ_GOV_START); - cpufreq_governor(i, CPUFREQ_GOV_LIMITS); - } - cpufreq_cpu_put(i); - } - - /* now we can safely remove it from the list */ list_del(&governor->governor_list); up(&cpufreq_governor_sem); return; @@ -781,7 +796,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) switch (state) { case CPUFREQ_PRECHANGE: notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); - adjust_jiffies(CPUFREQ_PRECHANGE, freqs); + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); @@ -859,37 +874,3 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) return 0; } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); - - -#ifdef CONFIG_PM - -/** - * cpufreq_restore - restore the CPU clock frequency after resume - * - * Restore the CPU clock frequency so that our idea of the current - * frequency reflects the actual hardware. - */ -static int cpufreq_restore(struct sys_device * sysdev) -{ - int cpu = sysdev->id; - unsigned int ret = 0; - struct cpufreq_policy policy; - - if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) { - down(&cpufreq_driver_sem); - memcpy(&policy, &cpufreq_driver->policy[cpu], - sizeof(struct cpufreq_policy)); - up(&cpufreq_driver_sem); - ret = cpufreq_set_policy(&policy); - cpufreq_cpu_put(cpu); - } - - return ret; -} - -#else -static int cpufreq_restore(struct sys_device * sysdev) -{ - return 0; -} -#endif /* CONFIG_PM */ diff --git a/kernel/exit.c b/kernel/exit.c index 367854d246e..7792bb1268f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -230,6 +230,7 @@ void reparent_to_init(void) /* signals? */ security_task_reparent_to_init(current); memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim))); + atomic_inc(&(INIT_USER->__count)); switch_uid(INIT_USER); write_unlock_irq(&tasklist_lock); @@ -442,7 +443,7 @@ static inline void __exit_mm(struct task_struct * tsk) /* more a memory barrier than a real lock */ task_lock(tsk); tsk->mm = NULL; - enter_lazy_tlb(mm, current, smp_processor_id()); + enter_lazy_tlb(mm, current); task_unlock(tsk); mmput(mm); } @@ -651,6 +652,8 @@ static void exit_notify(struct task_struct *tsk) if (tsk->exit_signal != -1) { int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD; do_notify_parent(tsk, signal); + } else if (tsk->ptrace) { + do_notify_parent(tsk, SIGCHLD); } tsk->state = TASK_ZOMBIE; @@ -680,6 +683,8 @@ NORET_TYPE void do_exit(long code) panic("Attempted to kill the idle task!"); if (unlikely(tsk->pid == 1)) panic("Attempted to kill init!"); + if (tsk->io_context) + exit_io_context(); tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); @@ -715,7 +720,7 @@ NORET_TYPE void do_exit(long code) tsk->exit_code = code; exit_notify(tsk); - if (tsk->exit_signal == -1) + if (tsk->exit_signal == -1 && tsk->ptrace == 0) release_task(tsk); schedule(); @@ -859,7 +864,7 @@ static int wait_task_zombie(task_t *p, unsigned int *stat_addr, struct rusage *r BUG_ON(state != TASK_DEAD); return 0; } - if (unlikely(p->exit_signal == -1)) + if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) /* * This can only happen in a race with a ptraced thread * dying on another processor. @@ -889,8 +894,12 @@ static int wait_task_zombie(task_t *p, unsigned int *stat_addr, struct rusage *r /* Double-check with lock held. */ if (p->real_parent != p->parent) { __ptrace_unlink(p); - do_notify_parent(p, p->exit_signal); p->state = TASK_ZOMBIE; + /* If this is a detached thread, this is where it goes away. */ + if (p->exit_signal == -1) + release_task (p); + else + do_notify_parent(p, p->exit_signal); p = NULL; } write_unlock_irq(&tasklist_lock); diff --git a/kernel/fork.c b/kernel/fork.c index 2abbc9c2da2..96ce3385cc7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -286,7 +286,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) continue; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - if (!vm_enough_memory(len)) + if (security_vm_enough_memory(len)) goto fail_nomem; charge += len; } @@ -864,6 +864,7 @@ struct task_struct *copy_process(unsigned long clone_flags, p->lock_depth = -1; /* -1 = no lock */ p->start_time = get_jiffies_64(); p->security = NULL; + p->io_context = NULL; retval = -ENOMEM; if ((retval = security_task_alloc(p))) diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 8544287c904..66ea4b6b4d8 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -462,6 +462,7 @@ EXPORT_SYMBOL(preempt_schedule); #endif EXPORT_SYMBOL(schedule_timeout); EXPORT_SYMBOL(yield); +EXPORT_SYMBOL(io_schedule); EXPORT_SYMBOL(__cond_resched); EXPORT_SYMBOL(set_user_nice); EXPORT_SYMBOL(task_nice); @@ -586,7 +587,7 @@ EXPORT_SYMBOL(tasklet_kill); EXPORT_SYMBOL(do_softirq); EXPORT_SYMBOL(raise_softirq); EXPORT_SYMBOL(open_softirq); -EXPORT_SYMBOL(cpu_raise_softirq); +EXPORT_SYMBOL(raise_softirq_irqoff); EXPORT_SYMBOL(__tasklet_schedule); EXPORT_SYMBOL(__tasklet_hi_schedule); diff --git a/kernel/sched.c b/kernel/sched.c index bb552059577..556c5cdbb9c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -508,8 +508,8 @@ repeat_lock_task: } #ifdef CONFIG_SMP else - if (unlikely(kick) && task_running(rq, p) && (p->thread_info->cpu != smp_processor_id())) - smp_send_reschedule(p->thread_info->cpu); + if (unlikely(kick) && task_running(rq, p) && (task_cpu(p) != smp_processor_id())) + smp_send_reschedule(task_cpu(p)); #endif p->state = TASK_RUNNING; } @@ -646,9 +646,9 @@ static inline task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next if (unlikely(!mm)) { next->active_mm = oldmm; atomic_inc(&oldmm->mm_count); - enter_lazy_tlb(oldmm, next, smp_processor_id()); + enter_lazy_tlb(oldmm, next); } else - switch_mm(oldmm, mm, next, smp_processor_id()); + switch_mm(oldmm, mm, next); if (unlikely(!prev->mm)) { prev->active_mm = NULL; @@ -1175,6 +1175,7 @@ DEFINE_PER_CPU(struct kernel_stat, kstat) = { { 0 } }; void scheduler_tick(int user_ticks, int sys_ticks) { int cpu = smp_processor_id(); + struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; runqueue_t *rq = this_rq(); task_t *p = current; @@ -1184,19 +1185,19 @@ void scheduler_tick(int user_ticks, int sys_ticks) if (p == rq->idle) { /* note: this timer irq context must be accounted for as well */ if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET) - kstat_cpu(cpu).cpustat.system += sys_ticks; + cpustat->system += sys_ticks; else if (atomic_read(&rq->nr_iowait) > 0) - kstat_cpu(cpu).cpustat.iowait += sys_ticks; + cpustat->iowait += sys_ticks; else - kstat_cpu(cpu).cpustat.idle += sys_ticks; + cpustat->idle += sys_ticks; rebalance_tick(rq, 1); return; } if (TASK_NICE(p) > 0) - kstat_cpu(cpu).cpustat.nice += user_ticks; + cpustat->nice += user_ticks; else - kstat_cpu(cpu).cpustat.user += user_ticks; - kstat_cpu(cpu).cpustat.system += sys_ticks; + cpustat->user += user_ticks; + cpustat->system += sys_ticks; /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { @@ -1332,7 +1333,7 @@ pick_next_task: switch_tasks: prefetch(next); clear_tsk_need_resched(prev); - RCU_qsctr(prev->thread_info->cpu)++; + RCU_qsctr(task_cpu(prev))++; if (likely(prev != next)) { rq->nr_switches++; @@ -2527,7 +2528,7 @@ void __init sched_init(void) * The boot idle thread does lazy MMU switching as well: */ atomic_inc(&init_mm.mm_count); - enter_lazy_tlb(&init_mm, current, smp_processor_id()); + enter_lazy_tlb(&init_mm, current); } #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP diff --git a/kernel/signal.c b/kernel/signal.c index 78c4dfa0073..7ac72191b30 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -579,8 +579,8 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) /* * Bad permissions for sending the signal */ -static inline int check_kill_permission(int sig, struct siginfo *info, - struct task_struct *t) +static int check_kill_permission(int sig, struct siginfo *info, + struct task_struct *t) { int error = -EINVAL; if (sig < 0 || sig > _NSIG) @@ -797,10 +797,11 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) int ret; spin_lock_irqsave(&t->sighand->siglock, flags); - if (t->sighand->action[sig-1].sa.sa_handler == SIG_IGN) + if (sigismember(&t->blocked, sig) || t->sighand->action[sig-1].sa.sa_handler == SIG_IGN) { t->sighand->action[sig-1].sa.sa_handler = SIG_DFL; - sigdelset(&t->blocked, sig); - recalc_sigpending_tsk(t); + sigdelset(&t->blocked, sig); + recalc_sigpending_tsk(t); + } ret = specific_send_sig_info(sig, info, t); spin_unlock_irqrestore(&t->sighand->siglock, flags); @@ -2081,12 +2082,58 @@ sys_kill(int pid, int sig) info.si_signo = sig; info.si_errno = 0; info.si_code = SI_USER; - info.si_pid = current->pid; + info.si_pid = current->tgid; info.si_uid = current->uid; return kill_something_info(sig, &info, pid); } +/** + * sys_tkill - send signal to one specific thread + * @tgid: the thread group ID of the thread + * @pid: the PID of the thread + * @sig: signal to be sent + * + * This syscall also checks the tgid and returns -ESRCH even if the PID + * exists but it's not belonging to the target process anymore. This + * method solves the problem of threads exiting and PIDs getting reused. + */ +asmlinkage long sys_tgkill(int tgid, int pid, int sig) +{ + struct siginfo info; + int error; + struct task_struct *p; + + /* This is only valid for single tasks */ + if (pid <= 0 || tgid <= 0) + return -EINVAL; + + info.si_signo = sig; + info.si_errno = 0; + info.si_code = SI_TKILL; + info.si_pid = current->tgid; + info.si_uid = current->uid; + + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + error = -ESRCH; + if (p && (p->tgid == tgid)) { + error = check_kill_permission(sig, &info, p); + /* + * The null signal is a permissions and process existence + * probe. No signal is actually delivered. + */ + if (!error && sig && p->sighand) { + spin_lock_irq(&p->sighand->siglock); + handle_stop_signal(sig, p); + error = specific_send_sig_info(sig, &info, p); + spin_unlock_irq(&p->sighand->siglock); + } + } + read_unlock(&tasklist_lock); + return error; +} + /* * Send a signal to only one task, even if it's a CLONE_THREAD task. */ @@ -2104,7 +2151,7 @@ sys_tkill(int pid, int sig) info.si_signo = sig; info.si_errno = 0; info.si_code = SI_TKILL; - info.si_pid = current->pid; + info.si_pid = current->tgid; info.si_uid = current->uid; read_lock(&tasklist_lock); diff --git a/kernel/softirq.c b/kernel/softirq.c index 20bf233a14c..96294a3d673 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -14,6 +14,7 @@ #include #include #include +#include #include /* @@ -41,15 +42,18 @@ EXPORT_SYMBOL(irq_stat); static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp; +static DEFINE_PER_CPU(struct task_struct *, ksoftirqd); + /* * we cannot loop indefinitely here to avoid userspace starvation, * but we also don't want to introduce a worst case 1/HZ latency * to the pending events, so lets the scheduler to balance * the softirq load for us. */ -static inline void wakeup_softirqd(unsigned cpu) +static inline void wakeup_softirqd(void) { - struct task_struct * tsk = ksoftirqd_task(cpu); + /* Interrupts are disabled: no need to stop preemption */ + struct task_struct *tsk = __get_cpu_var(ksoftirqd); if (tsk && tsk->state != TASK_RUNNING) wake_up_process(tsk); @@ -96,7 +100,7 @@ restart: goto restart; } if (pending) - wakeup_softirqd(smp_processor_id()); + wakeup_softirqd(); __local_bh_enable(); } @@ -117,9 +121,9 @@ EXPORT_SYMBOL(local_bh_enable); /* * This function must run with irqs disabled! */ -inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) +inline void raise_softirq_irqoff(unsigned int nr) { - __cpu_raise_softirq(cpu, nr); + __raise_softirq_irqoff(nr); /* * If we're in an interrupt or softirq, we're done @@ -131,7 +135,7 @@ inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) * schedule the softirq soon. */ if (!in_interrupt()) - wakeup_softirqd(cpu); + wakeup_softirqd(); } void raise_softirq(unsigned int nr) @@ -139,7 +143,7 @@ void raise_softirq(unsigned int nr) unsigned long flags; local_irq_save(flags); - cpu_raise_softirq(smp_processor_id(), nr); + raise_softirq_irqoff(nr); local_irq_restore(flags); } @@ -168,7 +172,7 @@ void __tasklet_schedule(struct tasklet_struct *t) local_irq_save(flags); t->next = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; - cpu_raise_softirq(smp_processor_id(), TASKLET_SOFTIRQ); + raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_restore(flags); } @@ -179,7 +183,7 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) local_irq_save(flags); t->next = __get_cpu_var(tasklet_hi_vec).list; __get_cpu_var(tasklet_hi_vec).list = t; - cpu_raise_softirq(smp_processor_id(), HI_SOFTIRQ); + raise_softirq_irqoff(HI_SOFTIRQ); local_irq_restore(flags); } @@ -211,7 +215,7 @@ static void tasklet_action(struct softirq_action *a) local_irq_disable(); t->next = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; - __cpu_raise_softirq(smp_processor_id(), TASKLET_SOFTIRQ); + __raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_enable(); } } @@ -244,7 +248,7 @@ static void tasklet_hi_action(struct softirq_action *a) local_irq_disable(); t->next = __get_cpu_var(tasklet_hi_vec).list; __get_cpu_var(tasklet_hi_vec).list = t; - __cpu_raise_softirq(smp_processor_id(), HI_SOFTIRQ); + __raise_softirq_irqoff(HI_SOFTIRQ); local_irq_enable(); } } @@ -325,7 +329,7 @@ static int ksoftirqd(void * __bind_cpu) __set_current_state(TASK_INTERRUPTIBLE); mb(); - local_ksoftirqd_task() = current; + __get_cpu_var(ksoftirqd) = current; for (;;) { if (!local_softirq_pending()) @@ -354,7 +358,7 @@ static int __devinit cpu_callback(struct notifier_block *nfb, return NOTIFY_BAD; } - while (!ksoftirqd_task(hotcpu)) + while (!per_cpu(ksoftirqd, hotcpu)) yield(); } return NOTIFY_OK; diff --git a/kernel/suspend.c b/kernel/suspend.c index 843cbaf6d43..308735894ac 100644 --- a/kernel/suspend.c +++ b/kernel/suspend.c @@ -692,7 +692,6 @@ static int suspend_prepare_image(void) printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages short\n", name_suspend, nr_needed_pages-nr_free_pages()); root_swap = 0xFFFF; - spin_unlock_irq(&suspend_pagedir_lock); return 1; } si_swapinfo(&i); /* FIXME: si_swapinfo(&i) returns all swap devices information. @@ -700,7 +699,6 @@ static int suspend_prepare_image(void) if (i.freeswap < nr_needed_pages) { printk(KERN_CRIT "%sThere's not enough swap space available, on %ld pages short\n", name_suspend, nr_needed_pages-i.freeswap); - spin_unlock_irq(&suspend_pagedir_lock); return 1; } @@ -710,7 +708,6 @@ static int suspend_prepare_image(void) /* Shouldn't happen */ printk(KERN_CRIT "%sCouldn't allocate enough pages\n",name_suspend); panic("Really should not happen"); - spin_unlock_irq(&suspend_pagedir_lock); return 1; } nr_copy_pages_check = nr_copy_pages; @@ -724,12 +721,9 @@ static int suspend_prepare_image(void) * End of critical section. From now on, we can write to memory, * but we should not touch disk. This specially means we must _not_ * touch swap space! Except we must write out our image of course. - * - * Following line enforces not writing to disk until we choose. */ printk( "critical section/: done (%d pages copied)\n", nr_copy_pages ); - spin_unlock_irq(&suspend_pagedir_lock); return 0; } @@ -808,6 +802,24 @@ void do_magic_resume_2(void) #endif } +/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically does: + + if (!resume) { + do_magic_suspend_1(); + save_processor_state(); + SAVE_REGISTERS + do_magic_suspend_2(); + return; + } + GO_TO_SWAPPER_PAGE_TABLES + do_magic_resume_1(); + COPY_PAGES_BACK + RESTORE_REGISTERS + restore_processor_state(); + do_magic_resume_2(); + + */ + void do_magic_suspend_1(void) { mb(); @@ -818,8 +830,13 @@ void do_magic_suspend_1(void) void do_magic_suspend_2(void) { + int is_problem; read_swapfiles(); - if (!suspend_prepare_image()) { /* suspend_save_image realeses suspend_pagedir_lock */ + is_problem = suspend_prepare_image(); + spin_unlock_irq(&suspend_pagedir_lock); + if (!is_problem) { + kernel_fpu_end(); /* save_processor_state() does kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks */ + BUG_ON(in_atomic()); suspend_save_image(); suspend_power_down(); /* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */ } @@ -1203,12 +1220,12 @@ static int read_suspend_image(const char * specialfile, int noresume) void software_resume(void) { -#ifdef CONFIG_SMP - printk(KERN_WARNING "Software Suspend has a malfunctioning SMP support. Disabled :(\n"); -#else + if (num_online_cpus() > 1) { + printk(KERN_WARNING "Software Suspend has malfunctioning SMP support. Disabled :(\n"); + return; + } /* We enable the possibility of machine suspend */ software_suspend_enabled = 1; -#endif if (!resume_status) return; @@ -1224,13 +1241,13 @@ void software_resume(void) orig_loglevel = console_loglevel; console_loglevel = new_loglevel; - if(!resume_file[0] && resume_status == RESUME_SPECIFIED) { + if (!resume_file[0] && resume_status == RESUME_SPECIFIED) { printk( "suspension device unspecified\n" ); return; } printk( "resuming from %s\n", resume_file); - if(read_suspend_image(resume_file, 0)) + if (read_suspend_image(resume_file, 0)) goto read_failure; do_magic(1); panic("This never returns"); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 7f0cc00cfa4..edebad7ddec 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -130,7 +130,7 @@ extern ctl_table random_table[]; static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); -static int proc_sys_permission(struct inode *, int); +static int proc_sys_permission(struct inode *, int, struct nameidata *); struct file_operations proc_sys_file_operations = { .read = proc_readsys, @@ -1177,7 +1177,7 @@ static ssize_t proc_writesys(struct file * file, const char __user * buf, return do_rw_proc(1, file, (char __user *) buf, count, ppos); } -static int proc_sys_permission(struct inode *inode, int op) +static int proc_sys_permission(struct inode *inode, int op, struct nameidata *nd) { return test_perm(inode->i_mode, op); } diff --git a/kernel/timer.c b/kernel/timer.c index 7bce7a7cb2c..3995425e44a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -126,13 +126,17 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer) * or you set a timer to go off in the past */ vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK); - } else if (idx <= 0xffffffffUL) { - int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; - vec = base->tv5.vec + i; } else { - /* Can only get here on architectures with 64-bit jiffies */ - INIT_LIST_HEAD(&timer->entry); - return; + int i; + /* If the timeout is larger than 0xffffffff on 64-bit + * architectures then we use the maximum timeout: + */ + if (idx > 0xffffffffUL) { + idx = 0xffffffffUL; + expires = idx + base->timer_jiffies; + } + i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; + vec = base->tv5.vec + i; } /* * Timers are FIFO: diff --git a/kernel/user.c b/kernel/user.c index 592680d8cc6..86bd412b85d 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -126,7 +126,6 @@ void switch_uid(struct user_struct *new_user) * we should be checking for it. -DaveM */ old_user = current->user; - atomic_inc(&new_user->__count); atomic_inc(&new_user->processes); atomic_dec(&old_user->processes); current->user = new_user; diff --git a/lib/Makefile b/lib/Makefile index 9121869155a..91e7b30d3ca 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ - kobject.o idr.o + kobject.o idr.o div64.o lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o diff --git a/lib/div64.c b/lib/div64.c new file mode 100644 index 00000000000..d8c699e1f70 --- /dev/null +++ b/lib/div64.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Bernardo Innocenti + * + * Based on former do_div() implementation from asm-parisc/div64.h: + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * + * + * Generic C version of 64bit/32bit division and modulo, with + * 64bit result and 32bit remainder. + * + * The fast case for (n>>32 == 0) is handled inline by do_div(). + * + * Code generated for this function might be very inefficient + * for some CPUs. __div64_32() can be overridden by linking arch-specific + * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. + */ + +#include +#include +#include + +/* Not needed on 64bit architectures */ +#if BITS_PER_LONG == 32 + +uint32_t __div64_32(uint64_t *n, uint32_t base) +{ + uint32_t low, low2, high, rem; + + low = *n & 0xffffffff; + high = *n >> 32; + rem = high % (uint32_t)base; + high = high / (uint32_t)base; + low2 = low >> 16; + low2 += rem << 16; + rem = low2 % (uint32_t)base; + low2 = low2 / (uint32_t)base; + low = low & 0xffff; + low += rem << 16; + rem = low % (uint32_t)base; + low = low / (uint32_t)base; + + *n = low + + ((uint64_t)low2 << 16) + + ((uint64_t)high << 32); + + return rem; +} + +EXPORT_SYMBOL(__div64_32); + +#endif /* BITS_PER_LONG == 32 */ diff --git a/lib/kobject.c b/lib/kobject.c index fb49131f5ff..15fa0ba4dd8 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -314,6 +314,21 @@ int kobject_register(struct kobject * kobj) } /** + * kobject_rename - change the name of an object + * @kobj: object in question. + * @new_name: object's new name + */ + +void kobject_rename(struct kobject * kobj, char *new_name) +{ + kobj = kobject_get(kobj); + if (!kobj) + return; + sysfs_rename_dir(kobj, new_name); + kobject_put(kobj); +} + +/** * kobject_del - unlink kobject from hierarchy. * @kobj: object. */ diff --git a/mm/bootmem.c b/mm/bootmem.c index db4aff37a1a..48f286bb780 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -84,10 +84,6 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add if (!size) BUG(); - if (sidx < 0) - BUG(); - if (eidx < 0) - BUG(); if (sidx >= eidx) BUG(); if ((addr >> PAGE_SHIFT) >= bdata->node_low_pfn) @@ -202,7 +198,7 @@ restart_scan: ; } - if (preferred) { + if (preferred > offset) { preferred = offset; goto restart_scan; } diff --git a/mm/filemap.c b/mm/filemap.c index 1352d59d2ee..f9623a9fecc 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -925,6 +925,9 @@ static int page_cache_read(struct file * file, unsigned long offset) return error == -EEXIST ? 0 : error; } +#define MMAP_READAROUND (16UL) +#define MMAP_LOTSAMISS (100) + /* * filemap_nopage() is invoked via the vma operations vector for a * mapped memory region to read in file data during a page fault. @@ -942,19 +945,19 @@ struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address struct inode *inode = mapping->host; struct page *page; unsigned long size, pgoff, endoff; - int did_readahead; + int did_readaround = 0; pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; retry_all: - /* - * An external ptracer can access pages that normally aren't - * accessible.. - */ size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; - if ((pgoff >= size) && (area->vm_mm == current->mm)) - return NULL; + if (pgoff >= size) + goto outside_data_content; + + /* If we don't want any read-ahead, don't bother */ + if (VM_RandomReadHint(area)) + goto no_cached_page; /* * The "size" of the file, as far as mmap is concerned, isn't bigger @@ -963,25 +966,14 @@ retry_all: if (size > endoff) size = endoff; - did_readahead = 0; - /* * The readahead code wants to be told about each and every page * so it can build and shrink its windows appropriately + * + * For sequential accesses, we use the generic readahead logic. */ - if (VM_SequentialReadHint(area)) { - did_readahead = 1; + if (VM_SequentialReadHint(area)) page_cache_readahead(mapping, ra, file, pgoff); - } - - /* - * If the offset is outside the mapping size we're off the end - * of a privately mapped file, so we need to map a zero page. - */ - if ((pgoff < size) && !VM_RandomReadHint(area)) { - did_readahead = 1; - page_cache_readaround(mapping, ra, file, pgoff); - } /* * Do we have something in the page cache already? @@ -989,13 +981,27 @@ retry_all: retry_find: page = find_get_page(mapping, pgoff); if (!page) { - if (did_readahead) { + if (VM_SequentialReadHint(area)) { handle_ra_miss(mapping, ra, pgoff); - did_readahead = 0; + goto no_cached_page; } - goto no_cached_page; + ra->mmap_miss++; + + /* + * Do we miss much more than hit in this file? If so, + * stop bothering with read-ahead. It will only hurt. + */ + if (ra->mmap_miss > ra->mmap_hit + MMAP_LOTSAMISS) + goto no_cached_page; + + did_readaround = 1; + do_page_cache_readahead(mapping, file, pgoff & ~(MMAP_READAROUND-1), MMAP_READAROUND); + goto retry_find; } + if (!did_readaround) + ra->mmap_hit++; + /* * Ok, found a page in the page cache, now we need to check * that it's up-to-date. @@ -1010,6 +1016,14 @@ success: mark_page_accessed(page); return page; +outside_data_content: + /* + * An external ptracer can access pages that normally aren't + * accessible.. + */ + if (area->vm_mm == current->mm) + return NULL; + /* Fall through to the non-read-ahead case */ no_cached_page: /* * We're only likely to ever get here if MADV_RANDOM is in diff --git a/mm/mmap.c b/mm/mmap.c index c83cf2a8b12..1052f84a82a 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -53,65 +54,9 @@ int sysctl_overcommit_memory = 0; /* default is heuristic overcommit */ int sysctl_overcommit_ratio = 50; /* default is 50% */ atomic_t vm_committed_space = ATOMIC_INIT(0); -/* - * Check that a process has enough memory to allocate a new virtual - * mapping. 1 means there is enough memory for the allocation to - * succeed and 0 implies there is not. - * - * We currently support three overcommit policies, which are set via the - * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-acounting - * - * Strict overcommit modes added 2002 Feb 26 by Alan Cox. - * Additional code 2002 Jul 20 by Robert Love. - */ -extern atomic_t slab_reclaim_pages; -int vm_enough_memory(long pages) -{ - unsigned long free, allowed; - - vm_acct_memory(pages); - - /* - * Sometimes we want to use more memory than we have - */ - if (sysctl_overcommit_memory == 1) - return 1; - - if (sysctl_overcommit_memory == 0) { - free = get_page_cache_size(); - free += nr_free_pages(); - free += nr_swap_pages; - - /* - * Any slabs which are created with the - * SLAB_RECLAIM_ACCOUNT flag claim to have contents - * which are reclaimable, under pressure. The dentry - * cache and most inode caches should fall into this - */ - free += atomic_read(&slab_reclaim_pages); - - /* - * Leave the last 3% for root - */ - if (!capable(CAP_SYS_ADMIN)) - free -= free / 32; - - if (free > pages) - return 1; - vm_unacct_memory(pages); - return 0; - } - - allowed = totalram_pages * sysctl_overcommit_ratio / 100; - allowed += total_swap_pages; - - if (atomic_read(&vm_committed_space) < allowed) - return 1; - - vm_unacct_memory(pages); - - return 0; -} +EXPORT_SYMBOL(sysctl_overcommit_memory); +EXPORT_SYMBOL(sysctl_overcommit_ratio); +EXPORT_SYMBOL(vm_committed_space); /* * Requires inode->i_mapping->i_shared_sem @@ -646,7 +591,7 @@ munmap_back: * Private writable mapping: check memory availability */ charged = len >> PAGE_SHIFT; - if (!vm_enough_memory(charged)) + if (security_vm_enough_memory(charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; } @@ -950,7 +895,7 @@ int expand_stack(struct vm_area_struct * vma, unsigned long address) grow = (address - vma->vm_end) >> PAGE_SHIFT; /* Overcommit.. */ - if (!vm_enough_memory(grow)) { + if (security_vm_enough_memory(grow)) { spin_unlock(&vma->vm_mm->page_table_lock); return -ENOMEM; } @@ -1004,7 +949,7 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address) grow = (vma->vm_start - address) >> PAGE_SHIFT; /* Overcommit.. */ - if (!vm_enough_memory(grow)) { + if (security_vm_enough_memory(grow)) { spin_unlock(&vma->vm_mm->page_table_lock); return -ENOMEM; } @@ -1376,7 +1321,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) if (mm->map_count > MAX_MAP_COUNT) return -ENOMEM; - if (!vm_enough_memory(len >> PAGE_SHIFT)) + if (security_vm_enough_memory(len >> PAGE_SHIFT)) return -ENOMEM; flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; diff --git a/mm/mprotect.c b/mm/mprotect.c index 978a9509c35..2c015794e3c 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -175,7 +175,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, if (newflags & VM_WRITE) { if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { charged = (end - start) >> PAGE_SHIFT; - if (!vm_enough_memory(charged)) + if (security_vm_enough_memory(charged)) return -ENOMEM; newflags |= VM_ACCOUNT; } diff --git a/mm/mremap.c b/mm/mremap.c index 8c6ec8b926d..088af945ac5 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -244,9 +245,7 @@ static unsigned long move_vma(struct vm_area_struct *vma, } if (!move_page_tables(vma, new_addr, addr, old_len)) { - unsigned long must_fault_in; - unsigned long fault_in_start; - unsigned long fault_in_end; + unsigned long vm_locked = vma->vm_flags & VM_LOCKED; if (allocated_vma) { *new_vma = *vma; @@ -272,14 +271,8 @@ static unsigned long move_vma(struct vm_area_struct *vma, } else vma = NULL; /* nothing more to do */ - must_fault_in = new_vma->vm_flags & VM_LOCKED; - fault_in_start = new_vma->vm_start; - fault_in_end = new_vma->vm_end; - do_munmap(current->mm, addr, old_len); - /* new_vma could have been invalidated by do_munmap */ - /* Restore VM_ACCOUNT if one or two pieces of vma left */ if (vma) { vma->vm_flags |= VM_ACCOUNT; @@ -288,9 +281,11 @@ static unsigned long move_vma(struct vm_area_struct *vma, } current->mm->total_vm += new_len >> PAGE_SHIFT; - if (must_fault_in) { + if (vm_locked) { current->mm->locked_vm += new_len >> PAGE_SHIFT; - make_pages_present(fault_in_start, fault_in_end); + if (new_len > old_len) + make_pages_present(new_addr + old_len, + new_addr + new_len); } return new_addr; } @@ -391,7 +386,7 @@ unsigned long do_mremap(unsigned long addr, if (vma->vm_flags & VM_ACCOUNT) { charged = (new_len - old_len) >> PAGE_SHIFT; - if (!vm_enough_memory(charged)) + if (security_vm_enough_memory(charged)) goto out_nc; } diff --git a/mm/nommu.c b/mm/nommu.c index cd7900bf3fe..5595fa7054f 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -62,11 +62,8 @@ do_expand: inode->i_size = offset; out_truncate: - if (inode->i_op && inode->i_op->truncate) { - lock_kernel(); + if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); - unlock_kernel(); - } return 0; out_sig: send_sig(SIGXFSZ, current, 0); @@ -253,23 +250,16 @@ static inline unsigned long calc_vm_flags(unsigned long prot, unsigned long flag #ifdef DEBUG static void show_process_blocks(void) { - struct mm_tblock_struct * tblock, *tmp; - + struct mm_tblock_struct *tblock; + printk("Process blocks %d:", current->pid); - - tmp = current->mm->context.tblock; - while (tmp) { - printk(" %p: %p", tmp, tmp->rblock); - if (tmp->rblock) - printk(" (%d @%p #%d)", kobjsize(tmp->rblock->kblock), - tmp->rblock->kblock, tmp->rblock->refcount); - if (tmp->next) - printk(" ->"); - else - printk("."); - tmp = tmp->next; + + for (tblock = ¤t->mm->context.tblock; tblock; tblock = tblock->next) { + printk(" %p: %p", tblock, tblock->rblock); + if (tblock->rblock) + printk(" (%d @%p #%d)", kobjsize(tblock->rblock->kblock), tblock->rblock->kblock, tblock->rblock->refcount); + printk(tblock->next ? " ->" : ".\n"); } - printk("\n"); } #endif /* DEBUG */ @@ -358,7 +348,7 @@ unsigned long do_mmap_pgoff( error = file->f_op->mmap(file, &vma); #ifdef DEBUG - printk("mmap mmap returned %d /%x\n", error, vma.vm_start); + printk("f_op->mmap() returned %d/%lx\n", error, vma.vm_start); #endif if (!error) return vma.vm_start; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index dfd254c2c94..16077203e5a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -32,6 +32,8 @@ #include #include +#include + DECLARE_BITMAP(node_online_map, MAX_NUMNODES); DECLARE_BITMAP(memblk_online_map, MAX_NR_MEMBLKS); struct pglist_data *pgdat_list; @@ -41,6 +43,9 @@ int nr_swap_pages; int numnodes = 1; int sysctl_lower_zone_protection = 0; +EXPORT_SYMBOL(totalram_pages); +EXPORT_SYMBOL(nr_swap_pages); + /* * Used by page_zone() to look up the address of the struct zone whose * id is encoded in the upper bits of page->flags @@ -265,6 +270,7 @@ void __free_pages_ok(struct page *page, unsigned int order) mod_page_state(pgfree, 1 << order); free_pages_check(__FUNCTION__, page); list_add(&page->list, &list); + kernel_map_pages(page, 1<pageset[get_cpu()].pcp[cold]; @@ -556,7 +563,7 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, (!wait && z->free_pages >= z->pages_high)) { page = buffered_rmqueue(z, order, cold); if (page) - return page; + goto got_pg; } min += z->pages_low * sysctl_lower_zone_protection; } @@ -579,7 +586,7 @@ __alloc_pages(unsigned int gfp_mask, unsigned int order, (!wait && z->free_pages >= z->pages_high)) { page = buffered_rmqueue(z, order, cold); if (page) - return page; + goto got_pg; } min += local_min * sysctl_lower_zone_protection; } @@ -594,7 +601,7 @@ rebalance: page = buffered_rmqueue(z, order, cold); if (page) - return page; + goto got_pg; } goto nopage; } @@ -622,7 +629,7 @@ rebalance: (!wait && z->free_pages >= z->pages_high)) { page = buffered_rmqueue(z, order, cold); if (page) - return page; + goto got_pg; } min += z->pages_low * sysctl_lower_zone_protection; } @@ -653,6 +660,9 @@ nopage: current->comm, order, gfp_mask); } return NULL; +got_pg: + kernel_map_pages(page, 1 << order, 1); + return page; } /* @@ -726,6 +736,7 @@ unsigned int nr_free_pages(void) return sum; } +EXPORT_SYMBOL(nr_free_pages); unsigned int nr_used_zone_pages(void) { @@ -818,6 +829,7 @@ DEFINE_PER_CPU(struct page_state, page_states) = {0}; EXPORT_PER_CPU_SYMBOL(page_states); atomic_t nr_pagecache = ATOMIC_INIT(0); +EXPORT_SYMBOL(nr_pagecache); #ifdef CONFIG_SMP DEFINE_PER_CPU(long, nr_pagecache_local) = 0; #endif @@ -896,7 +908,7 @@ void si_meminfo_node(struct sysinfo *val, int nid) { pg_data_t *pgdat = NODE_DATA(nid); - val->totalram = pgdat->node_size; + val->totalram = pgdat->node_present_pages; val->freeram = nr_free_pages_pgdat(pgdat); val->totalhigh = pgdat->node_zones[ZONE_HIGHMEM].present_pages; val->freehigh = pgdat->node_zones[ZONE_HIGHMEM].free_pages; @@ -1131,12 +1143,13 @@ static void __init calculate_zone_totalpages(struct pglist_data *pgdat, for (i = 0; i < MAX_NR_ZONES; i++) totalpages += zones_size[i]; - pgdat->node_size = totalpages; + pgdat->node_spanned_pages = totalpages; realtotalpages = totalpages; if (zholes_size) for (i = 0; i < MAX_NR_ZONES; i++) realtotalpages -= zholes_size[i]; + pgdat->node_present_pages = realtotalpages; printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages); } @@ -1342,7 +1355,7 @@ void __init free_area_init_node(int nid, struct pglist_data *pgdat, pgdat->node_start_pfn = node_start_pfn; calculate_zone_totalpages(pgdat, zones_size, zholes_size); if (!node_mem_map) { - size = (pgdat->node_size + 1) * sizeof(struct page); + size = (pgdat->node_spanned_pages + 1) * sizeof(struct page); node_mem_map = alloc_bootmem_node(pgdat, size); } pgdat->node_mem_map = node_mem_map; diff --git a/mm/readahead.c b/mm/readahead.c index d6fef1a3c12..179ba48d5e5 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -363,9 +363,9 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, } else { /* * A miss - lseek, pagefault, pread, etc. Shrink the readahead - * window by 25%. + * window. */ - ra->next_size -= ra->next_size / 4 + 2; + ra->next_size -= 2; } if ((long)ra->next_size > (long)max) @@ -437,37 +437,6 @@ out: return; } -/* - * For mmap reads (typically executables) the access pattern is fairly random, - * but somewhat ascending. So readaround favours pages beyond the target one. - * We also boost the window size, as it can easily shrink due to misses. - */ -void -page_cache_readaround(struct address_space *mapping, struct file_ra_state *ra, - struct file *filp, unsigned long offset) -{ - if (ra->next_size != -1UL) { - const unsigned long min = get_min_readahead(ra) * 2; - unsigned long target; - unsigned long backward; - - /* - * If next_size is zero then leave it alone, because that's a - * readahead startup state. - */ - if (ra->next_size && ra->next_size < min) - ra->next_size = min; - - target = offset; - backward = ra->next_size / 4; - - if (backward > target) - target = 0; - else - target -= backward; - page_cache_readahead(mapping, ra, filp, target); - } -} /* * handle_ra_miss() is called when it is known that a page which should have diff --git a/mm/shmem.c b/mm/shmem.c index 73301cee3f4..e9d5042bc13 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -507,7 +508,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) */ change = VM_ACCT(attr->ia_size) - VM_ACCT(inode->i_size); if (change > 0) { - if (!vm_enough_memory(change)) + if (security_vm_enough_memory(change)) return -ENOMEM; } else if (attr->ia_size < inode->i_size) { vm_unacct_memory(-change); @@ -1139,7 +1140,7 @@ shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t maxpos = inode->i_size; if (maxpos < pos + count) { maxpos = pos + count; - if (!vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) { + if (security_vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) { err = -ENOMEM; goto out; } @@ -1397,7 +1398,8 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, int mode) return 0; } -static int shmem_create(struct inode *dir, struct dentry *dentry, int mode) +static int shmem_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) { return shmem_mknod(dir, dentry, mode | S_IFREG, 0); } @@ -1493,7 +1495,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s memcpy(info, symname, len); inode->i_op = &shmem_symlink_inline_operations; } else { - if (!vm_enough_memory(VM_ACCT(1))) { + if (security_vm_enough_memory(VM_ACCT(1))) { iput(inode); return -ENOMEM; } @@ -1887,7 +1889,7 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) if (size > SHMEM_MAX_BYTES) return ERR_PTR(-EINVAL); - if ((flags & VM_ACCOUNT) && !vm_enough_memory(VM_ACCT(size))) + if ((flags & VM_ACCOUNT) && security_vm_enough_memory(VM_ACCT(size))) return ERR_PTR(-ENOMEM); error = -ENOMEM; diff --git a/mm/slab.c b/mm/slab.c index cad1bb2e8eb..bee3dfdf861 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -89,7 +89,12 @@ #include #include #include +#include +#include + #include +#include +#include /* * DEBUG - 1 for kmem_cache_create() to honour; SLAB_DEBUG_INITIAL, @@ -351,6 +356,34 @@ struct kmem_cache_s { #define POISON_AFTER 0x6b /* for use-after-free poisoning */ #define POISON_END 0xa5 /* end-byte of poisoning */ +static inline int obj_dbghead(kmem_cache_t *cachep) +{ + if (cachep->flags & SLAB_RED_ZONE) + return BYTES_PER_WORD; + return 0; +} + +static inline int obj_dbglen(kmem_cache_t *cachep) +{ + int len = 0; + + if (cachep->flags & SLAB_RED_ZONE) { + len += 2*BYTES_PER_WORD; + } + if (cachep->flags & SLAB_STORE_USER) { + len += BYTES_PER_WORD; + } + return len; +} +#else +static inline int obj_dbghead(kmem_cache_t *cachep) +{ + return 0; +} +static inline int obj_dbglen(kmem_cache_t *cachep) +{ + return 0; +} #endif /* @@ -430,6 +463,7 @@ struct list_head cache_chain; * SLAB_RECLAIM_ACCOUNT turns this on per-slab */ atomic_t slab_reclaim_pages; +EXPORT_SYMBOL(slab_reclaim_pages); /* * chicken and egg problem: delay the per-cpu array allocation @@ -441,7 +475,7 @@ enum { FULL } g_cpucache_up; -static struct timer_list reap_timers[NR_CPUS]; +static DEFINE_PER_CPU(struct timer_list, reap_timers); static void reap_timer_fnc(unsigned long data); @@ -491,7 +525,7 @@ static void __slab_error(const char *function, kmem_cache_t *cachep, char *msg) */ static void start_cpu_timer(int cpu) { - struct timer_list *rt = &reap_timers[cpu]; + struct timer_list *rt = &per_cpu(reap_timers, cpu); if (rt->function == NULL) { init_timer(rt); @@ -765,16 +799,45 @@ static inline void kmem_freepages (kmem_cache_t *cachep, void *addr) } #if DEBUG -static void poison_obj(kmem_cache_t *cachep, void *addr, unsigned char val) + +#ifdef CONFIG_DEBUG_PAGEALLOC +static void store_stackinfo(kmem_cache_t *cachep, unsigned long *addr, unsigned long caller) { - int size = cachep->objsize; - if (cachep->flags & SLAB_RED_ZONE) { - addr += BYTES_PER_WORD; - size -= 2*BYTES_PER_WORD; - } - if (cachep->flags & SLAB_STORE_USER) { - size -= BYTES_PER_WORD; + int size = cachep->objsize-obj_dbglen(cachep); + + addr = (unsigned long *)&((char*)addr)[obj_dbghead(cachep)]; + + if (size < 5*sizeof(unsigned long)) + return; + + *addr++=0x12345678; + *addr++=caller; + *addr++=smp_processor_id(); + size -= 3*sizeof(unsigned long); + { + unsigned long *sptr = &caller; + unsigned long svalue; + + while (((long) sptr & (THREAD_SIZE-1)) != 0) { + svalue = *sptr++; + if (kernel_text_address(svalue)) { + *addr++=svalue; + size -= sizeof(unsigned long); + if (size <= sizeof(unsigned long)) + break; + } + } + } + *addr++=0x87654321; +} +#endif + +static void poison_obj(kmem_cache_t *cachep, void *addr, unsigned char val) +{ + int size = cachep->objsize-obj_dbglen(cachep); + addr = &((char*)addr)[obj_dbghead(cachep)]; + memset(addr, val, size); *(unsigned char *)(addr+size-1) = POISON_END; } @@ -796,15 +859,11 @@ static void *scan_poisoned_obj(unsigned char* addr, unsigned int size) static void check_poison_obj(kmem_cache_t *cachep, void *addr) { - int size = cachep->objsize; void *end; - if (cachep->flags & SLAB_RED_ZONE) { - addr += BYTES_PER_WORD; - size -= 2*BYTES_PER_WORD; - } - if (cachep->flags & SLAB_STORE_USER) { - size -= BYTES_PER_WORD; - } + int size = cachep->objsize-obj_dbglen(cachep); + + addr = &((char*)addr)[obj_dbghead(cachep)]; + end = scan_poisoned_obj(addr, size); if (end) { int s; @@ -858,8 +917,16 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) void *objp = slabp->s_mem + cachep->objsize * i; int objlen = cachep->objsize; - if (cachep->flags & SLAB_POISON) + if (cachep->flags & SLAB_POISON) { +#ifdef CONFIG_DEBUG_PAGEALLOC + if ((cachep->objsize%PAGE_SIZE)==0 && OFF_SLAB(cachep)) + kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE,1); + else + check_poison_obj(cachep, objp); +#else check_poison_obj(cachep, objp); +#endif + } if (cachep->flags & SLAB_STORE_USER) objlen -= BYTES_PER_WORD; @@ -952,6 +1019,10 @@ kmem_cache_create (const char *name, size_t size, size_t offset, } #if FORCED_DEBUG +#ifdef CONFIG_DEBUG_PAGEALLOC + if (size < PAGE_SIZE-3*BYTES_PER_WORD && size > 128) + size = PAGE_SIZE-3*BYTES_PER_WORD; +#endif /* * Enable redzoning and last user accounting, except * - for caches with forced alignment: redzoning would violate the @@ -1404,6 +1475,8 @@ static void cache_init_objs (kmem_cache_t * cachep, slab_error(cachep, "constructor overwrote the" " start of an object"); } + if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON) + kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0); #else if (cachep->ctor) cachep->ctor(objp, cachep, ctor_flags); @@ -1584,25 +1657,28 @@ static inline void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp, v * caller can perform a verify of its state (debugging). * Called without the cache-lock held. */ - if (cachep->flags & SLAB_RED_ZONE) { - cachep->ctor(objp+BYTES_PER_WORD, + cachep->ctor(objp+obj_dbghead(cachep), cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY); - } else { - cachep->ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY); - } } if (cachep->flags & SLAB_POISON && cachep->dtor) { /* we want to cache poison the object, * call the destruction callback */ - if (cachep->flags & SLAB_RED_ZONE) - cachep->dtor(objp+BYTES_PER_WORD, cachep, 0); - else - cachep->dtor(objp, cachep, 0); + cachep->dtor(objp+obj_dbghead(cachep), cachep, 0); } - if (cachep->flags & SLAB_POISON) + if (cachep->flags & SLAB_POISON) { +#ifdef CONFIG_DEBUG_PAGEALLOC + if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) { + store_stackinfo(cachep, objp, POISON_AFTER); + kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 0); + } else { + poison_obj(cachep, objp, POISON_AFTER); + } +#else poison_obj(cachep, objp, POISON_AFTER); #endif + } +#endif return objp; } @@ -1617,6 +1693,7 @@ static inline void check_slabp(kmem_cache_t *cachep, struct slab *slabp) for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) { entries++; BUG_ON(entries > cachep->num); + BUG_ON(i < 0 || i >= cachep->num); } BUG_ON(entries != cachep->num - slabp->inuse); #endif @@ -1746,9 +1823,16 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, if (!objp) return objp; - if (cachep->flags & SLAB_POISON) { + if (cachep->flags & SLAB_POISON) { +#ifdef CONFIG_DEBUG_PAGEALLOC + if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) + kernel_map_pages(virt_to_page(objp), cachep->objsize/PAGE_SIZE, 1); + else + check_poison_obj(cachep, objp); +#else check_poison_obj(cachep, objp); - poison_obj(cachep, objp, POISON_BEFORE); +#endif + poison_obj(cachep, objp, POISON_BEFORE); } if (cachep->flags & SLAB_STORE_USER) { objlen -= BYTES_PER_WORD; @@ -2085,16 +2169,7 @@ free_percpu(const void *objp) unsigned int kmem_cache_size(kmem_cache_t *cachep) { - unsigned int objlen = cachep->objsize; - -#if DEBUG - if (cachep->flags & SLAB_RED_ZONE) - objlen -= 2*BYTES_PER_WORD; - if (cachep->flags & SLAB_STORE_USER) - objlen -= BYTES_PER_WORD; -#endif - - return objlen; + return cachep->objsize-obj_dbglen(cachep); } kmem_cache_t * kmem_find_general_cachep (size_t size, int gfpflags) @@ -2382,7 +2457,7 @@ next: static void reap_timer_fnc(unsigned long data) { int cpu = smp_processor_id(); - struct timer_list *rt = &reap_timers[cpu]; + struct timer_list *rt = &__get_cpu_var(reap_timers); cache_reap(); mod_timer(rt, jiffies + REAPTIMEOUT_CPUC + cpu); @@ -2626,3 +2701,70 @@ unsigned int ksize(const void *objp) return size; } +void ptrinfo(unsigned long addr) +{ + struct page *page; + + printk("Dumping data about address %p.\n", (void*)addr); + if (!virt_addr_valid((void*)addr)) { + printk("virt addr invalid.\n"); + return; + } + do { + pgd_t *pgd = pgd_offset_k(addr); + pmd_t *pmd; + if (pgd_none(*pgd)) { + printk("No pgd.\n"); + break; + } + pmd = pmd_offset(pgd, addr); + if (pmd_none(*pmd)) { + printk("No pmd.\n"); + break; + } +#ifdef CONFIG_X86 + if (pmd_large(*pmd)) { + printk("Large page.\n"); + break; + } +#endif + printk("normal page, pte_val 0x%llx\n", + (unsigned long long)pte_val(*pte_offset_kernel(pmd, addr))); + } while(0); + + page = virt_to_page((void*)addr); + printk("struct page at %p, flags %lxh.\n", page, page->flags); + if (PageSlab(page)) { + kmem_cache_t *c; + struct slab *s; + unsigned long flags; + int objnr; + void *objp; + + c = GET_PAGE_CACHE(page); + printk("belongs to cache %s.\n",c->name); + + spin_lock_irqsave(&c->spinlock, flags); + s = GET_PAGE_SLAB(page); + printk("slabp %p with %d inuse objects (from %d).\n", + s, s->inuse, c->num); + check_slabp(c,s); + + objnr = (addr-(unsigned long)s->s_mem)/c->objsize; + objp = s->s_mem+c->objsize*objnr; + printk("points into object no %d, starting at %p, len %d.\n", + objnr, objp, c->objsize); + if (objnr >= c->num) { + printk("Bad obj number.\n"); + } else { + kernel_map_pages(virt_to_page(objp), c->objsize/PAGE_SIZE, 1); + + printk("redzone: %lxh/%lxh/%lxh.\n", + ((unsigned long*)objp)[0], + ((unsigned long*)(objp+c->objsize))[-2], + ((unsigned long*)(objp+c->objsize))[-1]); + } + spin_unlock_irqrestore(&c->spinlock, flags); + + } +} diff --git a/mm/swap.c b/mm/swap.c index 5818b0a5a72..37302961e37 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include /* for try_to_release_page() */ #include @@ -370,6 +371,7 @@ void vm_acct_memory(long pages) } preempt_enable(); } +EXPORT_SYMBOL(vm_acct_memory); #endif diff --git a/mm/swapfile.c b/mm/swapfile.c index bdfd09be8d4..bc31505b689 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include #include @@ -30,6 +32,8 @@ unsigned int nr_swapfiles; int total_swap_pages; static int swap_overflow; +EXPORT_SYMBOL(total_swap_pages); + static const char Bad_file[] = "Bad swap file entry "; static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; @@ -1042,7 +1046,7 @@ asmlinkage long sys_swapoff(const char __user * specialfile) swap_list_unlock(); goto out_dput; } - if (vm_enough_memory(p->pages)) + if (!security_vm_enough_memory(p->pages)) vm_unacct_memory(p->pages); else { err = -ENOMEM; diff --git a/net/atm/clip.c b/net/atm/clip.c index 2736719d681..7b3514fee6d 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -327,40 +327,34 @@ static u32 clip_hash(const void *pkey, const struct net_device *dev) return hash_val; } - static struct neigh_table clip_tbl = { - NULL, /* next */ - AF_INET, /* family */ - sizeof(struct neighbour)+sizeof(struct atmarp_entry), /* entry_size */ - 4, /* key_len */ - clip_hash, - clip_constructor, /* constructor */ - NULL, /* pconstructor */ - NULL, /* pdestructor */ - NULL, /* proxy_redo */ - "clip_arp_cache", - { /* neigh_parms */ - NULL, /* next */ - NULL, /* neigh_setup */ - &clip_tbl, /* tbl */ - 0, /* entries */ - NULL, /* priv */ - NULL, /* sysctl_table */ - 30*HZ, /* base_reachable_time */ - 1*HZ, /* retrans_time */ - 60*HZ, /* gc_staletime */ - 30*HZ, /* reachable_time */ - 5*HZ, /* delay_probe_time */ - 3, /* queue_len */ - 3, /* ucast_probes */ - 0, /* app_probes */ - 3, /* mcast_probes */ - 1*HZ, /* anycast_delay */ - (8*HZ)/10, /* proxy_delay */ - 1*HZ, /* proxy_qlen */ - 64 /* locktime */ + .family = AF_INET, + .entry_size = sizeof(struct neighbour)+sizeof(struct atmarp_entry), + .key_len = 4, + .hash = clip_hash, + .constructor = clip_constructor, + .id = "clip_arp_cache", + + /* parameters are copied from ARP ... */ + .parms = { + .tbl = &clip_tbl, + .base_reachable_time = 30 * HZ, + .retrans_time = 1 * HZ, + .gc_staletime = 60 * HZ, + .reachable_time = 30 * HZ, + .delay_probe_time = 5 * HZ, + .queue_len = 3, + .ucast_probes = 3, + .mcast_probes = 3, + .anycast_delay = 1 * HZ, + .proxy_delay = (8 * HZ) / 10, + .proxy_qlen = 64, + .locktime = 1 * HZ, }, - 30*HZ,128,512,1024 /* copied from ARP ... */ + .gc_interval = 30 * HZ, + .gc_thresh1 = 128, + .gc_thresh2 = 512, + .gc_thresh3 = 1024, }; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 2040a73db16..1953785a0ce 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -632,6 +632,7 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, struct net_proto_family hci_sock_family_ops = { .family = PF_BLUETOOTH, + .owner = THIS_MODULE, .create = hci_sock_create, }; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 2a3eff6b437..e0aafca1b78 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -878,6 +878,7 @@ static struct proto_ops rfcomm_sock_ops = { static struct net_proto_family rfcomm_sock_family_ops = { .family = PF_BLUETOOTH, + .owner = THIS_MODULE, .create = rfcomm_sock_create }; diff --git a/net/core/dev.c b/net/core/dev.c index 5102b235b57..0605391589a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1712,7 +1712,7 @@ out: softnet_break: netdev_rx_stat[this_cpu].time_squeeze++; - __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); + __raise_softirq_irqoff(NET_RX_SOFTIRQ); goto out; } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c640ad5b41f..001fdb40e6d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -608,7 +608,9 @@ next_elt: static __inline__ int neigh_max_probes(struct neighbour *n) { struct neigh_parms *p = n->parms; - return p->ucast_probes + p->app_probes + p->mcast_probes; + return (n->nud_state & NUD_PROBE ? + p->ucast_probes : + p->ucast_probes + p->app_probes + p->mcast_probes); } diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9dd6fa44045..0f751521480 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2099,7 +2099,7 @@ struct igmp_mc_iter_state { struct in_device *in_dev; }; -#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)&seq->private) +#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)(seq)->private) static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) { @@ -2254,7 +2254,7 @@ struct igmp_mcf_iter_state { struct ip_mc_list *im; }; -#define igmp_mcf_seq_private(seq) ((struct igmp_mcf_iter_state *)&seq->private) +#define igmp_mcf_seq_private(seq) ((struct igmp_mcf_iter_state *)(seq)->private) static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) { diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 8d72a478f24..081885f4889 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1153,7 +1153,9 @@ static int ipgre_tunnel_init(struct net_device *dev) tunnel = (struct ip_tunnel*)dev->priv; iph = &tunnel->parms.iph; - tunnel->dev = dev; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -1215,6 +1217,9 @@ int __init ipgre_fb_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; struct iphdr *iph = &tunnel->parms.iph; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + iph->version = 4; iph->protocol = IPPROTO_GRE; iph->ihl = 5; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 706b6e8a7bc..c634b83f503 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1115,6 +1115,10 @@ static int pnp_get_info(char *buffer, char **start, "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameservers[i])); } + if (ic_servaddr != INADDR_NONE) + len += sprintf(buffer + len, + "bootserver %u.%u.%u.%u\n", + NIPQUAD(ic_servaddr)); if (offset > len) offset = len; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 59c26022efc..cfa33e90eff 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -805,7 +805,10 @@ static int ipip_tunnel_init(struct net_device *dev) tunnel = (struct ip_tunnel*)dev->priv; iph = &tunnel->parms.iph; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -841,6 +844,9 @@ static int __init ipip_fb_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel = dev->priv; struct iphdr *iph = &tunnel->parms.iph; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + iph->version = 4; iph->protocol = IPPROTO_IPIP; iph->ihl = 5; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index cb939b4fad0..76dc609a793 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -687,7 +687,7 @@ struct raw_iter_state { int bucket; }; -#define raw_seq_private(seq) ((struct raw_iter_state *)&seq->private) +#define raw_seq_private(seq) ((struct raw_iter_state *)(seq)->private) static struct sock *raw_get_first(struct seq_file *seq) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f29eaafc4c0..a287499dff5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3693,7 +3693,17 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_sync_mss(sk, tp->pmtu_cookie); tcp_initialize_rcv_mss(sk); + + /* Make sure socket is routed, for correct metrics. */ + tp->af_specific->rebuild_header(sk); + tcp_init_metrics(sk); + + /* Prevent spurious tcp_cwnd_restart() on first data + * packet. + */ + tp->lsndtime = tcp_time_stamp; + tcp_init_buffer_space(sk); if (sock_flag(sk, SOCK_KEEPOPEN)) @@ -3959,7 +3969,18 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (tp->tstamp_ok) tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; + /* Make sure socket is routed, for + * correct metrics. + */ + tp->af_specific->rebuild_header(sk); + tcp_init_metrics(sk); + + /* Prevent spurious tcp_cwnd_restart() on + * first data packet. + */ + tp->lsndtime = tcp_time_stamp; + tcp_initialize_rcv_mss(sk); tcp_init_buffer_space(sk); tcp_fast_path_on(tp); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 15a9ce7a3cc..dcf72c3485d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1299,7 +1299,6 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) { struct prefix_info *pinfo; - struct rt6_info *rt; __u32 valid_lft; __u32 prefered_lft; int addr_type; @@ -1355,33 +1354,33 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) else rt_expires = jiffies + valid_lft * HZ; - rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1); - - if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { - if (rt->rt6i_flags&RTF_EXPIRES) { - if (pinfo->onlink == 0 || valid_lft == 0) { - ip6_del_rt(rt, NULL, NULL); - rt = NULL; - } else { - rt->rt6i_expires = rt_expires; + if (pinfo->onlink) { + struct rt6_info *rt; + rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1); + + if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { + if (rt->rt6i_flags&RTF_EXPIRES) { + if (valid_lft == 0) { + ip6_del_rt(rt, NULL, NULL); + rt = NULL; + } else { + rt->rt6i_expires = rt_expires; + } } + } else if (valid_lft) { + addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, + dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES); } - } else if (pinfo->onlink && valid_lft) { - addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, - dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES); + if (rt) + dst_release(&rt->u.dst); } - if (rt) - dst_release(&rt->u.dst); /* Try to figure out our local address for this prefix */ if (pinfo->autoconf && in6_dev->cnf.autoconf) { struct inet6_ifaddr * ifp; struct in6_addr addr; - int plen; - int create = 0; - - plen = pinfo->prefix_len >> 3; + int create = 0, update_lft = 0; if (pinfo->prefix_len == 64) { memcpy(&addr, &pinfo->prefix, 8); @@ -1415,32 +1414,54 @@ ok: return; } - create = 1; + update_lft = create = 1; addrconf_dad_start(ifp); } - if (ifp && valid_lft == 0) { - ipv6_del_addr(ifp); - ifp = NULL; - } - if (ifp) { int flags; + unsigned long now; #ifdef CONFIG_IPV6_PRIVACY struct inet6_ifaddr *ift; #endif + u32 stored_lft; + /* update lifetime (RFC2462 5.5.3 e) */ spin_lock(&ifp->lock); - ifp->valid_lft = valid_lft; - ifp->prefered_lft = prefered_lft; - ifp->tstamp = jiffies; - flags = ifp->flags; - ifp->flags &= ~IFA_F_DEPRECATED; - spin_unlock(&ifp->lock); - - if (!(flags&IFA_F_TENTATIVE)) - ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ? - 0 : RTM_NEWADDR, ifp); + now = jiffies; + if (ifp->valid_lft > (now - ifp->tstamp) / HZ) + stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; + else + stored_lft = 0; + if (!update_lft && stored_lft) { + if (valid_lft > MIN_VALID_LIFETIME || + valid_lft > stored_lft) + update_lft = 1; + else if (stored_lft <= MIN_VALID_LIFETIME) { + /* valid_lft <= stored_lft is always true */ + /* XXX: IPsec */ + update_lft = 0; + } else { + valid_lft = MIN_VALID_LIFETIME; + if (valid_lft < prefered_lft) + prefered_lft = valid_lft; + update_lft = 1; + } + } + + if (update_lft) { + ifp->valid_lft = valid_lft; + ifp->prefered_lft = prefered_lft; + ifp->tstamp = now; + flags = ifp->flags; + ifp->flags &= ~IFA_F_DEPRECATED; + spin_unlock(&ifp->lock); + + if (!(flags&IFA_F_TENTATIVE)) + ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ? + 0 : RTM_NEWADDR, ifp); + } else + spin_unlock(&ifp->lock); #ifdef CONFIG_IPV6_PRIVACY read_lock_bh(&in6_dev->lock); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index ff77920a52c..1dc5b9da2e2 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -441,7 +441,7 @@ struct ac6_iter_state { struct inet6_dev *idev; }; -#define ac6_seq_private(seq) ((struct ac6_iter_state *)&seq->private) +#define ac6_seq_private(seq) ((struct ac6_iter_state *)(seq)->private) static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) { diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 7211838a454..c26b90ab571 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -559,7 +559,7 @@ struct ip6fl_iter_state { int bucket; }; -#define ip6fl_seq_private(seq) ((struct ip6fl_iter_state *)&(seq)->private) +#define ip6fl_seq_private(seq) ((struct ip6fl_iter_state *)(seq)->private) static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) { diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9edc73163d0..d2a96f793a5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1239,7 +1239,6 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse memcpy(np->cork.opt, opt, opt->tot_len); inet->cork.flags |= IPCORK_OPT; /* need source address above miyazawa*/ - exthdrlen += opt->opt_flen ? opt->opt_flen : 0; } dst_hold(&rt->u.dst); np->cork.rt = rt; @@ -1252,6 +1251,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offse length += exthdrlen; transhdrlen += exthdrlen; } + exthdrlen += opt ? opt->opt_flen : 0; } else { rt = np->cork.rt; if (inet->cork.flags & IPCORK_OPT) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 58dfe07c6b4..221a1dd22cb 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -87,18 +87,11 @@ static void ip6_xmit_unlock(void) static int ip6ip6_fb_tnl_dev_init(struct net_device *dev); static int ip6ip6_tnl_dev_init(struct net_device *dev); +static void ip6ip6_tnl_dev_setup(struct net_device *dev); /* the IPv6 tunnel fallback device */ -static struct net_device ip6ip6_fb_tnl_dev = { - .name = "ip6tnl0", - .init = ip6ip6_fb_tnl_dev_init -}; +static struct net_device *ip6ip6_fb_tnl_dev; -/* the IPv6 fallback tunnel */ -static struct ip6_tnl ip6ip6_fb_tnl = { - .dev = &ip6ip6_fb_tnl_dev, - .parms ={.name = "ip6tnl0", .proto = IPPROTO_IPV6} -}; /* lists for storing tunnels in use */ static struct ip6_tnl *tnls_r_l[HASH_SIZE]; @@ -216,59 +209,39 @@ static int ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt) { struct net_device *dev; - int err = -ENOBUFS; struct ip6_tnl *t; + char name[IFNAMSIZ]; + int err; - dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL); - if (!dev) - return err; - - memset(dev, 0, sizeof (*dev) + sizeof (*t)); - dev->priv = (void *) (dev + 1); - t = (struct ip6_tnl *) dev->priv; - t->dev = dev; - dev->init = ip6ip6_tnl_dev_init; - memcpy(&t->parms, p, sizeof (*p)); - t->parms.name[IFNAMSIZ - 1] = '\0'; - strcpy(dev->name, t->parms.name); - if (!dev->name[0]) { - int i = 0; - int exists = 0; - - do { - sprintf(dev->name, "ip6tnl%d", ++i); - exists = (__dev_get_by_name(dev->name) != NULL); - } while (i < IP6_TNL_MAX && exists); - - if (i == IP6_TNL_MAX) { - goto failed; + if (p->name[0]) { + strlcpy(name, p->name, IFNAMSIZ); + } else { + int i; + for (i = 1; i < IP6_TNL_MAX; i++) { + sprintf(name, "ip6tnl%d", i); + if (__dev_get_by_name(name) == NULL) + break; } - memcpy(t->parms.name, dev->name, IFNAMSIZ); + if (i == IP6_TNL_MAX) + return -ENOBUFS; } - SET_MODULE_OWNER(dev); + dev = alloc_netdev(sizeof (*t), name, ip6ip6_tnl_dev_setup); + if (dev == NULL) + return -ENOMEM; + + t = dev->priv; + dev->init = ip6ip6_tnl_dev_init; + t->parms = *p; + if ((err = register_netdevice(dev)) < 0) { - goto failed; + kfree(dev); + return err; } + dev_hold(dev); + ip6ip6_tnl_link(t); *pt = t; return 0; -failed: - kfree(dev); - return err; -} - -/** - * ip6_tnl_destroy() - destroy old tunnel - * @t: tunnel to be destroyed - * - * Return: - * whatever unregister_netdevice() returns - **/ - -static inline int -ip6_tnl_destroy(struct ip6_tnl *t) -{ - return unregister_netdevice(t->dev); } /** @@ -304,24 +277,13 @@ ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create) return (create ? -EEXIST : 0); } } - if (!create) { + if (!create) return -ENODEV; - } + return ip6_tnl_create(p, pt); } /** - * ip6ip6_tnl_dev_destructor - tunnel device destructor - * @dev: the device to be destroyed - **/ - -static void -ip6ip6_tnl_dev_destructor(struct net_device *dev) -{ - kfree(dev); -} - -/** * ip6ip6_tnl_dev_uninit - tunnel device uninitializer * @dev: the device to be destroyed * @@ -332,14 +294,14 @@ ip6ip6_tnl_dev_destructor(struct net_device *dev) static void ip6ip6_tnl_dev_uninit(struct net_device *dev) { - if (dev == &ip6ip6_fb_tnl_dev) { + if (dev == ip6ip6_fb_tnl_dev) { write_lock_bh(&ip6ip6_lock); tnls_wc[0] = NULL; write_unlock_bh(&ip6ip6_lock); } else { - struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; - ip6ip6_tnl_unlink(t); + ip6ip6_tnl_unlink((struct ip6_tnl *) dev->priv); } + dev_put(dev); } /** @@ -506,7 +468,7 @@ void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); if (rt) - dst_free(&rt->u.dst); + dst_release(&rt->u.dst); kfree_skb(skb2); } @@ -878,7 +840,6 @@ static void ip6_tnl_set_cap(struct ip6_tnl *t) } } - static void ip6ip6_tnl_link_config(struct ip6_tnl *t) { struct net_device *dev = t->dev; @@ -906,31 +867,25 @@ static void ip6ip6_tnl_link_config(struct ip6_tnl *t) if (p->flags & IP6_TNL_F_CAP_XMIT) { struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr, p->link, 0); - if (rt) { - struct net_device *rtdev; - if (!(rtdev = rt->rt6i_dev) || - rtdev->type == ARPHRD_TUNNEL6) { - /* as long as tunnels use the same socket - for transmission, locally nested tunnels - won't work */ - dst_release(&rt->u.dst); - goto no_link; - } else { - dev->iflink = rtdev->ifindex; - dev->hard_header_len = rtdev->hard_header_len + - sizeof (struct ipv6hdr); - dev->mtu = rtdev->mtu - sizeof (struct ipv6hdr); - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; - - dst_release(&rt->u.dst); - } + + if (rt == NULL) + return; + + /* as long as tunnels use the same socket for transmission, + locally nested tunnels won't work */ + + if (rt->rt6i_dev && rt->rt6i_dev->type != ARPHRD_TUNNEL6) { + dev->iflink = rt->rt6i_dev->ifindex; + + dev->hard_header_len = rt->rt6i_dev->hard_header_len + + sizeof (struct ipv6hdr); + + dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr); + + if (dev->mtu < IPV6_MIN_MTU) + dev->mtu = IPV6_MIN_MTU; } - } else { - no_link: - dev->iflink = 0; - dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); - dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); + dst_release(&rt->u.dst); } } @@ -995,7 +950,7 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGETTUNNEL: - if (dev == &ip6ip6_fb_tnl_dev) { + if (dev == ip6ip6_fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { @@ -1024,7 +979,7 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT; break; } - if (!create && dev != &ip6ip6_fb_tnl_dev) { + if (!create && dev != ip6ip6_fb_tnl_dev) { t = (struct ip6_tnl *) dev->priv; } if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) { @@ -1052,7 +1007,7 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) break; - if (dev == &ip6ip6_fb_tnl_dev) { + if (dev == ip6ip6_fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; @@ -1061,14 +1016,14 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) err = ip6ip6_tnl_locate(&p, &t, 0); if (err) break; - if (t == &ip6ip6_fb_tnl) { + if (t == ip6ip6_fb_tnl_dev->priv) { err = -EPERM; break; } } else { t = (struct ip6_tnl *) dev->priv; } - err = ip6_tnl_destroy(t); + err = unregister_netdevice(t->dev); break; default: err = -EINVAL; @@ -1110,40 +1065,49 @@ ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) } /** - * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices + * ip6ip6_tnl_dev_setup - setup virtual tunnel device * @dev: virtual device associated with tunnel * * Description: - * Set function pointers and initialize the &struct flowi template used - * by the tunnel. + * Initialize function pointers and device parameters **/ -static void -ip6ip6_tnl_dev_init_gen(struct net_device *dev) +static void ip6ip6_tnl_dev_setup(struct net_device *dev) { - struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; - struct flowi *fl = &t->fl; - - memset(fl, 0, sizeof (*fl)); - fl->proto = IPPROTO_IPV6; - - dev->destructor = ip6ip6_tnl_dev_destructor; + SET_MODULE_OWNER(dev); dev->uninit = ip6ip6_tnl_dev_uninit; + dev->destructor = (void (*)(struct net_device *))kfree; dev->hard_start_xmit = ip6ip6_tnl_xmit; dev->get_stats = ip6ip6_tnl_get_stats; dev->do_ioctl = ip6ip6_tnl_ioctl; dev->change_mtu = ip6ip6_tnl_change_mtu; + dev->type = ARPHRD_TUNNEL6; + dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); + dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); dev->flags |= IFF_NOARP; - if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST && - ipv6_addr_type(&t->parms.laddr) & IPV6_ADDR_UNICAST) - dev->flags |= IFF_POINTOPOINT; - /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be + dev->iflink = 0; + /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be copied to dev->dev_addr and dev->broadcast, like the ipv4 addresses were in ipip.c, ip_gre.c and sit.c. */ dev->addr_len = 0; } + +/** + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices + * @dev: virtual device associated with tunnel + **/ + +static inline void +ip6ip6_tnl_dev_init_gen(struct net_device *dev) +{ + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; + t->fl.proto = IPPROTO_IPV6; + t->dev = dev; + strcpy(t->parms.name, dev->name); +} + /** * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices * @dev: virtual device associated with tunnel @@ -1167,8 +1131,10 @@ ip6ip6_tnl_dev_init(struct net_device *dev) int ip6ip6_fb_tnl_dev_init(struct net_device *dev) { - ip6ip6_tnl_dev_init_gen(dev); - tnls_wc[0] = &ip6ip6_fb_tnl; + struct ip6_tnl *t = dev->priv; + ip6ip6_tnl_dev_init_gen(dev); + dev_hold(dev); + tnls_wc[0] = t; return 0; } @@ -1190,8 +1156,6 @@ int __init ip6_tunnel_init(void) struct sock *sk; struct ipv6_pinfo *np; - ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl; - for (i = 0; i < NR_CPUS; i++) { if (!cpu_possible(i)) continue; @@ -1219,10 +1183,23 @@ int __init ip6_tunnel_init(void) goto fail; } - SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev); - register_netdev(&ip6ip6_fb_tnl_dev); + + ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", + ip6ip6_tnl_dev_setup); + if (!ip6ip6_fb_tnl_dev) { + err = -ENOMEM; + goto tnl_fail; + } + ip6ip6_fb_tnl_dev->init = ip6ip6_fb_tnl_dev_init; + + if ((err = register_netdev(ip6ip6_fb_tnl_dev))) { + kfree(ip6ip6_fb_tnl_dev); + goto tnl_fail; + } return 0; +tnl_fail: + inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6); fail: for (j = 0; j < i; j++) { if (!cpu_possible(j)) @@ -1241,7 +1218,7 @@ void ip6_tunnel_cleanup(void) { int i; - unregister_netdev(&ip6ip6_fb_tnl_dev); + unregister_netdev(ip6ip6_fb_tnl_dev); inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f286ae429a2..82983227553 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2045,7 +2045,7 @@ struct igmp6_mc_iter_state { struct inet6_dev *idev; }; -#define igmp6_mc_seq_private(seq) ((struct igmp6_mc_iter_state *)&seq->private) +#define igmp6_mc_seq_private(seq) ((struct igmp6_mc_iter_state *)(seq)->private) static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) { @@ -2185,7 +2185,7 @@ struct igmp6_mcf_iter_state { struct ifmcaddr6 *im; }; -#define igmp6_mcf_seq_private(seq) ((struct igmp6_mcf_iter_state *)&seq->private) +#define igmp6_mcf_seq_private(seq) ((struct igmp6_mcf_iter_state *)(seq)->private) static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) { diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4d0cd058fd7..445556a097d 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -229,7 +229,7 @@ int snmp6_register_dev(struct inet6_dev *idev) return -EINVAL; if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), - __alignof__(struct ipv6_mib)) < 0) + __alignof__(struct icmpv6_mib)) < 0) goto err_icmp; #ifdef CONFIG_PROC_FS diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d1b44f4b813..890ec35ba0c 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -624,6 +624,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg if (msg->msg_controllen) { opt = &opt_space; memset(opt, 0, sizeof(struct ipv6_txoptions)); + opt->tot_len = sizeof(struct ipv6_txoptions); err = datagram_send_ctl(msg, &fl, opt, &hlimit); if (err < 0) { @@ -913,7 +914,7 @@ struct raw6_iter_state { int bucket; }; -#define raw6_seq_private(seq) ((struct raw6_iter_state *)&seq->private) +#define raw6_seq_private(seq) ((struct raw6_iter_state *)(seq)->private) static struct sock *raw6_get_first(struct seq_file *seq) { diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 63ec147528e..ff37d74152f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -602,6 +602,8 @@ static int ipv6_get_mtu(struct net_device *dev) static inline unsigned int ipv6_advmss(unsigned int mtu) { + mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); + if (mtu < ip6_rt_min_advmss) mtu = ip6_rt_min_advmss; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4bbfa57a29c..8d34af7550f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -743,7 +743,10 @@ static int ipip6_tunnel_init(struct net_device *dev) tunnel = (struct ip_tunnel*)dev->priv; iph = &tunnel->parms.iph; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -780,6 +783,9 @@ int __init ipip6_fb_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel = dev->priv; struct iphdr *iph = &tunnel->parms.iph; + tunnel->dev = dev; + strcpy(tunnel->parms.name, dev->name); + iph->version = 4; iph->protocol = IPPROTO_IPV6; iph->ihl = 5; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d22230f166a..21b165ec533 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -544,7 +544,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, struct ipv6_pinfo *np = inet6_sk(sk); struct tcp_opt *tp = tcp_sk(sk); struct in6_addr *saddr = NULL; - struct in6_addr saddr_buf; struct flowi fl; struct dst_entry *dst; int addr_type; @@ -671,23 +670,24 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, goto failure; } - ip6_dst_store(sk, dst, NULL); - sk->sk_route_caps = dst->dev->features & - ~(NETIF_F_IP_CSUM | NETIF_F_TSO); - if (saddr == NULL) { - err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf); - if (err) + err = ipv6_get_saddr(dst, &np->daddr, &fl.fl6_src); + if (err) { + dst_release(dst); goto failure; - - saddr = &saddr_buf; + } + saddr = &fl.fl6_src; + ipv6_addr_copy(&np->rcv_saddr, saddr); } /* set the source address */ - ipv6_addr_copy(&np->rcv_saddr, saddr); ipv6_addr_copy(&np->saddr, saddr); inet->rcv_saddr = LOOPBACK4_IPV6; + ip6_dst_store(sk, dst, NULL); + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); + tp->ext_header_len = 0; if (np->opt) tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen; @@ -714,8 +714,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, late_failure: tcp_set_state(sk, TCP_CLOSE); -failure: __sk_dst_reset(sk); +failure: inet->dport = 0; sk->sk_route_caps = 0; return err; diff --git a/net/key/af_key.c b/net/key/af_key.c index c14f2f1a18e..a6e913e5f11 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1989,9 +1989,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg err = 0; out: - if (xp) { - xfrm_policy_kill(xp); - } + xfrm_pol_put(xp); return err; } @@ -2031,12 +2029,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h err = 0; out: - if (xp) { - if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) - xfrm_policy_kill(xp); - else - xfrm_pol_put(xp); - } + xfrm_pol_put(xp); return err; } diff --git a/net/netsyms.c b/net/netsyms.c index aad457bd3d7..f327ebe6c75 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -641,6 +641,7 @@ EXPORT_SYMBOL(qdisc_tree_lock); #ifdef CONFIG_NET_SCHED PSCHED_EXPORTLIST; EXPORT_SYMBOL(pfifo_qdisc_ops); +EXPORT_SYMBOL(bfifo_qdisc_ops); EXPORT_SYMBOL(register_qdisc); EXPORT_SYMBOL(unregister_qdisc); EXPORT_SYMBOL(qdisc_get_rtab); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5867ffa99ac..e07cba1139b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1368,8 +1368,13 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void struct packet_opt *po = pkt_sk(sk); switch (msg) { - case NETDEV_DOWN: case NETDEV_UNREGISTER: +#ifdef CONFIG_PACKET_MULTICAST + if (po->mclist) + packet_dev_mclist(dev, po->mclist, -1); + // fallthrough +#endif + case NETDEV_DOWN: if (dev->ifindex == po->ifindex) { spin_lock(&po->bind_lock); if (po->running) { @@ -1386,10 +1391,6 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void } spin_unlock(&po->bind_lock); } -#ifdef CONFIG_PACKET_MULTICAST - if (po->mclist) - packet_dev_mclist(dev, po->mclist, -1); -#endif break; case NETDEV_UP: spin_lock(&po->bind_lock); @@ -1400,10 +1401,6 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void po->running = 1; } spin_unlock(&po->bind_lock); -#ifdef CONFIG_PACKET_MULTICAST - if (po->mclist) - packet_dev_mclist(dev, po->mclist, +1); -#endif break; } } diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 94c349128df..be15be08f0b 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -545,15 +545,16 @@ static int atm_tc_requeue(struct sk_buff *skb,struct Qdisc *sch) } -static int atm_tc_drop(struct Qdisc *sch) +static unsigned int atm_tc_drop(struct Qdisc *sch) { struct atm_qdisc_data *p = PRIV(sch); struct atm_flow_data *flow; + unsigned int len; DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n",sch,p); for (flow = p->flows; flow; flow = flow->next) - if (flow->q->ops->drop && flow->q->ops->drop(flow->q)) - return 1; + if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q))) + return len; return 0; } diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 620427492ed..f7e5bef816d 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1231,11 +1231,12 @@ static void cbq_link_class(struct cbq_class *this) } } -static int cbq_drop(struct Qdisc* sch) +static unsigned int cbq_drop(struct Qdisc* sch) { struct cbq_sched_data *q = (struct cbq_sched_data *)sch->data; struct cbq_class *cl, *cl_head; int prio; + unsigned int len; for (prio = TC_CBQ_MAXPRIO; prio >= 0; prio--) { if ((cl_head = q->active[prio]) == NULL) @@ -1243,9 +1244,9 @@ static int cbq_drop(struct Qdisc* sch) cl = cl_head; do { - if (cl->q->ops->drop && cl->q->ops->drop(cl->q)) { + if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) { sch->q.qlen--; - return 1; + return len; } } while ((cl = cl->next_alive) != cl_head); } diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 88274fa7808..ec9837bb9e5 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -302,17 +302,18 @@ static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch) } -static int dsmark_drop(struct Qdisc *sch) +static unsigned int dsmark_drop(struct Qdisc *sch) { struct dsmark_qdisc_data *p = PRIV(sch); - + unsigned int len; + DPRINTK("dsmark_reset(sch %p,[qdisc %p])\n",sch,p); if (!p->q->ops->drop) return 0; - if (!p->q->ops->drop(p->q)) + if (!(len = p->q->ops->drop(p->q))) return 0; sch->q.qlen--; - return 1; + return len; } diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index df193ebe19c..9e49f95eb0e 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -81,16 +81,17 @@ bfifo_dequeue(struct Qdisc* sch) return skb; } -static int +static unsigned int fifo_drop(struct Qdisc* sch) { struct sk_buff *skb; skb = __skb_dequeue_tail(&sch->q); if (skb) { - sch->stats.backlog -= skb->len; + unsigned int len = skb->len; + sch->stats.backlog -= len; kfree_skb(skb); - return 1; + return len; } return 0; } diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index f527f774697..051c2527fcc 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -259,8 +259,7 @@ gred_dequeue(struct Qdisc* sch) return NULL; } -static int -gred_drop(struct Qdisc* sch) +static unsigned int gred_drop(struct Qdisc* sch) { struct sk_buff *skb; @@ -269,20 +268,21 @@ gred_drop(struct Qdisc* sch) skb = __skb_dequeue_tail(&sch->q); if (skb) { - sch->stats.backlog -= skb->len; + unsigned int len = skb->len; + sch->stats.backlog -= len; sch->stats.drops++; q= t->tab[(skb->tc_index&0xf)]; if (q) { - q->backlog -= skb->len; + q->backlog -= len; q->other++; if (!q->backlog && !t->eqp) PSCHED_GET_TIME(q->qidlestart); - } else { - D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); - } + } else { + D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); + } kfree_skb(skb); - return 1; + return len; } q=t->tab[t->def]; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index ef4ea4452c5..6063ef43e17 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1059,7 +1059,7 @@ fin: } /* try to drop from each class (by prio) until one succeed */ -static int htb_drop(struct Qdisc* sch) +static unsigned int htb_drop(struct Qdisc* sch) { struct htb_sched *q = (struct htb_sched *)sch->data; int prio; @@ -1067,14 +1067,15 @@ static int htb_drop(struct Qdisc* sch) for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { struct list_head *p; list_for_each (p,q->drops+prio) { - struct htb_class *cl = list_entry(p,struct htb_class, - un.leaf.drop_list); + struct htb_class *cl = list_entry(p, struct htb_class, + un.leaf.drop_list); + unsigned int len; if (cl->un.leaf.q->ops->drop && - cl->un.leaf.q->ops->drop(cl->un.leaf.q)) { + (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { sch->q.qlen--; if (!cl->un.leaf.q->q.qlen) htb_deactivate (q,cl); - return 1; + return len; } } } diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index 2b77133fb9f..5a63a85d84b 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -190,7 +190,7 @@ static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch) return 0; } -static int ingress_drop(struct Qdisc *sch) +static unsigned int ingress_drop(struct Qdisc *sch) { #ifdef DEBUG_INGRESS struct ingress_qdisc_data *p = PRIV(sch); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 2bf080a641b..c09a7f95050 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -124,18 +124,18 @@ prio_dequeue(struct Qdisc* sch) } -static int -prio_drop(struct Qdisc* sch) +static unsigned int prio_drop(struct Qdisc* sch) { struct prio_sched_data *q = (struct prio_sched_data *)sch->data; int prio; + unsigned int len; struct Qdisc *qdisc; for (prio = q->bands-1; prio >= 0; prio--) { qdisc = q->queues[prio]; - if (qdisc->ops->drop(qdisc)) { + if ((len = qdisc->ops->drop(qdisc)) != 0) { sch->q.qlen--; - return 1; + return len; } } return 0; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index e5fd355f27b..b2e8956418a 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -342,19 +342,19 @@ red_dequeue(struct Qdisc* sch) return NULL; } -static int -red_drop(struct Qdisc* sch) +static unsigned int red_drop(struct Qdisc* sch) { struct sk_buff *skb; struct red_sched_data *q = (struct red_sched_data *)sch->data; skb = __skb_dequeue_tail(&sch->q); if (skb) { - sch->stats.backlog -= skb->len; + unsigned int len = skb->len; + sch->stats.backlog -= len; sch->stats.drops++; q->st.other++; kfree_skb(skb); - return 1; + return len; } PSCHED_GET_TIME(q->qidlestart); return 0; diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index a544be3aa72..c5802d8b2cc 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -209,11 +209,12 @@ static inline void sfq_inc(struct sfq_sched_data *q, sfq_index x) sfq_link(q, x); } -static int sfq_drop(struct Qdisc *sch) +static unsigned int sfq_drop(struct Qdisc *sch) { struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data; sfq_index d = q->max_depth; struct sk_buff *skb; + unsigned int len; /* Queue is full! Find the longest slot and drop a packet from it */ @@ -221,12 +222,13 @@ static int sfq_drop(struct Qdisc *sch) if (d > 1) { sfq_index x = q->dep[d+SFQ_DEPTH].next; skb = q->qs[x].prev; + len = skb->len; __skb_unlink(skb, &q->qs[x]); kfree_skb(skb); sfq_dec(q, x); sch->q.qlen--; sch->stats.drops++; - return 1; + return len; } if (d == 1) { @@ -235,13 +237,14 @@ static int sfq_drop(struct Qdisc *sch) q->next[q->tail] = q->next[d]; q->allot[q->next[d]] += q->quantum; skb = q->qs[d].prev; + len = skb->len; __skb_unlink(skb, &q->qs[d]); kfree_skb(skb); sfq_dec(q, d); sch->q.qlen--; q->ht[q->hash[d]] = SFQ_DEPTH; sch->stats.drops++; - return 1; + return len; } return 0; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 382bc76a71d..c115df75216 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -7,6 +7,8 @@ * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, + * Dmitry Torokhov - allow attaching inner qdiscs - + * original idea by Martin Devera * */ @@ -123,62 +125,63 @@ struct tbf_sched_data long ptokens; /* Current number of P tokens */ psched_time_t t_c; /* Time check-point */ struct timer_list wd_timer; /* Watchdog timer */ + struct Qdisc *qdisc; /* Inner qdisc, default - bfifo queue */ }; #define L2T(q,L) ((q)->R_tab->data[(L)>>(q)->R_tab->rate.cell_log]) #define L2T_P(q,L) ((q)->P_tab->data[(L)>>(q)->P_tab->rate.cell_log]) -static int -tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) +static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + int ret; - if (skb->len > q->max_size) - goto drop; - __skb_queue_tail(&sch->q, skb); - if ((sch->stats.backlog += skb->len) <= q->limit) { - sch->stats.bytes += skb->len; - sch->stats.packets++; - return 0; - } - - /* Drop action: undo the things that we just did, - * i.e. make tail drop - */ - - __skb_unlink(skb, &sch->q); - sch->stats.backlog -= skb->len; - -drop: - sch->stats.drops++; + if (skb->len > q->max_size || sch->stats.backlog + skb->len > q->limit) { + sch->stats.drops++; #ifdef CONFIG_NET_CLS_POLICE - if (sch->reshape_fail==NULL || sch->reshape_fail(skb, sch)) + if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch)) #endif - kfree_skb(skb); - return NET_XMIT_DROP; -} - -static int -tbf_requeue(struct sk_buff *skb, struct Qdisc* sch) -{ - __skb_queue_head(&sch->q, skb); + kfree_skb(skb); + + return NET_XMIT_DROP; + } + + if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) { + sch->stats.drops++; + return ret; + } + + sch->q.qlen++; sch->stats.backlog += skb->len; + sch->stats.bytes += skb->len; + sch->stats.packets++; return 0; } -static int -tbf_drop(struct Qdisc* sch) +static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch) { - struct sk_buff *skb; + struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + int ret; + + if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) { + sch->q.qlen++; + sch->stats.backlog += skb->len; + } + + return ret; +} - skb = __skb_dequeue_tail(&sch->q); - if (skb) { - sch->stats.backlog -= skb->len; +static unsigned int tbf_drop(struct Qdisc* sch) +{ + struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + unsigned int len; + + if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { + sch->q.qlen--; + sch->stats.backlog -= len; sch->stats.drops++; - kfree_skb(skb); - return 1; } - return 0; + return len; } static void tbf_watchdog(unsigned long arg) @@ -189,19 +192,19 @@ static void tbf_watchdog(unsigned long arg) netif_schedule(sch->dev); } -static struct sk_buff * -tbf_dequeue(struct Qdisc* sch) +static struct sk_buff *tbf_dequeue(struct Qdisc* sch) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; struct sk_buff *skb; - skb = __skb_dequeue(&sch->q); + skb = q->qdisc->dequeue(q->qdisc); if (skb) { psched_time_t now; long toks; long ptoks = 0; - + unsigned int len = skb->len; + PSCHED_GET_TIME(now); toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer, 0); @@ -210,18 +213,19 @@ tbf_dequeue(struct Qdisc* sch) ptoks = toks + q->ptokens; if (ptoks > (long)q->mtu) ptoks = q->mtu; - ptoks -= L2T_P(q, skb->len); + ptoks -= L2T_P(q, len); } toks += q->tokens; if (toks > (long)q->buffer) toks = q->buffer; - toks -= L2T(q, skb->len); + toks -= L2T(q, len); if ((toks|ptoks) >= 0) { q->t_c = now; q->tokens = toks; q->ptokens = ptoks; - sch->stats.backlog -= skb->len; + sch->stats.backlog -= len; + sch->q.qlen--; sch->flags &= ~TCQ_F_THROTTLED; return skb; } @@ -245,20 +249,25 @@ tbf_dequeue(struct Qdisc* sch) This is the main idea of all FQ algorithms (cf. CSZ, HPFQ, HFSC) */ - __skb_queue_head(&sch->q, skb); - + + if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { + /* When requeue fails skb is dropped */ + sch->q.qlen--; + sch->stats.backlog -= len; + sch->stats.drops++; + } + sch->flags |= TCQ_F_THROTTLED; sch->stats.overlimits++; } return NULL; } - -static void -tbf_reset(struct Qdisc* sch) +static void tbf_reset(struct Qdisc* sch) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + qdisc_reset(q->qdisc); skb_queue_purge(&sch->q); sch->stats.backlog = 0; PSCHED_GET_TIME(q->t_c); @@ -268,6 +277,31 @@ tbf_reset(struct Qdisc* sch) del_timer(&q->wd_timer); } +static struct Qdisc *tbf_create_dflt_qdisc(struct net_device *dev, u32 limit) +{ + struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops); + struct rtattr *rta; + int ret; + + if (q) { + rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); + if (rta) { + rta->rta_type = RTM_NEWQDISC; + rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); + ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + + ret = q->ops->change(q, rta); + kfree(rta); + + if (ret == 0) + return q; + } + qdisc_destroy(q); + } + + return NULL; +} + static int tbf_change(struct Qdisc* sch, struct rtattr *opt) { int err = -EINVAL; @@ -276,6 +310,7 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt) struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; + struct Qdisc *child = NULL; int max_size,n; if (rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || @@ -308,8 +343,14 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt) } if (max_size < 0) goto done; + + if (q->qdisc == &noop_qdisc) { + if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) + goto done; + } sch_tree_lock(sch); + if (child) q->qdisc = child; q->limit = qopt->limit; q->mtu = qopt->mtu; q->max_size = max_size; @@ -339,6 +380,8 @@ static int tbf_init(struct Qdisc* sch, struct rtattr *opt) init_timer(&q->wd_timer); q->wd_timer.function = tbf_watchdog; q->wd_timer.data = (unsigned long)sch; + + q->qdisc = &noop_qdisc; return tbf_change(sch, opt); } @@ -353,6 +396,9 @@ static void tbf_destroy(struct Qdisc *sch) qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); + + qdisc_destroy(q->qdisc); + q->qdisc = &noop_qdisc; } static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb) @@ -383,9 +429,92 @@ rtattr_failure: return -1; } +static int tbf_dump_class(struct Qdisc *sch, unsigned long cl, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct tbf_sched_data *q = (struct tbf_sched_data*)sch->data; + + if (cl != 1) /* only one class */ + return -ENOENT; + + tcm->tcm_parent = TC_H_ROOT; + tcm->tcm_handle = 1; + tcm->tcm_info = q->qdisc->handle; + + return 0; +} + +static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, + struct Qdisc **old) +{ + struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + + if (new == NULL) + new = &noop_qdisc; + + sch_tree_lock(sch); + *old = xchg(&q->qdisc, new); + qdisc_reset(*old); + sch_tree_unlock(sch); + + return 0; +} + +static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg) +{ + struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + return q->qdisc; +} + +static unsigned long tbf_get(struct Qdisc *sch, u32 classid) +{ + return 1; +} + +static void tbf_put(struct Qdisc *sch, unsigned long arg) +{ +} + +static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + struct rtattr **tca, unsigned long *arg) +{ + return -ENOSYS; +} + +static int tbf_delete(struct Qdisc *sch, unsigned long arg) +{ + return -ENOSYS; +} + +static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) +{ + struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; + + if (!walker->stop) { + if (walker->count >= walker->skip) + if (walker->fn(sch, (unsigned long)q, walker) < 0) { + walker->stop = 1; + return; + } + walker->count++; + } +} + +static struct Qdisc_class_ops tbf_class_ops = +{ + .graft = tbf_graft, + .leaf = tbf_leaf, + .get = tbf_get, + .put = tbf_put, + .change = tbf_change_class, + .delete = tbf_delete, + .walk = tbf_walk, + .dump = tbf_dump_class, +}; + struct Qdisc_ops tbf_qdisc_ops = { .next = NULL, - .cl_ops = NULL, + .cl_ops = &tbf_class_ops, .id = "tbf", .priv_size = sizeof(struct tbf_sched_data), .enqueue = tbf_enqueue, @@ -397,6 +526,7 @@ struct Qdisc_ops tbf_qdisc_ops = { .destroy = tbf_destroy, .change = tbf_change, .dump = tbf_dump, + .owner = THIS_MODULE, }; diff --git a/net/socket.c b/net/socket.c index 41106a676d6..74fd11fdd7a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1614,7 +1614,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) goto out; /* do not move before msg_sys is valid */ - err = -EINVAL; + err = -EMSGSIZE; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; @@ -1713,7 +1713,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag if (!sock) goto out; - err = -EINVAL; + err = -EMSGSIZE; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 64b97aec031..f249d4388e3 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -594,7 +594,7 @@ static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd); if (err) goto fail; - err = permission(nd.dentry->d_inode,MAY_WRITE); + err = permission(nd.dentry->d_inode,MAY_WRITE, &nd); if (err) goto put_fail; diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index f33bf229862..ba98f7f0f98 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -922,6 +922,8 @@ EXPORT_SYMBOL(wanrouter_type_trans); EXPORT_SYMBOL(lock_adapter_irq); EXPORT_SYMBOL(unlock_adapter_irq); +MODULE_LICENSE("GPL"); + /* * End */ diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 5a0fb48be99..dcfd387ab32 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -80,22 +80,24 @@ int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) { - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); + struct xfrm_policy_afinfo *afinfo; struct xfrm_type_map *typemap; struct xfrm_type *type; int modload_attempted = 0; +retry: + afinfo = xfrm_policy_get_afinfo(family); if (unlikely(afinfo == NULL)) return NULL; typemap = afinfo->type_map; -retry: read_lock(&typemap->lock); type = typemap->map[proto]; if (unlikely(type && !try_module_get(type->owner))) type = NULL; read_unlock(&typemap->lock); if (!type && !modload_attempted) { + xfrm_policy_put_afinfo(afinfo); request_module("xfrm-type-%d-%d", (int) family, (int) proto); modload_attempted = 1; @@ -141,11 +143,14 @@ static void xfrm_policy_timer(unsigned long data) struct xfrm_policy *xp = (struct xfrm_policy*)data; unsigned long now = (unsigned long)xtime.tv_sec; long next = LONG_MAX; - u32 index; + int warn = 0; + int dir; if (xp->dead) goto out; + dir = xp->index & 7; + if (xp->lft.hard_add_expires_seconds) { long tmo = xp->lft.hard_add_expires_seconds + xp->curlft.add_time - now; @@ -154,6 +159,37 @@ static void xfrm_policy_timer(unsigned long data) if (tmo < next) next = tmo; } + if (xp->lft.hard_use_expires_seconds) { + long tmo = xp->lft.hard_use_expires_seconds + + (xp->curlft.use_time ? : xp->curlft.add_time) - now; + if (tmo <= 0) + goto expired; + if (tmo < next) + next = tmo; + } + if (xp->lft.soft_add_expires_seconds) { + long tmo = xp->lft.soft_add_expires_seconds + + xp->curlft.add_time - now; + if (tmo <= 0) { + warn = 1; + tmo = XFRM_KM_TIMEOUT; + } + if (tmo < next) + next = tmo; + } + if (xp->lft.soft_use_expires_seconds) { + long tmo = xp->lft.soft_use_expires_seconds + + (xp->curlft.use_time ? : xp->curlft.add_time) - now; + if (tmo <= 0) { + warn = 1; + tmo = XFRM_KM_TIMEOUT; + } + if (tmo < next) + next = tmo; + } + + if (warn) + km_policy_expired(xp, dir, 0); if (next != LONG_MAX && !mod_timer(&xp->timer, jiffies + make_jiffies(next))) xfrm_pol_hold(xp); @@ -163,14 +199,9 @@ out: return; expired: - index = xp->index; + km_policy_expired(xp, dir, 1); + xfrm_policy_delete(xp, dir); xfrm_pol_put(xp); - - /* Not 100% correct. id can be recycled in theory */ - xp = xfrm_policy_byid(0, index, 1); - if (xp) { - xfrm_policy_kill(xp); - } } @@ -321,8 +352,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) policy->index = delpol ? delpol->index : xfrm_gen_index(dir); policy->curlft.add_time = (unsigned long)xtime.tv_sec; policy->curlft.use_time = 0; - if (policy->lft.hard_add_expires_seconds && - !mod_timer(&policy->timer, jiffies + HZ)) + if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); @@ -340,18 +370,18 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) { + xfrm_pol_hold(pol); if (delete) *p = pol->next; break; } } - if (pol) { - if (delete) - atomic_inc(&flow_cache_genid); - else - xfrm_pol_hold(pol); - } write_unlock_bh(&xfrm_policy_lock); + + if (pol && delete) { + atomic_inc(&flow_cache_genid); + xfrm_policy_kill(pol); + } return pol; } @@ -362,18 +392,18 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[id & 7]; (pol=*p)!=NULL; p = &pol->next) { if (pol->index == id) { + xfrm_pol_hold(pol); if (delete) *p = pol->next; break; } } - if (pol) { - if (delete) - atomic_inc(&flow_cache_genid); - else - xfrm_pol_hold(pol); - } write_unlock_bh(&xfrm_policy_lock); + + if (pol && delete) { + atomic_inc(&flow_cache_genid); + xfrm_policy_kill(pol); + } return pol; } @@ -473,25 +503,36 @@ struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi return pol; } -void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) +static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) { - pol->next = xfrm_policy_list[XFRM_POLICY_MAX+dir]; - xfrm_policy_list[XFRM_POLICY_MAX+dir] = pol; + pol->next = xfrm_policy_list[dir]; + xfrm_policy_list[dir] = pol; xfrm_pol_hold(pol); } -void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) +static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, + int dir) { struct xfrm_policy **polp; - for (polp = &xfrm_policy_list[XFRM_POLICY_MAX+dir]; + for (polp = &xfrm_policy_list[dir]; *polp != NULL; polp = &(*polp)->next) { if (*polp == pol) { *polp = pol->next; atomic_dec(&pol->refcnt); - return; + return pol; } } + return NULL; +} + +void xfrm_policy_delete(struct xfrm_policy *pol, int dir) +{ + write_lock_bh(&xfrm_policy_lock); + pol = __xfrm_policy_unlink(pol, dir); + write_unlock_bh(&xfrm_policy_lock); + if (pol) + xfrm_policy_kill(pol); } int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) @@ -504,10 +545,10 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) if (pol) { pol->curlft.add_time = (unsigned long)xtime.tv_sec; pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); - xfrm_sk_policy_link(pol, dir); + __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); } if (old_pol) - xfrm_sk_policy_unlink(old_pol, dir); + __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); write_unlock_bh(&xfrm_policy_lock); if (old_pol) { @@ -531,7 +572,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); write_lock_bh(&xfrm_policy_lock); - xfrm_sk_policy_link(newp, dir); + __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); write_unlock_bh(&xfrm_policy_lock); } return newp; @@ -550,15 +591,6 @@ int __xfrm_sk_clone_policy(struct sock *sk) return 0; } -void __xfrm_sk_free_policy(struct xfrm_policy *pol, int dir) -{ - write_lock_bh(&xfrm_policy_lock); - xfrm_sk_policy_unlink(pol, dir); - write_unlock_bh(&xfrm_policy_lock); - - xfrm_policy_kill(pol); -} - /* Resolve list of templates for the flow, given policy. */ static int @@ -758,8 +790,10 @@ restart: goto error; } if (err == -EAGAIN || - genid != atomic_read(&flow_cache_genid)) + genid != atomic_read(&flow_cache_genid)) { + xfrm_pol_put(policy); goto restart; + } } if (err) goto error; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 401fc996d9f..571a80f3981 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -140,7 +140,7 @@ static void xfrm_timer_handler(unsigned long data) } if (warn) - km_warn_expired(x); + km_state_expired(x, 0); resched: if (next != LONG_MAX && !mod_timer(&x->timer, jiffies + make_jiffies(next))) @@ -155,7 +155,7 @@ expired: goto resched; } if (x->id.spi != 0) - km_expired(x); + km_state_expired(x, 1); __xfrm_state_delete(x); out: @@ -512,7 +512,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) if (x->curlft.bytes >= x->lft.hard_byte_limit || x->curlft.packets >= x->lft.hard_packet_limit) { - km_expired(x); + km_state_expired(x, 1); if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) xfrm_state_hold(x); return -EINVAL; @@ -521,7 +521,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) if (!x->km.dying && (x->curlft.bytes >= x->lft.soft_byte_limit || x->curlft.packets >= x->lft.soft_packet_limit)) - km_warn_expired(x); + km_state_expired(x, 0); return 0; } @@ -737,28 +737,22 @@ int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl) static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list); static rwlock_t xfrm_km_lock = RW_LOCK_UNLOCKED; -void km_warn_expired(struct xfrm_state *x) +void km_state_expired(struct xfrm_state *x, int hard) { struct xfrm_mgr *km; - x->km.dying = 1; - read_lock(&xfrm_km_lock); - list_for_each_entry(km, &xfrm_km_list, list) - km->notify(x, 0); - read_unlock(&xfrm_km_lock); -} - -void km_expired(struct xfrm_state *x) -{ - struct xfrm_mgr *km; - - x->km.state = XFRM_STATE_EXPIRED; + if (hard) + x->km.state = XFRM_STATE_EXPIRED; + else + x->km.dying = 1; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) - km->notify(x, 1); + km->notify(x, hard); read_unlock(&xfrm_km_lock); - wake_up(&km_waitq); + + if (hard) + wake_up(&km_waitq); } int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) @@ -792,6 +786,20 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) return err; } +void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) +{ + struct xfrm_mgr *km; + + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) + if (km->notify_policy) + km->notify_policy(pol, dir, hard); + read_unlock(&xfrm_km_lock); + + if (hard) + wake_up(&km_waitq); +} + int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen) { int err; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c946e5ae5a1..ce9a5738a49 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -783,9 +783,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr if (xp == NULL) return -ENOENT; - if (delete) - xfrm_policy_kill(xp); - else { + if (!delete) { struct sk_buff *resp_skb; resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); @@ -796,9 +794,10 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr NETLINK_CB(skb).pid, MSG_DONTWAIT); } - xfrm_pol_put(xp); } + xfrm_pol_put(xp); + return err; } @@ -994,7 +993,7 @@ nlmsg_failure: return -1; } -static int xfrm_send_notify(struct xfrm_state *x, int hard) +static int xfrm_send_state_notify(struct xfrm_state *x, int hard) { struct sk_buff *skb; @@ -1120,11 +1119,56 @@ struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, return xp; } +static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, + int dir, int hard) +{ + struct xfrm_user_polexpire *upe; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + + nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); + upe = NLMSG_DATA(nlh); + nlh->nlmsg_flags = 0; + + copy_to_user_policy(xp, &upe->pol, dir); + if (copy_to_user_tmpl(xp, skb) < 0) + goto nlmsg_failure; + upe->hard = !!hard; + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +nlmsg_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard) +{ + struct sk_buff *skb; + size_t len; + + len = sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr; + len = RTA_ALIGN(RTA_LENGTH(len)); + len += NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info))); + skb = alloc_skb(len, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (build_polexpire(skb, xp, dir, hard) < 0) + BUG(); + + NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE; + + return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC); +} + static struct xfrm_mgr netlink_mgr = { .id = "netlink", - .notify = xfrm_send_notify, + .notify = xfrm_send_state_notify, .acquire = xfrm_send_acquire, .compile_policy = xfrm_compile_policy, + .notify_policy = xfrm_send_policy_notify, }; static int __init xfrm_user_init(void) diff --git a/scripts/ver_linux b/scripts/ver_linux index 99cb2c9f5ae..26f3084e7db 100644 --- a/scripts/ver_linux +++ b/scripts/ver_linux @@ -45,6 +45,9 @@ xfs_db -V 2>&1 | grep version | awk \ cardmgr -V 2>&1| grep version | awk \ 'NR==1{print "pcmcia-cs ", $3}' +quota -V 2>&1 | grep version | awk \ +'NR==1{print "quota-tools ", $NF}' + pppd --version 2>&1| grep version | awk \ 'NR==1{print "PPP ", $3}' diff --git a/security/capability.c b/security/capability.c index e01bc5271c3..cff54dd440f 100644 --- a/security/capability.c +++ b/security/capability.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -275,6 +278,65 @@ int cap_syslog (int type) return 0; } +/* + * Check that a process has enough memory to allocate a new virtual + * mapping. 0 means there is enough memory for the allocation to + * succeed and -ENOMEM implies there is not. + * + * We currently support three overcommit policies, which are set via the + * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-acounting + * + * Strict overcommit modes added 2002 Feb 26 by Alan Cox. + * Additional code 2002 Jul 20 by Robert Love. + */ +int cap_vm_enough_memory(long pages) +{ + unsigned long free, allowed; + + vm_acct_memory(pages); + + /* + * Sometimes we want to use more memory than we have + */ + if (sysctl_overcommit_memory == 1) + return 0; + + if (sysctl_overcommit_memory == 0) { + free = get_page_cache_size(); + free += nr_free_pages(); + free += nr_swap_pages; + + /* + * Any slabs which are created with the + * SLAB_RECLAIM_ACCOUNT flag claim to have contents + * which are reclaimable, under pressure. The dentry + * cache and most inode caches should fall into this + */ + free += atomic_read(&slab_reclaim_pages); + + /* + * Leave the last 3% for root + */ + if (!capable(CAP_SYS_ADMIN)) + free -= free / 32; + + if (free > pages) + return 0; + vm_unacct_memory(pages); + return -ENOMEM; + } + + allowed = totalram_pages * sysctl_overcommit_ratio / 100; + allowed += total_swap_pages; + + if (atomic_read(&vm_committed_space) < allowed) + return 0; + + vm_unacct_memory(pages); + + return -ENOMEM; +} + EXPORT_SYMBOL(cap_capable); EXPORT_SYMBOL(cap_ptrace); EXPORT_SYMBOL(cap_capget); @@ -286,6 +348,7 @@ EXPORT_SYMBOL(cap_bprm_secureexec); EXPORT_SYMBOL(cap_task_post_setuid); EXPORT_SYMBOL(cap_task_reparent_to_init); EXPORT_SYMBOL(cap_syslog); +EXPORT_SYMBOL(cap_vm_enough_memory); #ifdef CONFIG_SECURITY @@ -307,6 +370,8 @@ static struct security_operations capability_ops = { .task_reparent_to_init = cap_task_reparent_to_init, .syslog = cap_syslog, + + .vm_enough_memory = cap_vm_enough_memory, }; #if defined(CONFIG_SECURITY_CAPABILITIES_MODULE) diff --git a/security/dummy.c b/security/dummy.c index a4307e78a16..76c6560a76c 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -97,6 +100,54 @@ static int dummy_syslog (int type) return 0; } +static int dummy_vm_enough_memory(long pages) +{ + unsigned long free, allowed; + + vm_acct_memory(pages); + + /* + * Sometimes we want to use more memory than we have + */ + if (sysctl_overcommit_memory == 1) + return 0; + + if (sysctl_overcommit_memory == 0) { + free = get_page_cache_size(); + free += nr_free_pages(); + free += nr_swap_pages; + + /* + * Any slabs which are created with the + * SLAB_RECLAIM_ACCOUNT flag claim to have contents + * which are reclaimable, under pressure. The dentry + * cache and most inode caches should fall into this + */ + free += atomic_read(&slab_reclaim_pages); + + /* + * Leave the last 3% for root + */ + if (current->euid) + free -= free / 32; + + if (free > pages) + return 0; + vm_unacct_memory(pages); + return -ENOMEM; + } + + allowed = totalram_pages * sysctl_overcommit_ratio / 100; + allowed += total_swap_pages; + + if (atomic_read(&vm_committed_space) < allowed) + return 0; + + vm_unacct_memory(pages); + + return -ENOMEM; +} + static int dummy_bprm_alloc_security (struct linux_binprm *bprm) { return 0; @@ -793,6 +844,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, quota_on); set_to_dummy_if_null(ops, sysctl); set_to_dummy_if_null(ops, syslog); + set_to_dummy_if_null(ops, vm_enough_memory); set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); set_to_dummy_if_null(ops, bprm_compute_creds); diff --git a/usr/Makefile b/usr/Makefile index 58a915ee7fe..74279455813 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -5,11 +5,9 @@ host-progs := gen_init_cpio clean-files := initramfs_data.cpio.gz -LDFLAGS_initramfs_data.o := $(LDFLAGS_BLOB) -r -T - -$(obj)/initramfs_data.o: $(src)/initramfs_data.scr \ - $(obj)/initramfs_data.cpio.gz FORCE - $(call if_changed,ld) +$(src)/initramfs_data.S: $(obj)/initramfs_data.cpio.gz + echo " .section .init.ramfs,\"a\"" > $(src)/initramfs_data.S + echo ".incbin \"usr/initramfs_data.cpio.gz\"" >> $(src)/initramfs_data.S # initramfs-y are the programs which will be copied into the CPIO # archive. Currently, the filenames are hardcoded in gen_init_cpio, diff --git a/usr/initramfs_data.scr b/usr/initramfs_data.scr deleted file mode 100644 index bf6d172329e..00000000000 --- a/usr/initramfs_data.scr +++ /dev/null @@ -1,4 +0,0 @@ -SECTIONS -{ - .init.ramfs : { *(.data) } -} -- 2.11.4.GIT