Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 11 May 2007 16:56:05 +0000 (09:56 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 11 May 2007 16:56:05 +0000 (09:56 -0700)
* 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid:
  USB HID: hiddev - fix race between hiddev_send_event() and hiddev_release()
  HID: add hooks for getkeycode() and setkeycode() methods
  HID: switch to using input_dev->dev.parent
  USB HID: Logitech wheel 0x046d/0xc294 needs HID_QUIRK_NOGET quirk
  USB HID: usb_buffer_free() cleanup
  USB HID: report descriptor of Cypress USB barcode readers needs fixup
  Bluetooth HID: HIDP - don't initialize force feedback
  USB HID: update CONFIG_USB_HIDINPUT_POWERBOOK description
  HID: add input mappings for non-working keys on Logitech S510 remote

1417 files changed:
CREDITS
Documentation/ABI/removed/devfs
Documentation/DocBook/kernel-api.tmpl
Documentation/MSI-HOWTO.txt
Documentation/SubmitChecklist
Documentation/SubmittingPatches
Documentation/arm/Interrupts
Documentation/arm/Samsung-S3C24XX/H1940.txt
Documentation/auxdisplay/cfag12864b
Documentation/binfmt_misc.txt
Documentation/block/ioprio.txt
Documentation/cpu-freq/cpufreq-stats.txt
Documentation/cpu-hotplug.txt
Documentation/crypto/api-intro.txt
Documentation/device-mapper/delay.txt [new file with mode: 0644]
Documentation/driver-model/platform.txt
Documentation/dvb/README.dvb-usb
Documentation/dvb/contributors.txt
Documentation/fb/arkfb.txt [new file with mode: 0644]
Documentation/fb/aty128fb.txt
Documentation/fb/framebuffer.txt
Documentation/fb/imacfb.txt
Documentation/fb/sstfb.txt
Documentation/fb/vt8623fb.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/hpfs.txt
Documentation/filesystems/ntfs.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/relay.txt
Documentation/filesystems/xip.txt
Documentation/fujitsu/frv/gdbstub.txt
Documentation/gpio.txt
Documentation/hwmon/adm1026
Documentation/hwmon/gl518sm
Documentation/hwmon/lm83
Documentation/hwmon/sis5595
Documentation/hwmon/via686a
Documentation/hwmon/w83792d
Documentation/i2c/busses/i2c-i810
Documentation/i2c/busses/i2c-sis96x
Documentation/i2c/busses/i2c-via
Documentation/i2c/busses/i2c-viapro
Documentation/i2c/i2c-protocol
Documentation/i2o/README
Documentation/i386/boot.txt
Documentation/input/atarikbd.txt
Documentation/input/xpad.txt
Documentation/isdn/CREDITS
Documentation/isdn/README
Documentation/isdn/README.icn
Documentation/java.txt
Documentation/kernel-docs.txt
Documentation/kernel-parameters.txt
Documentation/m68k/README.buddha
Documentation/magic-number.txt
Documentation/md.txt
Documentation/netlabel/introduction.txt
Documentation/networking/6pack.txt
Documentation/networking/NAPI_HOWTO.txt
Documentation/networking/packet_mmap.txt
Documentation/networking/slicecom.hun
Documentation/networking/slicecom.txt
Documentation/networking/tms380tr.txt
Documentation/networking/udplite.txt
Documentation/networking/wan-router.txt
Documentation/pci.txt
Documentation/pcieaer-howto.txt
Documentation/pnp.txt
Documentation/power/swsusp.txt
Documentation/power/userland-swsusp.txt
Documentation/powerpc/booting-without-of.txt
Documentation/s390/Debugging390.txt
Documentation/scsi/aacraid.txt
Documentation/scsi/aha152x.txt
Documentation/scsi/aic7xxx.txt
Documentation/scsi/aic7xxx_old.txt
Documentation/scsi/ncr53c8xx.txt
Documentation/scsi/st.txt
Documentation/scsi/sym53c8xx_2.txt
Documentation/scsi/tmscsim.txt
Documentation/sonypi.txt
Documentation/sound/oss/mwave
Documentation/sysctl/kernel.txt
Documentation/usb/CREDITS
Documentation/usb/usb-serial.txt
Documentation/video4linux/README.pvrusb2
Documentation/video4linux/Zoran
Documentation/video4linux/meye.txt
Documentation/video4linux/ov511.txt
Documentation/vm/slabinfo.c
MAINTAINERS
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/init_task.c
arch/arm/kernel/module.c
arch/arm/kernel/smp.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/io.c
arch/arm/mach-omap1/mailbox.c [new file with mode: 0644]
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mailbox.c [new file with mode: 0644]
arch/arm/mach-s3c2410/sleep.S
arch/arm/mm/Kconfig
arch/arm/mm/Makefile
arch/arm/mm/abort-ev7.S [new file with mode: 0644]
arch/arm/mm/cache-v7.S [new file with mode: 0644]
arch/arm/mm/context.c
arch/arm/mm/proc-macros.S
arch/arm/mm/proc-v7.S [new file with mode: 0644]
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/clock.c
arch/arm/plat-omap/common.c
arch/arm/plat-omap/debug-leds.c [new file with mode: 0644]
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/mailbox.c [new file with mode: 0644]
arch/arm/plat-omap/mailbox.h [new file with mode: 0644]
arch/arm/plat-omap/sram.c
arch/arm/plat-omap/usb.c
arch/arm/plat-s3c24xx/sleep.S
arch/avr32/Makefile
arch/avr32/kernel/process.c
arch/avr32/kernel/ptrace.c
arch/avr32/kernel/syscall_table.S
arch/avr32/kernel/traps.c
arch/avr32/kernel/vmlinux.lds.c
arch/avr32/mach-at32ap/clock.c
arch/avr32/mm/dma-coherent.c
arch/blackfin/kernel/asm-offsets.c
arch/blackfin/kernel/ptrace.c
arch/cris/arch-v32/drivers/Kconfig
arch/frv/Kconfig
arch/frv/kernel/entry.S
arch/frv/kernel/gdb-stub.c
arch/frv/kernel/process.c
arch/frv/kernel/setup.c
arch/frv/mm/elf-fdpic.c
arch/frv/mm/pgalloc.c
arch/h8300/Kconfig.debug
arch/h8300/kernel/asm-offsets.c
arch/h8300/kernel/syscalls.S
arch/i386/Kconfig
arch/i386/Kconfig.cpu
arch/i386/boot/video.S
arch/i386/kernel/cpu/intel_cacheinfo.c
arch/i386/kernel/cpu/mcheck/therm_throt.c
arch/i386/kernel/cpu/transmeta.c
arch/i386/kernel/cpuid.c
arch/i386/kernel/head.S
arch/i386/kernel/microcode.c
arch/i386/kernel/msr.c
arch/i386/kernel/paravirt.c
arch/i386/kernel/syscall_table.S
arch/i386/kernel/traps.c
arch/i386/kernel/vmlinux.lds.S
arch/i386/mach-generic/probe.c
arch/i386/mach-voyager/voyager_basic.c
arch/i386/pci/init.c
arch/ia64/Kconfig
arch/ia64/ia32/ia32_entry.S
arch/ia64/ia32/ia32_signal.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/err_inject.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/process.c
arch/ia64/kernel/relocate_kernel.S
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/sigframe.h
arch/ia64/kernel/signal.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/topology.c
arch/ia64/kernel/traps.c
arch/ia64/kernel/unwind.c
arch/ia64/mm/tlb.c
arch/ia64/sn/kernel/irq.c
arch/ia64/sn/kernel/sn2/sn2_smp.c
arch/m32r/Kconfig
arch/m32r/mm/mmu.S
arch/m68knommu/Kconfig.debug
arch/m68knommu/kernel/asm-offsets.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/smtc.c
arch/mips/pci/fixup-sb1250.c
arch/parisc/kernel/asm-offsets.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/boot/dts/mpc832x_mds.dts
arch/powerpc/boot/dts/mpc834x_mds.dts
arch/powerpc/configs/celleb_defconfig
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/lparmap.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/swsusp.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/lib/Makefile
arch/powerpc/lib/rheap.c
arch/powerpc/mm/Makefile
arch/powerpc/mm/hash_low_64.S
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_context_64.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/ppc_mmu_32.c
arch/powerpc/mm/slb.c
arch/powerpc/mm/slb_low.S
arch/powerpc/mm/slice.c [new file with mode: 0644]
arch/powerpc/mm/tlb_32.c
arch/powerpc/mm/tlb_64.c
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/platforms/83xx/mpc8313_rdb.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc834x_itx.c
arch/powerpc/platforms/83xx/mpc834x_mds.c
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
arch/powerpc/platforms/86xx/mpc86xx_smp.c
arch/powerpc/platforms/8xx/mpc86xads_setup.c
arch/powerpc/platforms/8xx/mpc885ads_setup.c
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/io-workarounds.c
arch/powerpc/platforms/cell/pervasive.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spufs/Makefile
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/lscsa_alloc.c [new file with mode: 0644]
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/celleb/pci.c
arch/powerpc/platforms/celleb/scc_epci.c
arch/powerpc/platforms/celleb/setup.c
arch/powerpc/platforms/iseries/Kconfig
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/kexec.c
arch/powerpc/sysdev/commproc.c
arch/powerpc/sysdev/cpm2_common.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/powerpc/sysdev/qe_lib/ucc_fast.c
arch/powerpc/sysdev/qe_lib/ucc_slow.c
arch/ppc/8xx_io/commproc.c
arch/ppc/kernel/asm-offsets.c
arch/ppc/lib/Makefile
arch/ppc/lib/rheap.c [deleted file]
arch/ppc/platforms/mpc866ads_setup.c
arch/ppc/syslib/cpm2_common.c
arch/ppc/syslib/ipic.c
arch/s390/Kconfig
arch/s390/appldata/appldata_base.c
arch/s390/crypto/Kconfig
arch/s390/defconfig
arch/s390/hypfs/inode.c
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/ipl.c
arch/s390/kernel/smp.c
arch/s390/mm/fault.c
arch/sh/Kconfig
arch/sh/boards/landisk/setup.c
arch/sh/boards/se/7751/setup.c
arch/sh/drivers/Makefile
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/dma/Makefile
arch/sh/drivers/dma/dmabrg.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/Makefile
arch/sh/kernel/cpu/sh2a/opcode_helper.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2a/probe.c
arch/sh/kernel/cpu/sh3/entry.S
arch/sh/kernel/cpu/sh3/ex.S
arch/sh/kernel/cpu/sh4/Makefile
arch/sh/kernel/cpu/sh4/ex.S [deleted file]
arch/sh/kernel/cpu/sh4/fpu.c
arch/sh/kernel/cpu/sh4a/clock-sh73180.c
arch/sh/kernel/cpu/sh4a/clock-sh7343.c
arch/sh/kernel/cpu/sh4a/clock-sh7770.c
arch/sh/kernel/cpu/sh4a/clock-sh7780.c
arch/sh/kernel/process.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/signal.c
arch/sh/kernel/stacktrace.c
arch/sh/kernel/syscalls.S
arch/sh/kernel/time.c
arch/sh/kernel/timers/timer-tmu.c
arch/sh/kernel/traps.c
arch/sh/kernel/vsyscall/vsyscall.c
arch/sh/lib/delay.c
arch/sh/mm/Kconfig
arch/sh/mm/fault.c
arch/sh/mm/init.c
arch/sparc/kernel/asm-offsets.c
arch/sparc/kernel/systbls.S
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/kprobes.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_common.c
arch/sparc64/kernel/pci_fire.c
arch/sparc64/kernel/pci_impl.h
arch/sparc64/kernel/pci_iommu.c
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/prom.c
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/traps.c
arch/sparc64/mm/fault.c
arch/um/Kconfig
arch/um/Kconfig.scsi [deleted file]
arch/um/defconfig
arch/um/include/common-offsets.h
arch/um/include/kern_util.h
arch/um/include/os.h
arch/um/include/sysdep-i386/archsetjmp.h
arch/um/include/sysdep-x86_64/archsetjmp.h
arch/um/kernel/dyn.lds.S
arch/um/kernel/init_task.c
arch/um/kernel/irq.c
arch/um/kernel/skas/process.c
arch/um/kernel/tt/exec_kern.c
arch/um/kernel/tt/process_kern.c
arch/um/kernel/um_arch.c
arch/um/kernel/uml.lds.S
arch/um/os-Linux/process.c
arch/um/os-Linux/signal.c
arch/um/os-Linux/skas/mem.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/sys-i386/signal.c
arch/um/os-Linux/sys-x86_64/signal.c
arch/um/os-Linux/util.c
arch/v850/kernel/asm-offsets.c
arch/v850/kernel/entry.S
arch/x86_64/ia32/ia32entry.S
arch/x86_64/kernel/head64.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/irq.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/mce_amd.c
arch/x86_64/kernel/traps.c
arch/x86_64/kernel/vsyscall.c
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/pci-dma.c
block/as-iosched.c
block/genhd.c
block/ll_rw_blk.c
crypto/Kconfig
crypto/cryptomgr.c
drivers/Makefile
drivers/acpi/dispatcher/dsmethod.c
drivers/acpi/dispatcher/dsopcode.c
drivers/acpi/dispatcher/dsutils.c
drivers/acpi/dispatcher/dswstate.c
drivers/acpi/ec.c
drivers/acpi/events/evgpe.c
drivers/acpi/events/evgpeblk.c
drivers/acpi/events/evmisc.c
drivers/acpi/events/evregion.c
drivers/acpi/events/evrgnini.c
drivers/acpi/events/evxface.c
drivers/acpi/events/evxfevnt.c
drivers/acpi/executer/exconvrt.c
drivers/acpi/executer/excreate.c
drivers/acpi/executer/exdump.c
drivers/acpi/executer/exmutex.c
drivers/acpi/executer/exnames.c
drivers/acpi/executer/exprep.c
drivers/acpi/executer/exresop.c
drivers/acpi/executer/exsystem.c
drivers/acpi/executer/exutils.c
drivers/acpi/hardware/hwsleep.c
drivers/acpi/namespace/nseval.c
drivers/acpi/namespace/nsinit.c
drivers/acpi/namespace/nswalk.c
drivers/acpi/namespace/nsxfeval.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/parser/psopcode.c
drivers/acpi/resources/rscalc.c
drivers/acpi/resources/rscreate.c
drivers/acpi/resources/rsdump.c
drivers/acpi/resources/rsinfo.c
drivers/acpi/resources/rslist.c
drivers/acpi/resources/rsmisc.c
drivers/acpi/resources/rsutils.c
drivers/acpi/resources/rsxface.c
drivers/acpi/sleep/main.c
drivers/acpi/sleep/proc.c
drivers/acpi/tables/tbfadt.c
drivers/acpi/tables/tbxface.c
drivers/acpi/thermal.c
drivers/acpi/utilities/utalloc.c
drivers/acpi/utilities/utcache.c
drivers/acpi/utilities/utcopy.c
drivers/acpi/utilities/utdebug.c
drivers/acpi/utilities/utdelete.c
drivers/acpi/utilities/utglobal.c
drivers/acpi/utilities/utmisc.c
drivers/acpi/utilities/utmutex.c
drivers/acpi/utilities/utresrc.c
drivers/acpi/utilities/utxface.c
drivers/ata/Kconfig
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_qdi.c
drivers/ata/pata_scc.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_via.c
drivers/auxdisplay/Kconfig
drivers/base/devres.c
drivers/base/platform.c
drivers/base/topology.c
drivers/block/Kconfig
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/rd.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_uart.h
drivers/char/Kconfig
drivers/char/drm/drm_dma.c
drivers/char/drm/drm_vm.c
drivers/char/drm/r300_reg.h
drivers/char/genrtc.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/pasemi-rng.c [new file with mode: 0644]
drivers/char/ipmi/Kconfig
drivers/char/mmtimer.c
drivers/char/n_tty.c
drivers/char/pcmcia/Kconfig
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/rio/riocmd.c
drivers/char/rocket.c
drivers/char/rocket_int.h
drivers/char/synclink_gt.c
drivers/char/tpm/Kconfig
drivers/char/tty_io.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/cpu5wdt.c
drivers/char/watchdog/eurotechwdt.c
drivers/char/watchdog/i8xx_tco.c [deleted file]
drivers/char/watchdog/i8xx_tco.h [deleted file]
drivers/char/watchdog/ibmasr.c
drivers/char/watchdog/machzwd.c
drivers/char/watchdog/mtx-1_wdt.c [new file with mode: 0644]
drivers/char/watchdog/pcwd.c
drivers/char/watchdog/pcwd_usb.c
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/sbc8360.c
drivers/char/watchdog/w83627hf_wdt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/crypto/Kconfig
drivers/dma/Kconfig
drivers/edac/Kconfig
drivers/firewire/Kconfig [new file with mode: 0644]
drivers/firewire/Makefile [new file with mode: 0644]
drivers/firewire/fw-card.c [new file with mode: 0644]
drivers/firewire/fw-cdev.c [new file with mode: 0644]
drivers/firewire/fw-device.c [new file with mode: 0644]
drivers/firewire/fw-device.h [new file with mode: 0644]
drivers/firewire/fw-iso.c [new file with mode: 0644]
drivers/firewire/fw-ohci.c [new file with mode: 0644]
drivers/firewire/fw-ohci.h [new file with mode: 0644]
drivers/firewire/fw-sbp2.c [new file with mode: 0644]
drivers/firewire/fw-topology.c [new file with mode: 0644]
drivers/firewire/fw-topology.h [new file with mode: 0644]
drivers/firewire/fw-transaction.c [new file with mode: 0644]
drivers/firewire/fw-transaction.h [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/ams/ams-input.c
drivers/hwmon/applesmc.c
drivers/hwmon/coretemp.c
drivers/hwmon/hdaps.c
drivers/i2c/Kconfig
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/chips/tps65010.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/arm/bast-ide.c
drivers/ide/arm/icside.c
drivers/ide/arm/ide_arm.c
drivers/ide/arm/rapide.c
drivers/ide/cris/ide-cris.c
drivers/ide/h8300/ide-h8300.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-floppy.c
drivers/ide/ide-generic.c
drivers/ide/ide-io.c
drivers/ide/ide-iops.c
drivers/ide/ide-lib.c
drivers/ide/ide-pnp.c
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide-tape.c
drivers/ide/ide.c
drivers/ide/legacy/ali14xx.c
drivers/ide/legacy/buddha.c
drivers/ide/legacy/dtc2278.c
drivers/ide/legacy/falconide.c
drivers/ide/legacy/gayle.c
drivers/ide/legacy/ht6560b.c
drivers/ide/legacy/ide-cs.c
drivers/ide/legacy/macide.c
drivers/ide/legacy/q40ide.c
drivers/ide/legacy/qd65xx.c
drivers/ide/legacy/umc8672.c
drivers/ide/mips/au1xxx-ide.c
drivers/ide/mips/swarm.c
drivers/ide/pci/aec62xx.c
drivers/ide/pci/alim15x3.c
drivers/ide/pci/amd74xx.c
drivers/ide/pci/atiixp.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/cs5520.c
drivers/ide/pci/cs5535.c
drivers/ide/pci/delkin_cb.c
drivers/ide/pci/hpt34x.c
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c
drivers/ide/pci/it821x.c
drivers/ide/pci/jmicron.c
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/scc_pata.c
drivers/ide/pci/serverworks.c
drivers/ide/pci/sgiioc4.c
drivers/ide/pci/siimage.c
drivers/ide/pci/sis5513.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c
drivers/ide/pci/triflex.c
drivers/ide/ppc/pmac.c
drivers/ide/setup-pci.c
drivers/ieee1394/Kconfig
drivers/ieee1394/nodemgr.c
drivers/infiniband/Kconfig
drivers/infiniband/Makefile
drivers/infiniband/core/Makefile
drivers/infiniband/core/device.c
drivers/infiniband/core/umem.c [moved from drivers/infiniband/core/uverbs_mem.c with 59% similarity]
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/amso1100/c2_provider.c
drivers/infiniband/hw/amso1100/c2_provider.h
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb3/iwch_provider.h
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_mrmw.c
drivers/infiniband/hw/ipath/ipath_mr.c
drivers/infiniband/hw/ipath/ipath_verbs.h
drivers/infiniband/hw/mlx4/Kconfig [new file with mode: 0644]
drivers/infiniband/hw/mlx4/Makefile [new file with mode: 0644]
drivers/infiniband/hw/mlx4/ah.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/cq.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/doorbell.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/mad.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/main.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/mlx4_ib.h [new file with mode: 0644]
drivers/infiniband/hw/mlx4/mr.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/qp.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/srq.c [new file with mode: 0644]
drivers/infiniband/hw/mlx4/user.h [new file with mode: 0644]
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_provider.h
drivers/input/Kconfig
drivers/input/evdev.c
drivers/input/misc/ixp4xx-beeper.c
drivers/isdn/Kconfig
drivers/isdn/capi/Kconfig
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/eicon/divasync.h
drivers/isdn/hisax/hfc_usb.c
drivers/kvm/Kconfig
drivers/kvm/kvm_main.c
drivers/leds/Kconfig
drivers/leds/leds-h1940.c
drivers/macintosh/Kconfig
drivers/macintosh/mediabay.c
drivers/mca/mca-bus.c
drivers/mca/mca-driver.c
drivers/md/Kconfig
drivers/md/Makefile
drivers/md/dm-bio-list.h
drivers/md/dm-crypt.c
drivers/md/dm-delay.c [new file with mode: 0644]
drivers/md/dm-exception-store.c
drivers/md/dm-hw-handler.h
drivers/md/dm-io.c
drivers/md/dm-io.h
drivers/md/dm-log.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/kcopyd.c
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/media/Kconfig
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/tda10021.c
drivers/media/dvb/frontends/ves1x93.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/pwc/philips.txt
drivers/media/video/usbvideo/vicam.c
drivers/message/fusion/Kconfig
drivers/message/fusion/lsi/mpi_history.txt
drivers/message/fusion/mptbase.c
drivers/message/i2o/Kconfig
drivers/mfd/Kconfig
drivers/misc/Kconfig
drivers/misc/asus-laptop.c
drivers/misc/msi-laptop.c
drivers/misc/sony-laptop.c
drivers/misc/tifm_7xx1.c
drivers/mmc/Kconfig
drivers/mmc/card/Kconfig
drivers/mmc/core/Kconfig
drivers/mmc/core/core.c
drivers/mmc/host/Kconfig
drivers/mmc/host/tifm_sd.c
drivers/mtd/Kconfig
drivers/mtd/chips/Kconfig
drivers/mtd/chips/Makefile
drivers/mtd/chips/amd_flash.c [deleted file]
drivers/mtd/chips/jedec.c [deleted file]
drivers/mtd/chips/sharp.c [deleted file]
drivers/mtd/devices/block2mtd.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/arctic-mtd.c [deleted file]
drivers/mtd/maps/beech-mtd.c [deleted file]
drivers/mtd/maps/nettel.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/at91_nand.c
drivers/mtd/nand/cafe_ecc.c [deleted file]
drivers/mtd/nand/cafe_nand.c [moved from drivers/mtd/nand/cafe.c with 88% similarity]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/plat_nand.c [new file with mode: 0644]
drivers/mtd/onenand/onenand_base.c
drivers/net/3c509.c
drivers/net/3c59x.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/atl1/atl1_main.c
drivers/net/atp.c
drivers/net/bonding/bond_main.c
drivers/net/e1000/e1000_main.c
drivers/net/eepro.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/fs_enet/mac-scc.c
drivers/net/hamradio/Kconfig
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/donauboe.h
drivers/net/irda/kingsun-sir.c [new file with mode: 0644]
drivers/net/ixgb/ixgb_ee.c
drivers/net/meth.h
drivers/net/mlx4/Makefile [new file with mode: 0644]
drivers/net/mlx4/alloc.c [new file with mode: 0644]
drivers/net/mlx4/catas.c [new file with mode: 0644]
drivers/net/mlx4/cmd.c [new file with mode: 0644]
drivers/net/mlx4/cq.c [new file with mode: 0644]
drivers/net/mlx4/eq.c [new file with mode: 0644]
drivers/net/mlx4/fw.c [new file with mode: 0644]
drivers/net/mlx4/fw.h [new file with mode: 0644]
drivers/net/mlx4/icm.c [new file with mode: 0644]
drivers/net/mlx4/icm.h [new file with mode: 0644]
drivers/net/mlx4/intf.c [new file with mode: 0644]
drivers/net/mlx4/main.c [new file with mode: 0644]
drivers/net/mlx4/mcg.c [new file with mode: 0644]
drivers/net/mlx4/mlx4.h [new file with mode: 0644]
drivers/net/mlx4/mr.c [new file with mode: 0644]
drivers/net/mlx4/pd.c [new file with mode: 0644]
drivers/net/mlx4/profile.c [new file with mode: 0644]
drivers/net/mlx4/qp.c [new file with mode: 0644]
drivers/net/mlx4/reset.c [new file with mode: 0644]
drivers/net/mlx4/srq.c [new file with mode: 0644]
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/phy/Kconfig
drivers/net/phy/phy.c
drivers/net/skge.c
drivers/net/sundance.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tulip/interrupt.c
drivers/net/tulip/winbond-840.c
drivers/net/tulip/xircom_cb.c
drivers/net/typhoon.c
drivers/net/ucc_geth.c
drivers/net/usb/Kconfig [moved from drivers/usb/net/Kconfig with 100% similarity]
drivers/net/usb/Makefile [moved from drivers/usb/net/Makefile with 100% similarity]
drivers/net/usb/asix.c [moved from drivers/usb/net/asix.c with 100% similarity]
drivers/net/usb/catc.c [moved from drivers/usb/net/catc.c with 100% similarity]
drivers/net/usb/cdc_ether.c [moved from drivers/usb/net/cdc_ether.c with 100% similarity]
drivers/net/usb/cdc_subset.c [moved from drivers/usb/net/cdc_subset.c with 100% similarity]
drivers/net/usb/dm9601.c [moved from drivers/usb/net/dm9601.c with 100% similarity]
drivers/net/usb/gl620a.c [moved from drivers/usb/net/gl620a.c with 100% similarity]
drivers/net/usb/kaweth.c [moved from drivers/usb/net/kaweth.c with 100% similarity]
drivers/net/usb/kawethfw.h [moved from drivers/usb/net/kawethfw.h with 100% similarity]
drivers/net/usb/mcs7830.c [moved from drivers/usb/net/mcs7830.c with 100% similarity]
drivers/net/usb/net1080.c [moved from drivers/usb/net/net1080.c with 100% similarity]
drivers/net/usb/pegasus.c [moved from drivers/usb/net/pegasus.c with 100% similarity]
drivers/net/usb/pegasus.h [moved from drivers/usb/net/pegasus.h with 100% similarity]
drivers/net/usb/plusb.c [moved from drivers/usb/net/plusb.c with 100% similarity]
drivers/net/usb/rndis_host.c [moved from drivers/usb/net/rndis_host.c with 100% similarity]
drivers/net/usb/rtl8150.c [moved from drivers/usb/net/rtl8150.c with 100% similarity]
drivers/net/usb/usbnet.c [moved from drivers/usb/net/usbnet.c with 100% similarity]
drivers/net/usb/usbnet.h [moved from drivers/usb/net/usbnet.h with 99% similarity]
drivers/net/usb/zaurus.c [moved from drivers/usb/net/zaurus.c with 100% similarity]
drivers/net/wireless/Kconfig
drivers/net/wireless/airport.c
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_dma.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_main.h
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wavelan_cs.p.h
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/yellowfin.c
drivers/parport/Kconfig
drivers/pci/pci-driver.c
drivers/pnp/Kconfig
drivers/rtc/Kconfig
drivers/rtc/rtc-rs5c313.c
drivers/rtc/rtc-sh.c
drivers/s390/block/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_ioctl.c
drivers/s390/char/Kconfig [moved from drivers/s390/Kconfig with 59% similarity]
drivers/s390/char/monreader.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_sdias.c
drivers/s390/char/zcore.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio.c
drivers/s390/net/Kconfig
drivers/s390/net/qeth_main.c
drivers/s390/net/qeth_mpc.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/sbus/char/bpp.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/dpcsup.c
drivers/scsi/aacraid/rx.c
drivers/scsi/aic7xxx/aic79xx_pci.c
drivers/scsi/aic94xx/Makefile
drivers/scsi/ch.c
drivers/scsi/dc395x.c
drivers/scsi/dpt_i2o.c
drivers/scsi/ide-scsi.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_mm.c
drivers/scsi/mesh.c
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/qla4xxx/ql4_dbg.c
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/tmscsim.c
drivers/scsi/tmscsim.h
drivers/serial/Kconfig
drivers/serial/cpm_uart/cpm_uart.h
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_cpm1.c
drivers/serial/cpm_uart/cpm_uart_cpm2.c
drivers/serial/sunzilog.c
drivers/serial/sunzilog.h
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel_spi.c
drivers/spi/mpc52xx_psc_spi.c [new file with mode: 0644]
drivers/telephony/Kconfig
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/atm/usbatm.c
drivers/usb/misc/auerswald.c
drivers/usb/serial/Kconfig
drivers/usb/serial/aircable.c
drivers/usb/serial/io_edgeport.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/arkfb.c [new file with mode: 0644]
drivers/video/atmel_lcdfb.c [new file with mode: 0644]
drivers/video/aty/atyfb_base.c
drivers/video/aty/mach64_cursor.c
drivers/video/console/Kconfig
drivers/video/console/softcursor.c
drivers/video/fbmem.c
drivers/video/i810/i810_main.c
drivers/video/matrox/matroxfb_Ti3026.c
drivers/video/matrox/matroxfb_accel.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_misc.c
drivers/video/nvidia/nv_hw.c
drivers/video/nvidia/nvidia.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/riva/rivafb-i2c.c
drivers/video/s3fb.c
drivers/video/skeletonfb.c
drivers/video/svgalib.c
drivers/video/vt8623fb.c [new file with mode: 0644]
drivers/w1/Kconfig
fs/Kconfig
fs/Makefile
fs/affs/file.c
fs/afs/Makefile
fs/afs/afs.h
fs/afs/afs_fs.h
fs/afs/callback.c
fs/afs/dir.c
fs/afs/file.c
fs/afs/fsclient.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/main.c
fs/afs/misc.c
fs/afs/mntpt.c
fs/afs/rxrpc.c
fs/afs/security.c
fs/afs/server.c
fs/afs/super.c
fs/afs/vnode.c
fs/afs/write.c [new file with mode: 0644]
fs/aio.c
fs/anon_inodes.c [new file with mode: 0644]
fs/autofs/autofs_i.h
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/binfmt_misc.c
fs/buffer.c
fs/compat.c
fs/compat_ioctl.c
fs/configfs/file.c
fs/direct-io.c
fs/eventfd.c [new file with mode: 0644]
fs/eventpoll.c
fs/exec.c
fs/ext3/inode.c
fs/jbd/checkpoint.c
fs/jbd/recovery.c
fs/jbd/revoke.c
fs/jbd/transaction.c
fs/jbd2/checkpoint.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/jbd2/transaction.c
fs/jffs2/histo_mips.h [deleted file]
fs/jffs2/readinode.c
fs/jffs2/wbuf.c
fs/jfs/jfs_dmap.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_logmgr.c
fs/libfs.c
fs/locks.c
fs/mpage.c
fs/namei.c
fs/nfs/dir.c
fs/nfs/getroot.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs4xdr.c
fs/nfs/pagelist.c
fs/nfsd/Makefile
fs/nfsd/export.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4state.c
fs/nfsd/nfsfh.c
fs/nfsd/nfsproc.c
fs/nfsd/nfsxdr.c
fs/ocfs2/cluster/masklog.c
fs/open.c
fs/partitions/Kconfig
fs/partitions/efi.c
fs/proc/base.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/select.c
fs/signalfd.c [new file with mode: 0644]
fs/sysfs/file.c
fs/timerfd.c [new file with mode: 0644]
fs/xfs/xfs_itable.c
fs/xfs/xfs_mount.c
include/acpi/acdispat.h
include/acpi/acglobal.h
include/acpi/acinterp.h
include/acpi/aclocal.h
include/acpi/acnamesp.h
include/acpi/acobject.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpi_numa.h
include/acpi/acpiosxf.h
include/acpi/actypes.h
include/acpi/acutils.h
include/acpi/platform/aclinux.h
include/acpi/processor.h
include/asm-alpha/poll.h
include/asm-alpha/smp.h
include/asm-alpha/thread_info.h
include/asm-arm/arch-at91/at91rm9200.h
include/asm-arm/arch-at91/at91sam9260.h
include/asm-arm/arch-at91/at91sam9261.h
include/asm-arm/arch-at91/at91sam9263.h
include/asm-arm/arch-at91/board.h
include/asm-arm/arch-at91/cpu.h
include/asm-arm/arch-imx/imx-regs.h
include/asm-arm/arch-integrator/platform.h
include/asm-arm/arch-iop32x/glantank.h
include/asm-arm/arch-iop32x/n2100.h
include/asm-arm/arch-omap/aic23.h
include/asm-arm/arch-omap/board-apollon.h
include/asm-arm/arch-omap/board-h4.h
include/asm-arm/arch-omap/board.h
include/asm-arm/arch-omap/dma.h
include/asm-arm/arch-omap/dsp.h [deleted file]
include/asm-arm/arch-omap/dsp_common.h
include/asm-arm/arch-omap/gpio-switch.h [new file with mode: 0644]
include/asm-arm/arch-omap/gpio.h
include/asm-arm/arch-omap/gpmc.h
include/asm-arm/arch-omap/hardware.h
include/asm-arm/arch-omap/hwa742.h [new file with mode: 0644]
include/asm-arm/arch-omap/io.h
include/asm-arm/arch-omap/irqs.h
include/asm-arm/arch-omap/lcd_lph8923.h [deleted file]
include/asm-arm/arch-omap/lcd_mipid.h [new file with mode: 0644]
include/asm-arm/arch-omap/led.h [new file with mode: 0644]
include/asm-arm/arch-omap/mailbox.h [new file with mode: 0644]
include/asm-arm/arch-omap/mcspi.h
include/asm-arm/arch-omap/memory.h
include/asm-arm/arch-omap/menelaus.h
include/asm-arm/arch-omap/omap16xx.h
include/asm-arm/arch-omap/omap24xx.h
include/asm-arm/arch-omap/omapfb.h
include/asm-arm/arch-omap/sram.h
include/asm-arm/arch-omap/usb.h
include/asm-arm/arch-s3c2410/regs-power.h
include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
include/asm-arm/arch-s3c2410/regs-watchdog.h
include/asm-arm/arch-s3c2410/udc.h
include/asm-arm/cacheflush.h
include/asm-arm/dma-mapping.h
include/asm-arm/glue.h
include/asm-arm/mmu_context.h
include/asm-arm/poll.h
include/asm-arm/proc-fns.h
include/asm-arm/system.h
include/asm-arm26/io.h
include/asm-arm26/memory.h
include/asm-arm26/poll.h
include/asm-arm26/setup.h
include/asm-avr32/arch-at32ap/cpu.h [new file with mode: 0644]
include/asm-avr32/poll.h
include/asm-avr32/setup.h
include/asm-avr32/unistd.h
include/asm-blackfin/processor.h
include/asm-blackfin/system.h
include/asm-cris/poll.h
include/asm-frv/poll.h
include/asm-frv/tlb.h
include/asm-frv/unistd.h
include/asm-generic/Kbuild
include/asm-generic/bitops/atomic.h
include/asm-generic/poll.h [new file with mode: 0644]
include/asm-h8300/poll.h
include/asm-h8300/unistd.h
include/asm-i386/alternative.h
include/asm-i386/bitops.h
include/asm-i386/boot.h
include/asm-i386/mmzone.h
include/asm-i386/msr.h
include/asm-i386/paravirt.h
include/asm-i386/poll.h
include/asm-i386/smp.h
include/asm-i386/sync_bitops.h
include/asm-i386/thread_info.h
include/asm-i386/tsc.h
include/asm-i386/unistd.h
include/asm-ia64/hw_irq.h
include/asm-ia64/iosapic.h
include/asm-ia64/poll.h
include/asm-ia64/smp.h
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/thread_info.h
include/asm-ia64/tlbflush.h
include/asm-ia64/unistd.h
include/asm-m32r/pgtable-2level.h
include/asm-m32r/pgtable.h
include/asm-m32r/poll.h
include/asm-m32r/smp.h
include/asm-m32r/system.h
include/asm-m68k/atarihw.h
include/asm-m68k/atariints.h
include/asm-m68k/poll.h
include/asm-m68k/scatterlist.h
include/asm-m68k/thread_info.h
include/asm-mips/bootinfo.h
include/asm-mips/poll.h
include/asm-mips/system.h
include/asm-parisc/compat.h
include/asm-parisc/poll.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/mmu-hash64.h
include/asm-powerpc/mmzone.h
include/asm-powerpc/paca.h
include/asm-powerpc/page_64.h
include/asm-powerpc/pgalloc-64.h
include/asm-powerpc/pgtable-4k.h
include/asm-powerpc/pgtable-64k.h
include/asm-powerpc/poll.h
include/asm-powerpc/ppc-pci.h
include/asm-powerpc/ps3.h
include/asm-powerpc/qe.h
include/asm-powerpc/reg_booke.h [new file with mode: 0644]
include/asm-powerpc/rheap.h [moved from include/asm-ppc/rheap.h with 75% similarity]
include/asm-powerpc/smp.h
include/asm-powerpc/spu_csa.h
include/asm-powerpc/systbl.h
include/asm-powerpc/unistd.h
include/asm-ppc/commproc.h
include/asm-ppc/cpm2.h
include/asm-ppc/hydra.h
include/asm-s390/ccwdev.h
include/asm-s390/ipl.h
include/asm-s390/param.h
include/asm-s390/poll.h
include/asm-s390/smp.h
include/asm-sh/bug.h
include/asm-sh/cpu-features.h
include/asm-sh/cpu-sh3/dma.h
include/asm-sh/cpu-sh4/dma-sh7780.h
include/asm-sh/cpu-sh4/dma.h
include/asm-sh/dmabrg.h [new file with mode: 0644]
include/asm-sh/edosk7705.h
include/asm-sh/kdebug.h
include/asm-sh/pgalloc.h
include/asm-sh/poll.h
include/asm-sh/snapgear.h
include/asm-sh/system.h
include/asm-sh/timer.h
include/asm-sh/unistd.h
include/asm-sh64/poll.h
include/asm-sparc/poll.h
include/asm-sparc/smp.h
include/asm-sparc/unistd.h
include/asm-sparc64/kdebug.h
include/asm-sparc64/kprobes.h
include/asm-sparc64/openprom.h
include/asm-sparc64/pbm.h [deleted file]
include/asm-sparc64/poll.h
include/asm-sparc64/smp.h
include/asm-sparc64/unistd.h
include/asm-um/required-features.h [new file with mode: 0644]
include/asm-um/smp.h
include/asm-um/thread_info.h
include/asm-v850/poll.h
include/asm-x86_64/alternative.h
include/asm-x86_64/page.h
include/asm-x86_64/poll.h
include/asm-x86_64/smp.h
include/asm-x86_64/system.h
include/asm-x86_64/thread_info.h
include/asm-x86_64/unistd.h
include/asm-xtensa/platform-iss/simcall.h
include/asm-xtensa/poll.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/aio.h
include/linux/aio_abi.h
include/linux/anon_inodes.h [new file with mode: 0644]
include/linux/blkdev.h
include/linux/clocksource.h
include/linux/compat.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/crc-itu-t.h [new file with mode: 0644]
include/linux/eventfd.h [new file with mode: 0644]
include/linux/ext3_fs_i.h
include/linux/ext4_fs_i.h
include/linux/fb.h
include/linux/firewire-cdev.h [new file with mode: 0644]
include/linux/firewire-constants.h [new file with mode: 0644]
include/linux/futex.h
include/linux/generic_acl.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/highmem.h
include/linux/i2c-algo-bit.h
include/linux/i2c-algo-pcf.h
include/linux/ide.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/irda.h
include/linux/kernel.h
include/linux/kthread.h
include/linux/ktime.h
include/linux/magic.h
include/linux/mca.h
include/linux/meye.h
include/linux/mlx4/cmd.h [new file with mode: 0644]
include/linux/mlx4/cq.h [new file with mode: 0644]
include/linux/mlx4/device.h [new file with mode: 0644]
include/linux/mlx4/doorbell.h [new file with mode: 0644]
include/linux/mlx4/driver.h [new file with mode: 0644]
include/linux/mlx4/qp.h [new file with mode: 0644]
include/linux/mlx4/srq.h [new file with mode: 0644]
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/module.h
include/linux/mount.h
include/linux/mpage.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mutex.h
include/linux/netdevice.h
include/linux/netfilter/x_tables.h
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/nfs4_acl.h
include/linux/notifier.h
include/linux/pid.h
include/linux/pm.h
include/linux/pmu.h
include/linux/radix-tree.h
include/linux/relay.h
include/linux/rslib.h
include/linux/sched.h
include/linux/security.h
include/linux/signal.h
include/linux/signalfd.h [new file with mode: 0644]
include/linux/smp.h
include/linux/sonypi.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svcsock.h
include/linux/suspend.h
include/linux/svga.h
include/linux/synclink.h
include/linux/syscalls.h
include/linux/task_io_accounting_ops.h
include/linux/tifm.h
include/linux/timerfd.h [new file with mode: 0644]
include/linux/tty_driver.h
include/linux/tty_ldisc.h
include/linux/usb.h
include/linux/vmstat.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/ieee80211.h
include/net/irda/af_irda.h
include/net/irda/irda.h
include/net/irda/iriap.h
include/net/irda/iriap_event.h
include/net/irda/irias_object.h
include/net/irda/irlan_client.h
include/net/irda/irlan_common.h
include/net/irda/irlan_eth.h
include/net/irda/irlan_event.h
include/net/irda/irlan_filter.h
include/net/irda/irlan_provider.h
include/net/irda/irlap.h
include/net/irda/irlmp.h
include/net/irda/irlmp_event.h
include/net/irda/irlmp_frame.h
include/net/irda/irmod.h
include/net/irda/irqueue.h
include/net/irda/irttp.h
include/net/irda/parameters.h
include/net/irda/timer.h
include/net/irda/wrapper.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_nat_rule.h
include/net/udp.h
include/net/udplite.h
include/rdma/ib_umem.h [new file with mode: 0644]
include/rdma/ib_verbs.h
include/scsi/libsas.h
include/video/atmel_lcdc.h [new file with mode: 0644]
include/video/pm3fb.h
init/Kconfig
init/do_mounts.c
init/main.c
kernel/Kconfig.preempt
kernel/compat.c
kernel/configs.c
kernel/cpu.c
kernel/cpuset.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/futex_compat.c
kernel/hrtimer.c
kernel/irq/handle.c
kernel/kmod.c
kernel/kthread.c
kernel/module.c
kernel/mutex.c
kernel/pid.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/power.h
kernel/power/snapshot.c
kernel/power/user.c
kernel/profile.c
kernel/rcupdate.c
kernel/relay.c
kernel/rtmutex.c
kernel/rtmutex_common.h
kernel/sched.c
kernel/signal.c
kernel/softirq.c
kernel/softlockup.c
kernel/stop_machine.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/time/clocksource.c
kernel/time/timer_list.c
kernel/timer.c
kernel/wait.c
kernel/workqueue.c
lib/Kconfig
lib/Makefile
lib/crc-itu-t.c [new file with mode: 0644]
lib/hexdump.c [new file with mode: 0644]
lib/radix-tree.c
lib/reed_solomon/reed_solomon.c
mm/Kconfig
mm/filemap.c
mm/filemap_xip.c
mm/hugetlb.c
mm/mmap.c
mm/page-writeback.c
mm/page_alloc.c
mm/slab.c
mm/slub.c
mm/swap.c
mm/thrash.c
mm/truncate.c
mm/vmscan.c
mm/vmstat.c
net/Kconfig
net/ax25/Kconfig
net/bluetooth/Kconfig
net/bluetooth/hidp/core.c
net/core/dev.c
net/core/flow.c
net/core/link_watch.c
net/decnet/af_decnet.c
net/ieee80211/ieee80211_geo.c
net/ieee80211/ieee80211_wx.c
net/ipv4/Kconfig
net/ipv4/cipso_ipv4.c
net/ipv4/ipvs/ip_vs_ctl.c
net/ipv4/ipvs/ip_vs_sed.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv4/netfilter/nf_nat_standalone.c
net/ipv4/udp.c
net/ipv4/udp_impl.h
net/ipv4/udplite.c
net/ipv6/addrconf.c
net/ipv6/exthdrs.c
net/ipv6/ip6_output.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/udp.c
net/ipv6/udp_impl.h
net/ipv6/udplite.c
net/irda/Kconfig
net/iucv/iucv.c
net/llc/af_llc.c
net/mac80211/ieee80211_sta.c
net/netfilter/Kconfig
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/xt_conntrack.c
net/rxrpc/ar-peer.c
net/sched/sch_generic.c
net/sched/sch_teql.c
net/sctp/chunk.c
net/sctp/socket.c
net/sctp/ulpevent.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/svcauth.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
scripts/basic/docproc.c
scripts/kernel-doc
scripts/mod/modpost.c
security/selinux/Kconfig
sound/Kconfig
sound/core/Kconfig
sound/oss/es1371.c
sound/oss/pas2_pcm.c
sound/oss/trident.c
sound/pci/ac97/ac97_codec.c
sound/pci/ice1712/delta.h
sound/pci/mixart/mixart.c
sound/soc/pxa/pxa2xx-ac97.h
sound/soc/pxa/pxa2xx-i2s.h
sound/sparc/dbri.c

diff --git a/CREDITS b/CREDITS
index 80e241304b8ee0ad5d535ccc96ed0e4db7f5f940..6829e91a88d43f5827be72eef88f17e06eaab377 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -380,7 +380,7 @@ S: FutureTV Labs Ltd
 S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG
 S: United Kingdom
 
-N: Thomas Bogendörfer
+N: Thomas Bogendörfer
 E: tsbogend@alpha.franken.de
 D: PCnet32 driver, SONIC driver, JAZZ_ESP driver
 D: newport abscon driver, g364 framebuffer driver
@@ -400,7 +400,7 @@ W: http://math-www.uni-paderborn.de/~axel/
 D: Configuration help text support
 D: Linux CD and Support Giveaway List
 
-N: Erik Inge Bolsø
+N: Erik Inge Bolsø
 E: knan@mo.himolde.no
 D: Misc kernel hacks
 
@@ -428,7 +428,7 @@ D: Various fixes (mostly networking)
 S: Montreal, Quebec
 S: Canada
 
-N: Zoltán Böszörményi
+N: Zoltán Böszörményi
 E: zboszor@mail.externet.hu
 D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
 
@@ -1029,11 +1029,11 @@ D: Future Domain TMC-16x0 SCSI driver (author)
 D: APM driver (early port)
 D: DRM drivers (author of several)
 
-N: János Farkas
+N: János Farkas
 E: chexum@shadow.banki.hu
 D: romfs, various (mostly networking) fixes
 P: 1024/F81FB2E1 41 B7 E4 E6 3E D4 A6 71  6D 9C F3 9F F2 BF DF 6E
-S: Madarász Viktor utca 25
+S: Madarász Viktor utca 25
 S: 1131 Budapest
 S: Hungary
 
@@ -1044,10 +1044,10 @@ D: UDF filesystem
 S: (ask for current address)
 S: USA
 
-N: Jürgen Fischer
-E: fischer@norbit.de (=?iso-8859-1?q?J=FCrgen?= Fischer)
+N: Jürgen Fischer
+E: fischer@norbit.de
 D: Author of Adaptec AHA-152x SCSI driver
-S: Schulstraße 18
+S: Schulstraße 18
 S: 26506 Norden
 S: Germany
 
@@ -1113,7 +1113,7 @@ E: fuganti@netbank.com.br
 D: random kernel hacker, ZF MachZ Watchdog driver
 S: Conectiva S.A.
 S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
 N: Kumar Gala
@@ -1258,12 +1258,12 @@ S: 44 St. Joseph Street, Suite 506
 S: Toronto, Ontario, M4Y 2W4
 S: Canada
 
-N: Richard Günther
+N: Richard Günther
 E: rguenth@tat.physik.uni-tuebingen.de
 W: http://www.tat.physik.uni-tuebingen.de/~rguenth
 P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2  93 7A 32 42 45 37 23 57
 D: binfmt_misc
-S: 72074 Tübingen
+S: 72074 Tübingen
 S: Germany
 
 N: Justin Guyett
@@ -1287,7 +1287,7 @@ N: Bruno Haible
 E: haible@ma2s2.mathematik.uni-karlsruhe.de
 D: SysV FS, shm swapping, memory management fixes
 S: 17 rue Danton
-S: F - 94270 Le Kremlin-Bicêtre
+S: F - 94270 Le Kremlin-Bicêtre
 S: France
 
 N: Greg Hankins
@@ -1701,7 +1701,7 @@ S: Czech Republic
 N: Jakob Kemi
 E: jakob.kemi@telia.com
 D: V4L W9966 Webcam driver
-S: Forsbyvägen 33
+S: Forsbyvägen 33
 S: 74143 Knivsta
 S: Sweden
 
@@ -2065,7 +2065,7 @@ D: misc. kernel hacking and debugging
 S: Cambridge, MA 02139
 S: USA
 
-N: Martin von Löwis
+N: Martin von Löwis
 E: loewis@informatik.hu-berlin.de
 D: script binary format
 D: NTFS driver
@@ -2142,7 +2142,7 @@ S: PO BOX 220, HFX. CENTRAL
 S: Halifax, Nova Scotia
 S: Canada B3J 3C8
 
-N: Kai Mäkisara
+N: Kai Mäkisara
 E: Kai.Makisara@kolumbus.fi
 D: SCSI Tape Driver
 
@@ -2785,10 +2785,10 @@ N: Juan Quintela
 E: quintela@fi.udc.es
 D: Memory Management hacking
 S: LFCIA
-S: Departamento de Computación
-S: Universidade da Coruña
+S: Departamento de Computación
+S: Universidade da Coruña
 S: E-15071
-S: A Coruña
+S: A Coruña
 S: Spain
 
 N: Augusto Cesar Radtke
@@ -2939,7 +2939,7 @@ E: aris@cathedrallabs.org
 D: Support for EtherExpress 10 ISA (i82595) in eepro driver
 D: User level driver support for input
 S: R. Jose Serrato, 130 - Santa Candida
-S: 82640-320 - Curitiba - Paraná
+S: 82640-320 - Curitiba - Paraná
 S: Brazil
 
 N: Alessandro Rubini
@@ -3345,15 +3345,15 @@ P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87  CA26 189B 9946 D0FE 7AFB
 D: rcutorture maintainer
 D: lock annotations, finding and fixing lock bugs
 
-N: Winfried Trümper
+N: Winfried Trümper
 E: winni@xpilot.org
 W: http://www.shop.de/~winni/
 D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
 D: CD-Writing HOWTO, various mini-HOWTOs
 D: One-week tutorials on Linux twice a year (free of charge)
-D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
+D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
 S: Tacitusstr. 6
-S: D-50968 Köln
+S: D-50968 Köln
 
 N: Tsu-Sheng Tsao
 E: tsusheng@scf.usc.edu
index 8195c4e0d0a1002b75c55e78f43dd5855f9b3c5f..8ffd28bf65982b575b8d97013aade37fbecd1645 100644 (file)
@@ -6,7 +6,7 @@ Description:
        races, contains a naming policy within the kernel that is
        against the LSB, and can be replaced by using udev.
        The files fs/devfs/*, include/linux/devfs_fs*.h were removed,
-       along with the the assorted devfs function calls throughout the
+       along with the assorted devfs function calls throughout the
        kernel tree.
 
 Users:
index a2b2b4d187c5c75a9312112fb9fc361159acd20b..38f88b6ae405a16606134db8aedf7a89ccf8e643 100644 (file)
@@ -84,6 +84,10 @@ X!Iinclude/linux/kobject.h
 !Ekernel/rcupdate.c
      </sect1>
 
+     <sect1><title>Device Resource Management</title>
+!Edrivers/base/devres.c
+     </sect1>
+
   </chapter>
 
   <chapter id="adt">
index d389388c733e6c718f87de37a885132af6519930..0d8240774fca2d3bc00454ce5bc65ec20fe09e2e 100644 (file)
@@ -480,8 +480,8 @@ The PCI stack provides 3 possible levels of MSI disabling:
 
 6.1. Disabling MSI on a single device
 
-Under some circumstances, it might be required to disable MSI on a
-single device, It may be achived by either not calling pci_enable_msi()
+Under some circumstances it might be required to disable MSI on a
+single device.  This may be achieved by either not calling pci_enable_msi()
 or all, or setting the pci_dev->no_msi flag before (most of the time
 in a quirk).
 
@@ -492,7 +492,7 @@ being able to route MSI between busses. In this case, MSI have to be
 disabled on all devices behind this bridge. It is achieves by setting
 the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
 subordinate bus. There is no need to set the same flag on bridges that
-are below the broken brigde. When pci_enable_msi() is called to enable
+are below the broken bridge. When pci_enable_msi() is called to enable
 MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
 flag in all parent busses of the device.
 
index bd23dc0bc0c7c9ced4323b761396377d700fad83..3af3e65cf43b54ccfb150824e9338b8567234812 100644 (file)
@@ -73,10 +73,14 @@ kernel patches.
     If the new code is substantial, addition of subsystem-specific fault
     injection might be appropriate.
 
-22: Newly-added code has been compiled with `gcc -W'.  This will generate
-    lots of noise, but is good for finding bugs like "warning: comparison
-    between signed and unsigned".
+22: Newly-added code has been compiled with `gcc -W' (use "make
+    EXTRA_CFLAGS=-W").  This will generate lots of noise, but is good for
+    finding bugs like "warning: comparison between signed and unsigned".
 
 23: Tested after it has been merged into the -mm patchset to make sure
     that it still works with all of the other queued patches and various
     changes in the VM, VFS, and other subsystems.
+
+24: Avoid whitespace damage such as indenting with spaces or whitespace
+    at the end of lines.  You can test this by feeding the patch to
+    "git apply --check --whitespace=error-all"
index b0d0043f7c46cdde154f6be25fe33ba3a98b645d..a417b25fb1aa40f62234c222db0a4be1cfaa938d 100644 (file)
@@ -363,7 +363,8 @@ area or subsystem of the kernel is being patched.
 The "summary phrase" in the email's Subject should concisely
 describe the patch which that email contains.  The "summary
 phrase" should not be a filename.  Do not use the same "summary
-phrase" for every patch in a whole patch series.
+phrase" for every patch in a whole patch series (where a "patch
+series" is an ordered sequence of multiple, related patches).
 
 Bear in mind that the "summary phrase" of your email becomes
 a globally-unique identifier for that patch.  It propagates
index 72c93de8cd4e2ef306aedca82034fe1e207b7d45..0d3dbf1099bcc90cae1b364002ef32e15dcdc06a 100644 (file)
@@ -149,7 +149,7 @@ So, what's changed?
 
 3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
 
-4. Direct access to SA1111 INTPOL is depreciated.  Use set_irq_type instead.
+4. Direct access to SA1111 INTPOL is deprecated.  Use set_irq_type instead.
 
 5. A handler is expected to perform any necessary acknowledgement of the
    parent IRQ via the correct chip specific function.  For instance, if
index d6b1de92b1115e37dda8ca8aae4d6bcb34992f2c..f4a7b22c8664be44c398ab4325c951b084b965e8 100644 (file)
@@ -23,7 +23,7 @@ Support
 
     http://handhelds.org/moin/moin.cgi/HpIpaqH1940
 
-  Herbert Pötzl pages:
+  Herbert Pötzl pages:
 
     http://vserver.13thfloor.at/H1940/
 
@@ -32,7 +32,7 @@ Maintainers
 -----------
 
   This project is being maintained and developed by a variety
-  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+  of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
 
   Thanks to the many others who have also provided support.
 
index 3572b98f45b8378460dc75bbe730571c90e4172c..b714183d412515abc2a39c32e898cdab52d21eff 100644 (file)
@@ -78,9 +78,9 @@ Select (17)------------------------------(16) Data / Instruction
 Ground (18)---[GND]              [+5v]---(19) LED +
 Ground (19)---[GND]
 Ground (20)---[GND]              E    A             Values:
-Ground (21)---[GND]       [GND]---[P1]---(18) Vee    · R = Resistor = 22 ohm
-Ground (22)---[GND]                |                 · P1 = Preset = 10 Kohm
-Ground (23)---[GND]       ----   S ------( 3) V0     · P2 = Preset = 1 Kohm
+Ground (21)---[GND]       [GND]---[P1]---(18) Vee    - R = Resistor = 22 ohm
+Ground (22)---[GND]                |                 - P1 = Preset = 10 Kohm
+Ground (23)---[GND]       ----   S ------( 3) V0     - P2 = Preset = 1 Kohm
 Ground (24)---[GND]       |  |
 Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED -
 
index d097f09ee15ad21c1dc56c2f0d75e06e156368ff..f609ebf9c78fe4023d87a50c0fa73d415846d4b1 100644 (file)
@@ -113,4 +113,4 @@ cause unexpected behaviour and can be a security hazard.
 There is a web page about binfmt_misc at
 http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
 
-Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
+Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
index 96ccf681075e9d5a95c62b402ef11646aaf8cc02..1b930ef5a079a9f9dcbceca52851e6c14cd722ee 100644 (file)
@@ -6,10 +6,10 @@ Intro
 -----
 
 With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
-priorities is supported for reads on files. This enables users to io nice
-processes or process groups, similar to what has been possible to cpu
-scheduling for ages. This document mainly details the current possibilites
-with cfq, other io schedulers do not support io priorities so far.
+priorities are supported for reads on files.  This enables users to io nice
+processes or process groups, similar to what has been possible with cpu
+scheduling for ages.  This document mainly details the current possibilities
+with cfq; other io schedulers do not support io priorities thus far.
 
 Scheduling classes
 ------------------
index 53d62c1e1c94f68531756d20c80e50c48aa718b3..fc647492e940539be1f37b02335ac1bbc7829820 100644 (file)
@@ -17,7 +17,7 @@ Contents
 
 1. Introduction
 
-cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
+cpufreq-stats is a driver that provides CPU frequency statistics for each CPU.
 These statistics are provided in /sysfs as a bunch of read_only interfaces. This
 interface (when configured) will appear in a separate directory under cpufreq
 in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
index cc60d29b954cd394ccd1eba1c27b06bfc049302d..b6d24c22274b8dfb0ea28c3e841594779f5b20e7 100644 (file)
@@ -217,14 +217,17 @@ Q: What happens when a CPU is being logically offlined?
 A: The following happen, listed in no particular order :-)
 
 - A notification is sent to in-kernel registered modules by sending an event
-  CPU_DOWN_PREPARE
+  CPU_DOWN_PREPARE or CPU_DOWN_PREPARE_FROZEN, depending on whether or not the
+  CPU is being offlined while tasks are frozen due to a suspend operation in
+  progress
 - All process is migrated away from this outgoing CPU to a new CPU
 - All interrupts targeted to this CPU is migrated to a new CPU
 - timers/bottom half/task lets are also migrated to a new CPU
 - Once all services are migrated, kernel calls an arch specific routine
   __cpu_disable() to perform arch specific cleanup.
 - Once this is successful, an event for successful cleanup is sent by an event
-  CPU_DEAD.
+  CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the
+  CPU is being offlined).
 
   "It is expected that each service cleans up when the CPU_DOWN_PREPARE
   notifier is called, when CPU_DEAD is called its expected there is nothing
@@ -242,9 +245,11 @@ A: This is what you would need in your kernel code to receive notifications.
 
                switch (action) {
                case CPU_ONLINE:
+               case CPU_ONLINE_FROZEN:
                        foobar_online_action(cpu);
                        break;
                case CPU_DEAD:
+               case CPU_DEAD_FROZEN:
                        foobar_dead_action(cpu);
                        break;
                }
index 9b84b805ab759114fc1b7ccb9d1bd5af3ecfefb0..a2ac6d2947932022ddd8b6d906d13bd5882a0719 100644 (file)
@@ -177,7 +177,7 @@ Portions of this API were derived from the following projects:
 and;
   
   Nettle (http://www.lysator.liu.se/~nisse/nettle/)
-    Niels Möller
+    Niels Möller
 
 Original developers of the crypto algorithms:
 
@@ -200,8 +200,8 @@ SHA1 algorithm contributors:
   
 DES algorithm contributors:
   Raimar Falke
-  Gisle Sælensminde
-  Niels Möller
+  Gisle Sælensminde
+  Niels Möller
 
 Blowfish algorithm contributors:
   Herbert Valerio Riedel
diff --git a/Documentation/device-mapper/delay.txt b/Documentation/device-mapper/delay.txt
new file mode 100644 (file)
index 0000000..15adc55
--- /dev/null
@@ -0,0 +1,26 @@
+dm-delay
+========
+
+Device-Mapper's "delay" target delays reads and/or writes
+and maps them to different devices.
+
+Parameters:
+    <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+
+With separate write parameters, the first set is only used for reads.
+Delays are specified in milliseconds.
+
+Example scripts
+===============
+[[
+#!/bin/sh
+# Create device delaying rw operation for 500ms
+echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
+]]
+
+[[
+#!/bin/sh
+# Create device delaying only write operation for 500ms and
+# splitting reads and writes to different devices $1 $2
+echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
+]]
index f7c9262b2dc8543aa2808931e2cb5c316efacb06..19c4a6e136760750365483d49751edb4853daad6 100644 (file)
@@ -16,7 +16,7 @@ host bridges to peripheral buses, and most controllers integrated
 into system-on-chip platforms.  What they usually have in common
 is direct addressing from a CPU bus.  Rarely, a platform_device will
 be connected through a segment of some other kind of bus; but its
-registers will still be directly addressible.
+registers will still be directly addressable.
 
 Platform devices are given a name, used in driver binding, and a
 list of resources such as addresses and IRQs.
@@ -125,7 +125,7 @@ three different ways to find such a match:
       usually register later during booting, or by module loading.
 
     - Registering a driver using platform_driver_probe() works just like
-      using platform_driver_register(), except that the the driver won't
+      using platform_driver_register(), except that the driver won't
       be probed later if another device registers.  (Which is OK, since
       this interface is only for use with non-hotpluggable devices.)
 
index 46b78b7331c27e4f0fe131336f08c25235138ad5..bf2a9cdfe7bbc2077001308ae40089a6fa33ca07 100644 (file)
@@ -228,5 +228,5 @@ Patches, comments and suggestions are very very welcome.
 
    Ulf Hermenau for helping me out with traditional chinese.
 
-   André Smoktun and Christian Frömmel for supporting me with
+   André Smoktun and Christian Frömmel for supporting me with
     hardware and listening to my problems very patiently.
index 4c33cced5f657fd25be698d01a25473a11c0dfd4..4865addebe1cb92145d9f88c1de3c1cf586c8f4a 100644 (file)
@@ -66,7 +66,7 @@ Michael Dreher <michael@5dot1.de>
 Andreas 'randy' Weinberger
   for the support of the Fujitsu-Siemens Activy budget DVB-S
 
-Kenneth Aafløy <ke-aa@frisurf.no>
+Kenneth Aafløy <ke-aa@frisurf.no>
   for adding support for Typhoon DVB-S budget card
 
 Ernst Peinlich <e.peinlich@inode.at>
diff --git a/Documentation/fb/arkfb.txt b/Documentation/fb/arkfb.txt
new file mode 100644 (file)
index 0000000..e8487a9
--- /dev/null
@@ -0,0 +1,68 @@
+
+       arkfb - fbdev driver for ARK Logic chips
+       ========================================
+
+
+Supported Hardware
+==================
+
+       ARK 2000PV chip
+       ICS 5342 ramdac
+
+       - only BIOS initialized VGA devices supported
+       - probably not working on big endian
+
+
+Supported Features
+==================
+
+       *  4 bpp pseudocolor modes (with 18bit palette, two variants)
+       *  8 bpp pseudocolor mode (with 18bit palette)
+       * 16 bpp truecolor modes (RGB 555 and RGB 565)
+       * 24 bpp truecolor mode (RGB 888)
+       * 32 bpp truecolor mode (RGB 888)
+       * text mode (activated by bpp = 0)
+       * doublescan mode variant (not available in text mode)
+       * panning in both directions
+       * suspend/resume support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (i got maximum about 70 MHz, it is dependent on specific
+hardware). This limitation is not enforced by driver. Text mode supports 8bit
+wide fonts only (hardware limitation) and 16bit tall fonts (driver
+limitation). Unfortunately character attributes (like color) in text mode are
+broken for unknown reason, so its usefulness is limited.
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+       * secondary (not initialized by BIOS) device support
+       * big endian support
+       * DPMS support
+       * MMIO support
+       * interlaced mode variant
+       * support for fontwidths != 8 in 4 bpp modes
+       * support for fontheight != 16 in text mode
+       * hardware cursor
+       * vsync synchronization
+       * feature connector support
+       * acceleration support (8514-like 2D)
+
+
+Known bugs
+==========
+
+       * character attributes (and cursor) in text mode are broken
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
index 069262fb619dfce82735bef6e639aa6abf6fc8f5..b605204fcfe1c797ab25c1a4a6cee09719f0ab37 100644 (file)
@@ -54,8 +54,8 @@ Accepted options:
 
 noaccel  - do not use acceleration engine. It is default.
 accel    - use acceleration engine. Not finished.
-vmode:x  - chooses PowerMacintosh video mode <x>. Depreciated.
-cmode:x  - chooses PowerMacintosh colour mode <x>. Depreciated.
+vmode:x  - chooses PowerMacintosh video mode <x>. Deprecated.
+cmode:x  - chooses PowerMacintosh colour mode <x>. Deprecated.
 <XxX@X>  - selects startup videomode. See modedb.txt for detailed
           explanation. Default is 640x480x8bpp.
 
index 610e7801207b5248a5f32e6ccffb921e1ff010f6..b3e3a035683993edc8391cefd11ea3ef6be9eb08 100644 (file)
@@ -215,11 +215,11 @@ vertical retrace time is the sum of the upper margin, the lower margin and the
 vsync length.
 
   +----------+---------------------------------------------+----------+-------+
-  |          |                ^                            |          |       |
+  |          |                                            |          |       |
   |          |                |upper_margin                |          |       |
-  |          |                ¥                            |          |       |
+  |          |                                            |          |       |
   +----------###############################################----------+-------+
-  |          #                ^                            #          |       |
+  |          #                                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
@@ -238,15 +238,15 @@ vsync length.
   |          #                |                            #          |       |
   |          #                |                            #          |       |
   |          #                |                            #          |       |
-  |          #                ¥                            #          |       |
+  |          #                                            #          |       |
   +----------###############################################----------+-------+
-  |          |                ^                            |          |       |
+  |          |                                            |          |       |
   |          |                |lower_margin                |          |       |
-  |          |                ¥                            |          |       |
+  |          |                                            |          |       |
   +----------+---------------------------------------------+----------+-------+
-  |          |                ^                            |          |       |
+  |          |                                            |          |       |
   |          |                |vsync_len                   |          |       |
-  |          |                ¥                            |          |       |
+  |          |                                            |          |       |
   +----------+---------------------------------------------+----------+-------+
 
 The frame buffer device expects all horizontal timings in number of dotclocks
index 759028545a7ee833c90c4726bcf9ff83c9337102..316ec9bb7debd5f79ac76e9cbbea5f957ba25e74 100644 (file)
@@ -17,7 +17,7 @@ How to use it?
 ==============
 
 Imacfb does not have any kind of autodetection of your machine.
-You have to add the fillowing kernel parameters in your elilo.conf:
+You have to add the following kernel parameters in your elilo.conf:
        Macbook :
                video=imacfb:macbook
        MacMini :
index df27f5bf15dbc4cef4e0285085b4adc2709b279a..550ca775a4cbbe78ef623a2d5c0ed96fc72d550e 100644 (file)
@@ -2,9 +2,9 @@
 Introduction
 
          This is a frame buffer device driver for 3dfx' Voodoo Graphics 
-       (aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based 
+       (aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based 
        video boards. It's highly experimental code, but is guaranteed to work
-       on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
+       on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
        and with me "between chair and keyboard". Some people tested other
        combinations and it seems that it works.
          The main page is located at <http://sstfb.sourceforge.net>, and if
diff --git a/Documentation/fb/vt8623fb.txt b/Documentation/fb/vt8623fb.txt
new file mode 100644 (file)
index 0000000..f654576
--- /dev/null
@@ -0,0 +1,64 @@
+
+       vt8623fb - fbdev driver for graphics core in VIA VT8623 chipset
+       ===============================================================
+
+
+Supported Hardware
+==================
+
+       VIA VT8623 [CLE266] chipset and its graphics core
+               (known as CastleRock or Unichrome)
+
+I tested vt8623fb on VIA EPIA ML-6000
+
+
+Supported Features
+==================
+
+       *  4 bpp pseudocolor modes (with 18bit palette, two variants)
+       *  8 bpp pseudocolor mode (with 18bit palette)
+       * 16 bpp truecolor mode (RGB 565)
+       * 32 bpp truecolor mode (RGB 888)
+       * text mode (activated by bpp = 0)
+       * doublescan mode variant (not available in text mode)
+       * panning in both directions
+       * suspend/resume support
+       * DPMS support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (maximum about 100 MHz). This limitation is not enforced by
+driver. Text mode supports 8bit wide fonts only (hardware limitation) and
+16bit tall fonts (driver limitation).
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+       * secondary (not initialized by BIOS) device support
+       * MMIO support
+       * interlaced mode variant
+       * support for fontwidths != 8 in 4 bpp modes
+       * support for fontheight != 16 in text mode
+       * hardware cursor
+       * video overlay support
+       * vsync synchronization
+       * acceleration support (8514-like 2D, busmaster transfers)
+
+
+Known bugs
+==========
+
+       * cursor disable in text mode doesn't work
+
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
index 2291ff620d93e2e220823dd3da8094b60ef709fa..c6322c760348f243a30c61ffc22bd63259c3116a 100644 (file)
@@ -59,6 +59,15 @@ Who: Dan Dennedy <dan@dennedy.org>, Stefan Richter <stefanr@s5r6.in-berlin.de>
 
 ---------------------------
 
+What:  old NCR53C9x driver
+When:  October 2007
+Why:   Replaced by the much better esp_scsi driver.  Actual low-level
+       driver can ported over almost trivially.
+Who:   David Miller <davem@davemloft.net>
+       Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
 What:  Video4Linux API 1 ioctls and video_decoder.h from Video devices.
 When:  December 2006
 Why:   V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
@@ -269,14 +278,6 @@ Who:       Richard Purdie <rpurdie@rpsys.net>
 
 ---------------------------
 
-What:  i8xx_tco watchdog driver
-When:  in 2.6.22
-Why:   the i8xx_tco watchdog driver has been replaced by the iTCO_wdt
-       watchdog driver.
-Who:   Wim Van Sebroeck <wim@iguana.be>
-
----------------------------
-
 What:  Multipath cached routing support in ipv4
 When:  in 2.6.23
 Why:   Code was merged, then submitter immediately disappeared leaving
index 59c14159cc47ddce04a19ae48d559fabedcf6902..d866551be03790c20a00b5f96c41f9226260bcfa 100644 (file)
@@ -54,7 +54,7 @@ ata *);
 
 locking rules:
        all may block, none have BKL
-               i_sem(inode)
+               i_mutex(inode)
 lookup:                yes
 create:                yes
 link:          yes (both)
@@ -74,7 +74,7 @@ setxattr:     yes
 getxattr:      no
 listxattr:     no
 removexattr:   yes
-       Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on
+       Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
        cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
        ->truncate() is never called directly - it's a callback, not a
@@ -461,7 +461,7 @@ doesn't take the BKL.
 ->read on directories probably must go away - we should just enforce -EISDIR
 in sys_read() and friends.
 
-->fsync() has i_sem on inode.
+->fsync() has i_mutex on inode.
 
 --------------------------- dquot_operations -------------------------------
 prototypes:
index 38aba03efc5e1451e91f63d3c9ea0afa3022d90f..fa45c3baed98a7b06418862ccab7d3a2d7a6f49a 100644 (file)
@@ -290,7 +290,7 @@ History
 2.07 More fixes for Warp Server. Now it really works
 2.08 Creating new files is not so slow on large disks
      An attempt to sync deleted file does not generate filesystem error
-2.09 Fixed error on extremly fragmented files
+2.09 Fixed error on extremely fragmented files
 
 
  vim: set textwidth=80:
index 81779068b09bc4b63274460cf0a40977bf4b1bfd..8ee10ec882936d1725e948554da052b3c7d09426 100644 (file)
@@ -349,7 +349,7 @@ end of the line.
 Note the "Should sync?" parameter "nosync" means that the two mirrors are
 already in sync which will be the case on a clean shutdown of Windows.  If the
 mirrors are not clean, you can specify the "sync" option instead of "nosync"
-and the Device-Mapper driver will then copy the entirey of the "Source Device"
+and the Device-Mapper driver will then copy the entirety of the "Source Device"
 to the "Target Device" or if you specified multipled target devices to all of
 them.
 
index 4f3e84c520a5cd844f602ad4e2b8c18c02c48aec..8756a07f4dc34abf3368935f5abb7a1adee228ef 100644 (file)
@@ -229,7 +229,7 @@ Table 1-3: Kernel info in /proc
  mounts      Mounted filesystems                               
  net         Networking info (see text)                        
  partitions  Table of partitions known to the system           
- pci        Depreciated info of PCI bus (new way -> /proc/bus/pci/, 
+ pci        Deprecated info of PCI bus (new way -> /proc/bus/pci/,
              decoupled by lspci                                        (2.4)
  rtc         Real time clock                                   
  scsi        SCSI info (see text)                              
index 7fbb6ffe576910695a5aecabd21c1c428497304f..18d23f9a18c74663e1a7cbcc07232e7879945c5e 100644 (file)
@@ -351,7 +351,7 @@ If the current buffer is full, i.e. all sub-buffers remain unconsumed,
 the callback returns 0 to indicate that the buffer switch should not
 occur yet, i.e. until the consumer has had a chance to read the
 current set of ready sub-buffers.  For the relay_buf_full() function
-to make sense, the consumer is reponsible for notifying the relay
+to make sense, the consumer is responsible for notifying the relay
 interface when sub-buffers have been consumed via
 relay_subbufs_consumed().  Any subsequent attempts to write into the
 buffer will again invoke the subbuf_start() callback with the same
index 6c0cef10eb4d95a9cfe48eed7ec27c0a3a160bee..3cc4010521a019562e68eb070aa83ad78b0e8c4b 100644 (file)
@@ -19,7 +19,7 @@ completely. With execute-in-place, read&write type operations are performed
 directly from/to the memory backed storage device. For file mappings, the
 storage device itself is mapped directly into userspace.
 
-This implementation was initialy written for shared memory segments between
+This implementation was initially written for shared memory segments between
 different virtual machines on s390 hardware to allow multiple machines to
 share the same binaries and libraries.
 
index 9304fb36ae8a91671693bde1fd2644b3085f42f2..b92bfd902a4e4e5784bf34561c189d5493e0f025 100644 (file)
@@ -126,5 +126,5 @@ GDB stub and the debugger:
 
 Furthermore, the GDB stub will intercept a number of exceptions automatically
 if they are caused by kernel execution. It will also intercept BUG() macro
-invokation.
+invocation.
 
index f8528db967fa758ad3afbfcc5f5fed4d170d1b7f..e8be0abb346c1bb95e254d7b9f78072d4e6a0d4c 100644 (file)
@@ -66,7 +66,9 @@ registers; another might implement it by delegating through abstractions
 used for several very different kinds of GPIO controller.
 
 That said, if the convention is supported on their platform, drivers should
-use it when possible:
+use it when possible.  Platforms should declare GENERIC_GPIO support in
+Kconfig (boolean true), which multi-platform drivers can depend on when
+using the include file:
 
        #include <asm/gpio.h>
 
index 473c689d79245761ae3c1ba353391f9277222656..f4327db2307e3105c57db9820b91036fc9be1b97 100644 (file)
@@ -80,7 +80,7 @@ temperature sensor inputs. Both the PWM output and the DAC output can be
 used to control fan speed. Usually only one of these two outputs will be
 used. Write the minimum PWM or DAC value to the appropriate control
 register. Then set the low temperature limit in the tmin values for each
-temperature sensor. The range of control is fixed at 20 °C, and the
+temperature sensor. The range of control is fixed at 20 Â°C, and the
 largest difference between current and tmin of the temperature sensors sets
 the control output. See the datasheet for several example circuits for
 controlling fan speed with the PWM and DAC outputs. The fan speed sensors
index ce0881883bca8ce02479342cdd037dc3daf6dfef..229f8b7891859db136217bc4c6ed7ff60f00694f 100644 (file)
@@ -13,7 +13,7 @@ Supported chips:
 
 Authors:
         Frodo Looijaard <frodol@dds.nl>,
-        Kyösti Mälkki <kmalkki@cc.hut.fi>
+        Kyösti Mälkki <kmalkki@cc.hut.fi>
         Hong-Gunn Chew <hglinux@gunnet.org>
         Jean Delvare <khali@linux-fr.org>
 
index f7aad1489cb00a63ac675f11348f9b8d4cfa8e93..a04d1fe9269cc9f2e129de63a2cdd18625704bca 100644 (file)
@@ -45,7 +45,7 @@ Unconfirmed motherboards:
 The LM82 is confirmed to have been found on most AMD Geode reference
 designs and test platforms.
 
-The driver has been successfully tested by Magnus Forsström, who I'd
+The driver has been successfully tested by Magnus Forsström, who I'd
 like to thank here. More testers will be of course welcome.
 
 The fact that the LM83 is only scarcely used can be easily explained.
index b7ae36b8cdf53bc1ed82c727687543754edf9e92..4f8877a34f37509ac9741627978b8a6d2e157882 100644 (file)
@@ -8,7 +8,7 @@ Supported chips:
     Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
 
 Authors:
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
         Mark D. Studebaker <mdsxyz123@yahoo.com>,
         Aurelien Jarno <aurelien@aurel32.net> 2.6 port
 
index a936fb3824b248c3a3b8bcd6e0efec3314c36432..d651b25f751971df193f3928356d4d492df05bc6 100644 (file)
@@ -8,7 +8,7 @@ Supported chips:
     Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
 
 Authors:
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
         Mark D. Studebaker <mdsxyz123@yahoo.com>
         Bob Dougherty <bobd@stanford.edu>
         (Some conversion-factor data were contributed by
index 8171c285bb55ae198d985b85dc31bd4538f8db71..14a668ed8aaa483a36496c2230778745263ec9fb 100644 (file)
@@ -107,7 +107,7 @@ Known problems:
          by CR[0x49h].
        - The function of vid and vrm has not been finished, because I'm NOT
          very familiar with them. Adding support is welcome.
-       - The function of chassis open detection needs more tests.
+      - The function of chassis open detection needs more tests.
        - If you have ASUS server board and chip was not found: Then you will
          need to upgrade to latest (or beta) BIOS. If it does not help please
          contact us.
index 83c3b9743c3c9cf01702760452dad4fade20ff61..778210ee158381f7219368af99311009d6a59e4f 100644 (file)
@@ -7,7 +7,7 @@ Supported adapters:
 Authors: 
        Frodo Looijaard <frodol@dds.nl>, 
        Philip Edelbrock <phil@netroedge.com>,
-        Kyösti Mälkki <kmalkki@cc.hut.fi>,
+        Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Ralph Metzler <rjkm@thp.uni-koeln.de>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>
 
index 08d7b2dac69af0dd016e5799402c190e626293ae..266481fd26e2de612cd3a87075c6cc103501e961 100644 (file)
@@ -60,7 +60,7 @@ Mark D. Studebaker <mdsxyz123@yahoo.com>
  - design hints and bug fixes
 Alexander Maylsh <amalysh@web.de>
  - ditto, plus an important datasheet... almost the one I really wanted
-Hans-Günter Lütke Uphues <hg_lu@t-online.de>
+Hans-Günter Lütke Uphues <hg_lu@t-online.de>
  - patch for SiS735
 Robert Zwerus <arzie@dds.nl>
  - testing for SiS645DX
index 55edfe1a640be08d1aac5a49dcd5a2f9dd6d9e6c..343870661ac3d01a7d89187629b7690f1d90263d 100644 (file)
@@ -4,7 +4,7 @@ Supported adapters:
   * VIA Technologies, InC. VT82C586B
     Datasheet: Publicly available at the VIA website
 
-Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
 
 Description
 -----------
index 775f489e86f63162d9abe00b1588f4b515704521..06b4be3ef6d8eb0e7f3c94343df92e0009e25c7b 100644 (file)
@@ -17,7 +17,7 @@ Supported adapters:
     Datasheet: available on request and under NDA from VIA
 
 Authors:
-       Kyösti Mälkki <kmalkki@cc.hut.fi>,
+       Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>,
        Jean Delvare <khali@linux-fr.org>
 
index b4022c914210ef10a5a0acf79405dc369c20df0e..579b92d5f3a38c4796d6bcf4c1de559277090974 100644 (file)
@@ -68,7 +68,7 @@ We have found some I2C devices that needs the following modifications:
 
   Flags I2C_M_IGNORE_NAK
     Normally message is interrupted immediately if there is [NA] from the
-    client. Setting this flag treats any [NA] as [A], and all of
+    client. Setting this flag treats any [NA] as [A], and all of
     message is sent.
     These messages may still fail to SCL lo->hi timeout.
 
index 9aa6ddb446eb25d26e43cb7912f38244733b605e..0ebf58c73f54e9acd6bd611033c9639f160e6880 100644 (file)
@@ -30,13 +30,13 @@ Juha Sievanen, University of Helsinki Finland
        Bug fixes
        Core code extensions
 
-Auvo Häkkinen, University of Helsinki Finland
+Auvo Häkkinen, University of Helsinki Finland
        LAN OSM code
        /Proc interface to LAN class
        Bug fixes
        Core code extensions
 
-Taneli Vähäkangas, University of Helsinki Finland
+Taneli Vähäkangas, University of Helsinki Finland
        Fixes to i2o_config
 
 CREDITS
index 6498666ea3307dea2e6e67748c5a4983f0fec590..d01b7a2a0f2eea6bdfa219fb88490fcbb6b80a0e 100644 (file)
@@ -2,7 +2,7 @@
                     ----------------------------
 
                    H. Peter Anvin <hpa@zytor.com>
-                       Last update 2007-03-06
+                       Last update 2007-05-07
 
 On the i386 platform, the Linux kernel uses a rather complicated boot
 convention.  This has evolved partially due to historical aspects, as
@@ -11,7 +11,7 @@ bootable image, the complicated PC memory model and due to changed
 expectations in the PC industry caused by the effective demise of
 real-mode DOS as a mainstream operating system.
 
-Currently, four versions of the Linux/i386 boot protocol exist.
+Currently, the following versions of the Linux/i386 boot protocol exist.
 
 Old kernels:   zImage/Image support only.  Some very early kernels
                may not even support a command line.
@@ -183,9 +183,9 @@ filled out, however:
        a version number.  Otherwise, enter 0xFF here.
 
        Assigned boot loader ids:
-       0  LILO
+       0  LILO                 (0x00 reserved for pre-2.00 bootloader)
        1  Loadlin
-       2  bootsect-loader
+       2  bootsect-loader      (0x20, all other values reserved)
        3  SYSLINUX
        4  EtherBoot
        5  ELILO
@@ -210,6 +210,9 @@ filled out, however:
        additional data (such as the kernel command line) moved in
        addition to the real-mode kernel itself.
 
+       The unit is bytes starting with the beginning of the boot
+       sector.
+
   ramdisk_image, ramdisk_size:
        If your boot loader has loaded an initial ramdisk (initrd),
        set ramdisk_image to the 32-bit pointer to the ramdisk data
@@ -278,14 +281,54 @@ command line is entered using the following protocol:
        field.
 
 
+**** MEMORY LAYOUT OF THE REAL-MODE CODE
+
+The real-mode code requires a stack/heap to be set up, as well as
+memory allocated for the kernel command line.  This needs to be done
+in the real-mode accessible memory in bottom megabyte.
+
+It should be noted that modern machines often have a sizable Extended
+BIOS Data Area (EBDA).  As a result, it is advisable to use as little
+of the low megabyte as possible.
+
+Unfortunately, under the following circumstances the 0x90000 memory
+segment has to be used:
+
+       - When loading a zImage kernel ((loadflags & 0x01) == 0).
+       - When loading a 2.01 or earlier boot protocol kernel.
+
+         -> For the 2.00 and 2.01 boot protocols, the real-mode code
+            can be loaded at another address, but it is internally
+            relocated to 0x90000.  For the "old" protocol, the
+            real-mode code must be loaded at 0x90000.
+
+When loading at 0x90000, avoid using memory above 0x9a000.
+
+For boot protocol 2.02 or higher, the command line does not have to be
+located in the same 64K segment as the real-mode setup code; it is
+thus permitted to give the stack/heap the full 64K segment and locate
+the command line above it.
+
+The kernel command line should not be located below the real-mode
+code, nor should it be located in high memory.
+
+
 **** SAMPLE BOOT CONFIGURATION
 
 As a sample configuration, assume the following layout of the real
-mode segment (this is a typical, and recommended layout):
+mode segment:
+
+    When loading below 0x90000, use the entire segment:
+
+       0x0000-0x7fff   Real mode kernel
+       0x8000-0xdfff   Stack and heap
+       0xe000-0xffff   Kernel command line
 
-       0x0000-0x7FFF   Real mode kernel
-       0x8000-0x8FFF   Stack and heap
-       0x9000-0x90FF   Kernel command line
+    When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+       0x0000-0x7fff   Real mode kernel
+       0x8000-0x97ff   Stack and heap
+       0x9800-0x9fff   Kernel command line
 
 Such a boot loader should enter the following fields in the header:
 
@@ -301,22 +344,33 @@ Such a boot loader should enter the following fields in the header:
                        ramdisk_image = <initrd_address>;
                        ramdisk_size = <initrd_size>;
                }
+
+               if ( protocol >= 0x0202 && loadflags & 0x01 )
+                       heap_end = 0xe000;
+               else
+                       heap_end = 0x9800;
+
                if ( protocol >= 0x0201 ) {
-                       heap_end_ptr = 0x9000 - 0x200;
+                       heap_end_ptr = heap_end - 0x200;
                        loadflags |= 0x80; /* CAN_USE_HEAP */
                }
+
                if ( protocol >= 0x0202 ) {
-                       cmd_line_ptr = base_ptr + 0x9000;
+                       cmd_line_ptr = base_ptr + heap_end;
+                       strcpy(cmd_line_ptr, cmdline);
                } else {
                        cmd_line_magic  = 0xA33F;
-                       cmd_line_offset = 0x9000;
-                       setup_move_size = 0x9100;
+                       cmd_line_offset = heap_end;
+                       setup_move_size = heap_end + strlen(cmdline)+1;
+                       strcpy(base_ptr+cmd_line_offset, cmdline);
                }
        } else {
                /* Very old kernel */
 
+               heap_end = 0x9800;
+
                cmd_line_magic  = 0xA33F;
-               cmd_line_offset = 0x9000;
+               cmd_line_offset = heap_end;
 
                /* A very old kernel MUST have its real-mode code
                   loaded at 0x90000 */
@@ -324,12 +378,11 @@ Such a boot loader should enter the following fields in the header:
                if ( base_ptr != 0x90000 ) {
                        /* Copy the real-mode kernel */
                        memcpy(0x90000, base_ptr, (setup_sects+1)*512);
-                       /* Copy the command line */
-                       memcpy(0x99000, base_ptr+0x9000, 256);
-
                        base_ptr = 0x90000;              /* Relocated */
                }
 
+               strcpy(0x90000+cmd_line_offset, cmdline);
+
                /* It is recommended to clear memory up to the 32K mark */
                memset(0x90000 + (setup_sects+1)*512, 0,
                       (64-(setup_sects+1))*512);
@@ -375,10 +428,11 @@ conflict with actual kernel options now or in the future.
        line is parsed.
 
   mem=<size>
-       <size> is an integer in C notation optionally followed by K, M
-       or G (meaning << 10, << 20 or << 30).  This specifies the end
-       of memory to the kernel. This affects the possible placement
-       of an initrd, since an initrd should be placed near end of
+       <size> is an integer in C notation optionally followed by
+       (case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
+       << 30, << 40, << 50 or << 60).  This specifies the end of
+       memory to the kernel. This affects the possible placement of
+       an initrd, since an initrd should be placed near end of
        memory.  Note that this is an option to *both* the kernel and
        the bootloader!
 
@@ -428,7 +482,7 @@ In our example from above, we would do:
 
        /* Set up the real-mode kernel stack */
        _SS = seg;
-       _SP = 0x9000;   /* Load SP immediately after loading SS! */
+       _SP = heap_end;
 
        _DS = _ES = _FS = _GS = seg;
        jmp_far(seg+0x20, 0);   /* Run the kernel */
@@ -460,8 +514,9 @@ IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
   code32_start:
        A 32-bit flat-mode routine *jumped* to immediately after the
        transition to protected mode, but before the kernel is
-       uncompressed.  No segments, except CS, are set up; you should
-       set them up to KERNEL_DS (0x18) yourself.
+       uncompressed.  No segments, except CS, are guaranteed to be
+       set up (current kernels do, but older ones do not); you should
+       set them up to BOOT_DS (0x18) yourself.
 
        After completing your hook, you should jump to the address
        that was in this field before your boot loader overwrote it.
index 668f4d0d97d60efe0f8fd99538e4b259b19874ff..ab050621e20f7878f19c19392f1007718fd6dddc 100644 (file)
@@ -179,9 +179,9 @@ reporting mode for joystick 1, with both buttons being logically assigned to
 the mouse. After any joystick command, the ikbd assumes that joysticks are
 connected to both Joystick0 and Joystick1. Any mouse command (except MOUSE
 DISABLE) then causes port 0 to again be scanned as if it were a mouse, and
-both buttons are logically connected to it. If a mouse diable command is
+both buttons are logically connected to it. If a mouse disable command is
 received while port 0 is presumed to be a mouse, the button is logically
-assigned to Joystick1 ( until the mouse is reenabled by another mouse command).
+assigned to Joystick1 (until the mouse is reenabled by another mouse command).
 
 9. ikbd Command Set
 
index 5427bdf225ed0392372ff6ce428dd1e68a2aab83..aae0d404c5666a15aba9f56703b4fdb997f009aa 100644 (file)
@@ -65,15 +65,15 @@ of buttons, see section 0.3 - Unknown Controllers
 I've tested this with Stepmania, and it works quite well.
 
 
-0.3 Unkown Controllers
+0.3 Unknown Controllers
 ----------------------
-If you have an unkown xbox controller, it should work just fine with
+If you have an unknown xbox controller, it should work just fine with
 the default settings.
 
 HOWEVER if you have an unknown dance pad not listed below, it will not
 work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
 
-PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with
+PLEASE, if you have an unknown controller, email Dom <binary1230@yahoo.com> with
 a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
 whether it is a dance pad or normal controller) so that we can add your pad
 to the list of supported devices, ensuring that it will work out of the
index e1b3023efaa8701f31886d695adb478a55fcd07f..7c17c837064fbfe7cd5f688de32947f5c4182fe2 100644 (file)
@@ -2,7 +2,7 @@
 I want to thank all who contributed to this project and especially to:
 (in alphabetical order)
 
-Thomas Bogendörfer (tsbogend@bigbug.franken.de)
+Thomas Bogendörfer (tsbogend@bigbug.franken.de)
   Tester, lots of bugfixes and hints.
 
 Alan Cox (alan@redhat.com)
@@ -11,7 +11,7 @@ Alan Cox (alan@redhat.com)
 Henner Eisen (eis@baty.hanse.de)
   For X.25 implementation.
 
-Volker Götz (volker@oops.franken.de)
+Volker Götz (volker@oops.franken.de)
   For contribution of man-pages, the imontty-tool and a perfect
   maintaining of the mailing-list at hub-wue.
 
index 761595243931a93bf300875adcc638a1dbb469b4..6783437f21c2df8563312706fe72974e3f0a0c4c 100644 (file)
@@ -402,7 +402,7 @@ README for the ISDN-subsystem
      the script tools/tcltk/isdnmon. You can add actions for line-status
      changes. See the comments at the beginning of the script for how to
      do that. There are other tty-based tools in the tools-subdirectory
-     contributed by Michael Knigge (imon), Volker Götz (imontty) and
+     contributed by Michael Knigge (imon), Volker Götz (imontty) and
      Andreas Kool (isdnmon).
 
    l) For initial testing, you can set the verbose-level to 2 (default: 0).
index a5f55eadb3ca5d45ad88734e24a93222c2e12675..13f833d4e910c3b385f267359f3b451a38b1ad40 100644 (file)
@@ -3,8 +3,8 @@ $Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
 You can get the ICN-ISDN-card from:
 
 Thinking Objects Software GmbH
-Versbacher Röthe 159
-97078 Würzburg
+Versbacher Röthe 159
+97078 Würzburg
 Tel: +49 931 2877950
 Fax: +49 931 2877951
 
index c768dc63b34e9c73c629a7e15b6444d76a8692e9..3cce3fbb664437a2fb1acf65fda6ff3360e36273 100644 (file)
@@ -390,7 +390,7 @@ the execution bit, then just do
 
 
 originally by Brian A. Lantz, brian@lantz.com
-heavily edited for binfmt_misc by Richard Günther
+heavily edited for binfmt_misc by Richard Günther
 new scripts by Colin J. Watson <cjw44@cam.ac.uk>
 added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
 
index c68dafeda7a70ae6db56523816fa2280cd13e1b9..d9e3b199929bd6fb158576a040e88ee01276561f 100644 (file)
 
      * Title: "Design and Implementation of the Second Extended
        Filesystem"
-       Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
+       Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
        URL: http://web.mit.edu/tytso/www/linux/ext2intro.html
        Keywords: ext2, linux fs history, inode, directory, link, devices,
        VFS, physical structure, performance, benchmarks, ext2fs library,
index 6b8ad06846c449550212b08974f0e6c9de50786a..09220a1e22d964b3ad19a235952a77c2bd9d1cef 100644 (file)
@@ -754,14 +754,6 @@ and is between 256 and 4096 characters. It is defined in the file
        inport.irq=     [HW] Inport (ATI XL and Microsoft) busmouse driver
                        Format: <irq>
 
-       combined_mode=  [HW] control which driver uses IDE ports in combined
-                       mode: legacy IDE driver, libata, or both
-                       (in the libata case, libata.atapi_enabled=1 may be
-                       useful as well).  Note that using the ide or libata
-                       options may affect your device naming (e.g. by
-                       changing hdc to sdb).
-                       Format: combined (default), ide, or libata
-
        inttest=        [IA64]
 
        io7=            [HW] IO7 for Marvel based alpha systems
index ef484a719bb9d528cdce84cbecbfbb06f3c6bf69..3ea9827ba3c797e51b6d531364f5bfb529f5ed05 100644 (file)
@@ -204,7 +204,7 @@ always  shows a "no IRQ here" on the Buddha, and accesses to
 the  third  IDE  port  are  going into data's Nirwana on the
 Buddha.
 
-                           Jens Schönfeld february 19th, 1997
+                           Jens Schönfeld february 19th, 1997
                                        updated may 27th, 1997
                             eMail: sysop@nostlgic.tng.oche.de
 
index 0e740c812d12e4dc3ea77c67601a3937c26b26cb..bd450e797558f5df225f4d7de661e166275e41e4 100644 (file)
@@ -129,7 +129,7 @@ SAVEKMSG_MAGIC1       0x53415645  savekmsg          arch/*/amiga/config.c
 GDA_MAGIC             0x58464552  gda               include/asm-mips64/sn/gda.h
 RED_MAGIC1            0x5a2cf071  (any)             mm/slab.c
 STL_PORTMAGIC         0x5a7182c9  stlport           include/linux/stallion.h
-EEPROM_MAGIC_VALUE    0X5ab478d2  lanai_dev         drivers/atm/lanai.c
+EEPROM_MAGIC_VALUE    0x5ab478d2  lanai_dev         drivers/atm/lanai.c
 HDLCDRV_MAGIC         0x5ac6e778  hdlcdrv_state     include/linux/hdlcdrv.h
 EPCA_MAGIC            0x5c6df104  channel           include/linux/epca.h
 PCXX_MAGIC            0x5c6df104  channel           drivers/char/pcxx.h
index 2202f5dc8ac208381a241bd5fc6b56b73c81ea9a..5818628207b5ec8b5f32ed6d727857f5f6dcbbec 100644 (file)
@@ -178,6 +178,21 @@ All md devices contain:
      The size should be at least PAGE_SIZE (4k) and should be a power
      of 2.  This can only be set while assembling an array
 
+  layout
+     The "layout" for the array for the particular level.  This is
+     simply a number that is interpretted differently by different
+     levels.  It can be written while assembling an array.
+
+  reshape_position
+     This is either "none" or a sector number within the devices of
+     the array where "reshape" is up to.  If this is set, the three
+     attributes mentioned above (raid_disks, chunk_size, layout) can
+     potentially have 2 values, an old and a new value.  If these
+     values differ, reading the attribute returns
+        new (old)
+     and writing will effect the 'new' value, leaving the 'old'
+     unchanged.
+
   component_size
      For arrays with data redundancy (i.e. not raid0, linear, faulty,
      multipath), all components must be the same size - or at least
@@ -193,11 +208,6 @@ All md devices contain:
      1.2 (newer format in varying locations) or "none" indicating that
      the kernel isn't managing metadata at all.
 
-  layout
-     The "layout" for the array for the particular level.  This is
-     simply a number that is interpretted differently by different
-     levels.  It can be written while assembling an array.
-
   resync_start
      The point at which resync should start.  If no resync is needed,
      this will be a very large number.  At array creation it will
@@ -259,29 +269,6 @@ All md devices contain:
          like active, but no writes have been seen for a while (safe_mode_delay).
 
 
-   sync_speed_min
-   sync_speed_max
-     This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
-     however they only apply to the particular array.
-     If no value has been written to these, of if the word 'system'
-     is written, then the system-wide value is used.  If a value,
-     in kibibytes-per-second is written, then it is used.
-     When the files are read, they show the currently active value
-     followed by "(local)" or "(system)" depending on whether it is
-     a locally set or system-wide value.
-
-   sync_completed
-     This shows the number of sectors that have been completed of
-     whatever the current sync_action is, followed by the number of
-     sectors in total that could need to be processed.  The two
-     numbers are separated by a '/'  thus effectively showing one
-     value, a fraction of the process that is complete.
-
-   sync_speed
-     This shows the current actual speed, in K/sec, of the current
-     sync_action.  It is averaged over the last 30 seconds.
-
-
 As component devices are added to an md array, they appear in the 'md'
 directory as new directories named
       dev-XXX
@@ -412,6 +399,35 @@ also have
       Note that the numbers are 'bit' numbers, not 'block' numbers.
       They should be scaled by the bitmap_chunksize.
 
+   sync_speed_min
+   sync_speed_max
+     This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
+     however they only apply to the particular array.
+     If no value has been written to these, of if the word 'system'
+     is written, then the system-wide value is used.  If a value,
+     in kibibytes-per-second is written, then it is used.
+     When the files are read, they show the currently active value
+     followed by "(local)" or "(system)" depending on whether it is
+     a locally set or system-wide value.
+
+   sync_completed
+     This shows the number of sectors that have been completed of
+     whatever the current sync_action is, followed by the number of
+     sectors in total that could need to be processed.  The two
+     numbers are separated by a '/'  thus effectively showing one
+     value, a fraction of the process that is complete.
+
+   sync_speed
+     This shows the current actual speed, in K/sec, of the current
+     sync_action.  It is averaged over the last 30 seconds.
+
+   suspend_lo
+   suspend_hi
+     The two values, given as numbers of sectors, indicate a range
+     within the array where IO will be blocked.  This is currently
+     only supported for raid4/5/6.
+
+
 Each active md device may also have attributes specific to the
 personality module that manages it.
 These are specific to the implementation of the module and could
index a4ffba1694c8fc928ba933c336bee7525c4d02d2..5ecd8d1dcf4e5d93c1031e8fe2ad281fe6b39e76 100644 (file)
@@ -30,7 +30,7 @@ The communication layer exists to allow NetLabel configuration and monitoring
 from user space.  The NetLabel communication layer uses a message based
 protocol built on top of the Generic NETLINK transport mechanism.  The exact
 formatting of these NetLabel messages as well as the Generic NETLINK family
-names can be found in the the 'net/netlabel/' directory as comments in the
+names can be found in the 'net/netlabel/' directory as comments in the
 header files as well as in 'include/net/netlabel.h'.
 
  * Security Module API
index 48ed2b711bd270cce9ccd9fb454bee17a40e3dd6..d0777a1200e1a3a3c224db65cac7fe0d866ea44f 100644 (file)
@@ -1,6 +1,6 @@
 This is the 6pack-mini-HOWTO, written by
 
-Andreas Könsgen DG3KQ
+Andreas Könsgen DG3KQ
 Internet: ajk@iehk.rwth-aachen.de
 AMPR-net: dg3kq@db0pra.ampr.org
 AX.25:    dg3kq@db0ach.#nrw.deu.eu
index fb8dc6422a5212488f362e1a48711afe452f0482..7907435a661c3ed463a2718021f7b5fe4d394f31 100644 (file)
@@ -160,7 +160,7 @@ on current cpu. This primitive is called by dev->poll(), when
 it completes its work. The device cannot be out of poll list at this
 call, if it is then clearly it is a BUG(). You'll know ;->
 
-All these above nethods are used below. So keep reading for clarity.
+All of the above methods are used below, so keep reading for clarity.
 
 Device driver changes to be made when porting NAPI
 ==================================================
index 5a232d946be39fd425c1f9b6c5e821b902b2d465..db0cd51695812cfe2c8850bb80471b422f994e25 100644 (file)
@@ -13,7 +13,7 @@ You can find the latest version of this document at
 
 Please send me your comments to
 
-    Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
+    Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
 
 -------------------------------------------------------------------------------
 + Why use PACKET_MMAP
index 5acf1918694a01e76e89828ee5a345d42e19cd23..bed2f045e5501ea78e9e3ed9755330fa589b5ed3 100644 (file)
@@ -1,7 +1,7 @@
 
 SliceCOM adapter felhasznaloi dokumentacioja - 0.51 verziohoz
 
-Bartók István <bartoki@itc.hu>
+Bartók István <bartoki@itc.hu>
 Utolso modositas: Wed Aug 29 17:26:58 CEST 2001
 
 -----------------------------------------------------------------
index 32d3b916afadfe19718ce5f00ffd436a97481402..c82c0cf981b48aafcca1dbd503fdf9351f95922a 100644 (file)
@@ -1,9 +1,9 @@
 
 SliceCOM adapter user's documentation - for the 0.51 driver version
 
-Written by Bartók István <bartoki@itc.hu>
+Written by Bartók István <bartoki@itc.hu>
 
-English translation: Lakatos György <gyuri@itc.hu>
+English translation: Lakatos György <gyuri@itc.hu>
 Mon Dec 11 15:28:42 CET 2000
 
 Last modified: Wed Aug 29 17:25:37 CEST 2001
index c169a57bc92584704817e116faa9be02a1f9dde7..1f73e13058df6377ea6922b1576a12a9fd5a3169 100644 (file)
@@ -71,24 +71,24 @@ Below find attached the setting for the SK NET TR 4/16 ISA adapters
   CHAPTER 1     LOCATION OF DIP-SWITCH
   ==============================================================
 
-UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-þUÄÄÄÄÄÄ¿                         UÄÄÄÄÄ¿            UÄÄÄ¿         þ
-þAÄÄÄÄÄÄU                      W1 AÄÄÄÄÄU     UÄÄÄÄ¿ þ   þ         þ
-þUÄÄÄÄÄÄ¿                                     þ    þ þ   þ      UÄÄÅ¿
-þAÄÄÄÄÄÄU              UÄÄÄÄÄÄÄÄÄÄÄ¿          AÄÄÄÄU þ   þ      þ  þþ
-þUÄÄÄÄÄÄ¿              þ           þ          UÄÄÄ¿  AÄÄÄU      AÄÄÅU
-þAÄÄÄÄÄÄU              þ TMS380C26 þ          þ   þ                þ
-þUÄÄÄÄÄÄ¿              þ           þ          AÄÄÄU                AÄ¿
-þAÄÄÄÄÄÄU              þ           þ                               þ þ
-þ                      AÄÄÄÄÄÄÄÄÄÄÄU                               þ þ
-þ                                                                  þ þ
-þ                                                                  AÄU
-þ                                                                  þ
-þ                                                                  þ
-þ                                                                  þ
-þ                                                                  þ
-AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
-             AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU  AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
+UÃ\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84Ã\84¿
+þUÄÄÄÄÄÄ¿                         UÄÄÄÄÄ¿            UÄÄÄ¿         þ
+þAÄÄÄÄÄÄU                      W1 AÄÄÄÄÄU     UÄÄÄÄ¿ þ   þ         þ
+þUÃ\84Ã\84Ã\84Ã\84Ã\84Ã\84¿                                     Ã¾    Ã¾ Ã¾   Ã¾      UÃ\84Ã\84Ã\85¿
+þAÄÄÄÄÄÄU              UÄÄÄÄÄÄÄÄÄÄÄ¿          AÄÄÄÄU þ   þ      þ  þþ
+þUÄÄÄÄÄÄ¿              þ           þ          UÄÄÄ¿  AÄÄÄU      AÄÄÅU
+þAÄÄÄÄÄÄU              þ TMS380C26 þ          þ   þ                þ
+þUÃ\84Ã\84Ã\84Ã\84Ã\84Ã\84¿              Ã¾           Ã¾          AÃ\84Ã\84Ã\84U                AÃ\84¿
+þAÄÄÄÄÄÄU              þ           þ                               þ þ
+þ                      AÄÄÄÄÄÄÄÄÄÄÄU                               þ þ
+þ                                                                  þ þ
+þ                                                                  AÄU
+þ                                                                  þ
+þ                                                                  þ
+þ                                                                  þ
+þ                                                                  þ
+AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
+             AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU  AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
 
   ==============================================================
   CHAPTER 2     DEFAULT SETTINGS
@@ -108,9 +108,9 @@ A
   CHAPTER 3     DIP SWITCH W1 DESCRIPTION
   ==============================================================
 
-      UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿  ON
-      þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
-      AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU  OFF
+      UÃ\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84\84Ã\84Ã\84¿  ON
+      þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
+      AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU  OFF
       |AD | BootROM Addr. |  I/O      |
       +-+-+-------+-------+-----+-----+
         |         |             |
index dd6f46b83dab126f70463b3c476a8ad42997979c..6be09ba24a365f25e1c16881f7560d63a2cef3e3 100644 (file)
   3) Disabling the Checksum Computation
 
   On both sender and receiver, checksumming will always be performed
-  and can not be disabled using SO_NO_CHECK. Thus
+  and cannot be disabled using SO_NO_CHECK. Thus
 
         setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK,  ... );
 
index 07dd6d9930a14d22fe30e783e6e59ed38918ad9f..bc2ab419a74aff2f60f147860cc66ff9713ef60f 100644 (file)
@@ -335,7 +335,7 @@ REVISION HISTORY
                                creating applications using BiSync
                                streaming.        
 
-2.0.5   Aug 04, 1999           CHDLC initializatin bug fix.
+2.0.5   Aug 04, 1999           CHDLC initialization bug fix.
                                PPP interrupt driven driver: 
                                Fix to the PPP line hangup problem.
                                New PPP firmware
@@ -372,7 +372,7 @@ REVISION HISTORY
                                o cfgft1 GUI csu/dsu configurator
                                o wancfg GUI configuration file 
                                  configurator.
-                               o Architectual directory changes.
+                               o Architectural directory changes.
 
 beta-2.1.4 Jul 2000            o Dynamic interface configuration:
                                        Network interfaces reflect the state
index e2c9d0a0c43de9de21efbbc5c6e74fe7f544aa06..d38261b679053255986f380acdb91e11dabb354a 100644 (file)
@@ -373,7 +373,7 @@ E.g. clearing pending interrupts.
 
 3.6 Register IRQ handler
 ~~~~~~~~~~~~~~~~~~~~~~~~
-While calling request_irq() is the the last step described here,
+While calling request_irq() is the last step described here,
 this is often just another intermediate step to initialize a device.
 This step can often be deferred until the device is opened for use.
 
index 16c251230c82398a1ad26a3754762e49fc819922..d5da86170106489e608fd032dfee2cb553b398d0 100644 (file)
@@ -13,7 +13,7 @@ Reporting (AER) driver and provides information on how to use it, as
 well as how to enable the drivers of endpoint devices to conform with
 PCI Express AER driver.
 
-1.2 Copyright © Intel Corporation 2006.
+1.2 Copyright Â© Intel Corporation 2006.
 
 1.3 What is the PCI Express AER Driver?
 
index 28037aa1846c89bbf8082007b5e10e470000ac94..481faf515d5360e608b6f4541ef03f759612bc4f 100644 (file)
@@ -140,7 +140,7 @@ Plug and Play but it is planned to be in the near future.
 Requirements for a Linux PnP protocol:
 1.) the protocol must use EISA IDs
 2.) the protocol must inform the PnP Layer of a devices current configuration
-- the ability to set resources is optional but prefered.
+- the ability to set resources is optional but preferred.
 
 The following are PnP protocol related functions:
 
index c55bd5079b90e4ddc654fb8755e93bfca8144560..5b8d6953f05e741b6b6a3dd88e1ee0c6681f680a 100644 (file)
@@ -48,7 +48,7 @@ before suspend (it is limited to 500 MB by default).
 
 Article about goals and implementation of Software Suspend for Linux
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Author: G\82ábor Kuti
+Author: G\82ábor Kuti
 Last revised: 2003-10-20 by Pavel Machek
 
 Idea and goals to achieve
index 000556c932e9fc4a4ede893f997d66833c4902c9..e00c6cf09e85aad17e587f0ac9d19d0a543a4cad 100644 (file)
@@ -93,21 +93,23 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
        to resume the system from RAM if there's enough battery power or restore
        its state on the basis of the saved suspend image otherwise)
 
-SNAPSHOT_PMOPS - enable the usage of the pmops->prepare, pmops->enter and
-       pmops->finish methods (the in-kernel swsusp knows these as the "platform
-       method") which are needed on many machines to (among others) speed up
-       the resume by letting the BIOS skip some steps or to let the system
-       recognise the correct state of the hardware after the resume (in
-       particular on many machines this ensures that unplugged AC
-       adapters get correctly detected and that kacpid does not run wild after
-       the resume).  The last ioctl() argument can take one of the three
-       values, defined in kernel/power/power.h:
+SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
+       hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
+       swsusp knows these as the "platform method") which are needed on many
+       machines to (among others) speed up the resume by letting the BIOS skip
+       some steps or to let the system recognise the correct state of the
+       hardware after the resume (in particular on many machines this ensures
+       that unplugged AC adapters get correctly detected and that kacpid does
+       not run wild after the resume).  The last ioctl() argument can take one
+       of the three values, defined in kernel/power/power.h:
        PMOPS_PREPARE - make the kernel carry out the
-               pm_ops->prepare(PM_SUSPEND_DISK) operation
+               hibernation_ops->prepare() operation
        PMOPS_ENTER - make the kernel power off the system by calling
-               pm_ops->enter(PM_SUSPEND_DISK)
+               hibernation_ops->enter()
        PMOPS_FINISH - make the kernel carry out the
-               pm_ops->finish(PM_SUSPEND_DISK) operation
+               hibernation_ops->finish() operation
+       Note that the actual constants are misnamed because they surface
+       internal kernel implementation details that have changed.
 
 The device's read() operation can be used to transfer the snapshot image from
 the kernel.  It has the following limitations:
index d4bfae75c9465edf74328d2348ffa34773955b39..b49ce169a63aa27d75271a45948b0c1ed8d15ecd 100644 (file)
@@ -1444,7 +1444,7 @@ platforms are moved over to use the flattened-device-tree model.
    Basically, it is a bus of devices, that could act more or less
    as a complete entity (UCC, USB etc ). All of them should be siblings on
    the "root" qe node, using the common properties from there.
-   The description below applies to the the qe of MPC8360 and
+   The description below applies to the qe of MPC8360 and
    more nodes and properties would be extended in the future.
 
    i) Root QE device
@@ -1633,7 +1633,7 @@ platforms are moved over to use the flattened-device-tree model.
      - assignment : function number of the pin according to the Pin Assignment
        tables in User Manual.  Each pin can have up to 4 possible functions in
        QE and two options for CPM.
-     - has_irq : indicates if the pin is used as source of exteral
+     - has_irq : indicates if the pin is used as source of external
        interrupts.
 
    Example:
index 0993969609cf497e50232847aa319716a7b3663b..d30a281c570f025c35234fd52f2a899e29bc0ec2 100644 (file)
@@ -2209,7 +2209,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
 #3  0x5167e6 in readline_internal_char () at readline.c:454
 #4  0x5168ee in readline_internal_charloop () at readline.c:507
 #5  0x51692c in readline_internal () at readline.c:521
-#6  0x5164fe in readline (prompt=0x7ffff810 "\177\81ÿ\81øx\177\81ÿ\81÷\81Ø\177\81ÿ\81øx\81À")
+#6  0x5164fe in readline (prompt=0x7ffff810 "\177\81ÿ\81øx\177\81ÿ\81÷\81Ø\177\81ÿ\81øx\81À")
     at readline.c:349
 #7  0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1,
     annotation_suffix=0x4d6b44 "prompt") at top.c:2091
index 2368e7e4a8cfa9d64c27c0b9932c79e5e3f378f0..ce3cb42507bd1edd5c0495af1a1ba6edb1b764a8 100644 (file)
@@ -98,8 +98,8 @@ Supported Cards/Chipsets
        9005:0285:9005:02b0             (Sunrise Lake ARK)
        9005:0285:9005:02b1     Adaptec (Voodoo 8 internal 8 external)
        9005:0285:108e:7aac     SUN     STK RAID REM (Voodoo44 Coyote)
-       9005:0285:108e:0286     SUN     SG-XPCIESAS-R-IN (Cougar)
-       9005:0285:108e:0287     SUN     SG-XPCIESAS-R-EX (Prometheus)
+       9005:0285:108e:0286     SUN     STK RAID INT (Cougar)
+       9005:0285:108e:0287     SUN     STK RAID EXT (Prometheus)
 
 People
 -------------------------
index 2ce022cec9be6a57cc3bc26926f19e386672a81f..29ce6d87e451b37627b5fe6fbbfd584fbc79b165 100644 (file)
@@ -1,7 +1,7 @@
 $Id: README.aha152x,v 1.2 1999/12/25 15:32:30 fischer Exp fischer $
 Adaptec AHA-1520/1522 SCSI driver for Linux (aha152x)
 
-Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
+Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
 TC1550 patches by Luuk van Dijk (ldz@xs4all.nl)
 
 
index 9b894f116d95b364d3c8cc862eaf1d7eb97d1b4e..5f34d2ba69b47ce0e4571ac5288a3415c314c05d 100644 (file)
@@ -40,7 +40,7 @@ The following information is available in this file:
    2.   Multi-function Twin Channel Device - Two controllers on one chip.
    3.   Command Channel Secondary DMA Engine - Allows scatter gather list
         and SCB prefetch.
-   4.   64 Byte SCB Support - Allows disconnected, unttagged request table
+   4.   64 Byte SCB Support - Allows disconnected, untagged request table
         for all possible target/lun combinations.
    5.   Block Move Instruction Support - Doubles the speed of certain
         sequencer operations.
index 05667e7308d40cfecad6cefbedfcc7bbaedcffd0..7bd210ab45a1baacc566c551ab4f248ef51874a9 100644 (file)
@@ -356,7 +356,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
         or enable Tagged Command Queueing (TCQ) on specific devices.  As of
        driver version 5.1.11, TCQ is now either on or off by default
        according to the setting you choose during the make config process.
-       In order to en/disable TCQ for certian devices at boot time, a user
+       In order to en/disable TCQ for certain devices at boot time, a user
        may use this boot param.  The driver will then parse this message out
         and en/disable the specific device entries that are present based upon
         the value given.  The param line is parsed in the following manner:
index 88ef88b949f7140bf4d59476aecf7fbca09f7409..39d409a8efe57709e2c1c17b6f5e76f0fceef483 100644 (file)
@@ -1260,7 +1260,7 @@ then the request of the IRQ obviously will not succeed for all the drivers.
 15.1 Problem tracking
 
 Most SCSI problems are due to a non conformant SCSI bus or to buggy
-devices.  If infortunately you have SCSI problems, you can check the
+devices.  If unfortunately you have SCSI problems, you can check the
 following things:
 
 - SCSI bus cables
index 3c12422f7f41bf67cc6d365937090a81176eb0e0..b7be95b5bd24f1a53431ef0d45ddb85b2832c3a9 100644 (file)
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-The driver is currently maintained by Kai Mäkisara (email
+The driver is currently maintained by Kai Mäkisara (email
 Kai.Makisara@kolumbus.fi)
 
 Last modified: Mon Mar  7 21:14:44 2005 by kai.makisara
index 2c1745a9df0052fa634489d3f4b43dd1828a078b..3d9f06bb3d005df531abccda5ba5ad11f820b363 100644 (file)
@@ -587,7 +587,7 @@ devices, ... may cause a SCSI signal to be wrong when te driver reads it.
 15.1 Problem tracking
 
 Most SCSI problems are due to a non conformant SCSI bus or too buggy
-devices.  If infortunately you have SCSI problems, you can check the
+devices.  If unfortunately you have SCSI problems, you can check the
 following things:
 
 - SCSI bus cables
index 8b2168aa4fc7e25d318b9127d1f58d43629665ad..61c0531e044a75f68f4eea49f846d78d42f55194 100644 (file)
@@ -426,7 +426,7 @@ Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and
 all the others for the wonderful OS and software.
 Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
 release and support.
-Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
+Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
 Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
 Tonneau) for intensively testing the driver (and even risking data loss
 doing this during early revisions).
index c1237a9255055635475552c519f8199303789c8e..4857acfc50f1fa025f71b7d49cd0066381642750 100644 (file)
@@ -1,7 +1,7 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
        Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
-       Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+       Copyright (C) 2001-2002 Alcôve <www.alcove.com>
        Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
        Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
        Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
index 858334bb46b08890cba4168e208e6eff5868c2c5..5fbcb160927589fc54f38ac423a54a85692ff11c 100644 (file)
@@ -163,7 +163,7 @@ OR the Default= line COULD be
 Default=SBPRO
 
 Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure
-the sound modules and voilà - ThinkPad sound with Linux.
+the sound modules and voilà - ThinkPad sound with Linux.
 
 Now the gotchas - you can either have CD sound OR Mixers but not both. That's a
 problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why
index 5922e84d913340b98891a8e583663ab55ad3c5a6..111fd28727ec3754931d5de68ab21037871382c0 100644 (file)
@@ -221,14 +221,14 @@ Controls the kernel's behaviour when an oops or BUG is encountered.
 
 0: try to continue operation
 
-1: panic immediatly.  If the `panic' sysctl is also non-zero then the
+1: panic immediately.  If the `panic' sysctl is also non-zero then the
    machine will be rebooted.
 
 ==============================================================
 
 pid_max:
 
-PID allocation wrap value.  When the kenrel's next PID value
+PID allocation wrap value.  When the kernel's next PID value
 reaches this value, it wraps back to a minimum PID value.
 PIDs of value pid_max or larger are not allocated.
 
index 27a721635f924808f1953e3a1e9cf3fdecd487a4..67c59cdc9959b4f6d0987fc5d87dee809d24c91b 100644 (file)
@@ -65,7 +65,7 @@ THANKS file in Inaky's driver):
           will sell keyboards to some of the 3 million (at least)
           Linux users.
 
-        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
           It was almost impossible to get a PC backplate USB connector
           for the motherboard here at Europe (mine, home-made, was
           quite lousy :). Now I know where to acquire nice USB stuff!
index b18e86a225068c212e18a141a940b2481be59209..5b635ae849443a1deae12b9f0c0019cc06bcc4e5 100644 (file)
@@ -45,9 +45,9 @@ ConnectTech WhiteHEAT 4 port converter
   Connect Tech's Support Department at support@connecttech.com
 
 
-HandSpring Visor, Palm USB, and Clié USB driver
+HandSpring Visor, Palm USB, and Clié USB driver
 
-  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
+  This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
   devices.
 
   Only when the device tries to connect to the host, will the device show
@@ -69,7 +69,7 @@ HandSpring Visor, Palm USB, and Cli
   the port to use for the HotSync transfer. The "Generic" port can be used
   for other device communication, such as a PPP link.
 
-  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
+  For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
   device.  This is true for all OS version 3.5 devices, and most devices
   that have had a flash upgrade to a newer version of the OS.  See the
   kernel system log for information on which is the correct port to use.
index a4b7ae800866c4ad6411187d7a65e1f021f7bbe5..a747200fe67c5b7d4bdcae47bdee0ee2508ce3bd 100644 (file)
@@ -8,7 +8,7 @@ Background:
 
   This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
   is a USB 2.0 hosted TV Tuner.  This driver is a work in progress.
-  Its history started with the reverse-engineering effort by Björn
+  Its history started with the reverse-engineering effort by Björn
   Danielsson <pvrusb2@dax.nu> whose web page can be found here:
 
     http://pvrusb2.dax.nu/
index 85c575ac4fb982dfbfe16e7258c4b7f0909633cb..295462b2317a46a3c191c446030030efea063bdb 100644 (file)
@@ -242,7 +242,7 @@ can generate: PAL , NTSC , SECAM
 
 Conexant bt866 TV encoder
 is used in AVS6EYES, and
-can generate: NTSC/PAL, PAL­M, PAL­N
+can generate: NTSC/PAL, PAL­M, PAL­N
 
 The adv717x, should be able to produce PAL N. But you find nothing PAL N
 specific in the registers. Seem that you have to reuse a other standard
index 5e51c59bf2b024e2915d747e76f63d00e11d53f9..bf3af5fe558f09e37b5ad2d7e06e6c36ca63c2c1 100644 (file)
@@ -1,7 +1,7 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
        Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
-       Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+       Copyright (C) 2001-2002 Alcôve <www.alcove.com>
        Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
index 79af610d4ba59175ebabcb3cb18c58dfc937d914..b3326b167ada592b0d2b7eb7e408d299509ae92d 100644 (file)
@@ -195,11 +195,11 @@ MODULE PARAMETERS:
   NAME: bandingfilter
   TYPE: integer (Boolean)
   DEFAULT: 0 (off)
-  DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
+  DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
        or stabilizes the "banding" caused by some artificial light sources
        (especially fluorescent). You might have to set lightfreq correctly for
        this to work right. As an added bonus, this sometimes makes it
-       possible to capture your monitor´s output.
+       possible to capture your monitor´s output.
 
   NAME: fastset
   TYPE: integer (Boolean)
index 41710ccf3a29a1f138537de5c96d00f429289096..686a8e04a4f3c3902ff130b571fc8af53776c542 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdarg.h>
 #include <getopt.h>
 #include <regex.h>
+#include <errno.h>
 
 #define MAX_SLABS 500
 #define MAX_ALIASES 500
@@ -41,12 +42,15 @@ struct aliasinfo {
 } aliasinfo[MAX_ALIASES];
 
 int slabs = 0;
+int actual_slabs = 0;
 int aliases = 0;
 int alias_targets = 0;
 int highest_node = 0;
 
 char buffer[4096];
 
+int show_empty = 0;
+int show_report = 0;
 int show_alias = 0;
 int show_slab = 0;
 int skip_zero = 1;
@@ -59,6 +63,15 @@ int show_inverted = 0;
 int show_single_ref = 0;
 int show_totals = 0;
 int sort_size = 0;
+int set_debug = 0;
+int show_ops = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
 
 int page_size;
 
@@ -76,20 +89,33 @@ void fatal(const char *x, ...)
 
 void usage(void)
 {
-       printf("slabinfo [-ahnpvtsz] [slab-regexp]\n"
+       printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
+               "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
                "-a|--aliases           Show aliases\n"
+               "-d<options>|--debug=<options> Set/Clear Debug options\n"
+               "-e|--empty             Show empty slabs\n"
+               "-f|--first-alias       Show first alias\n"
                "-h|--help              Show usage information\n"
+               "-i|--inverted          Inverted list\n"
+               "-l|--slabs             Show slabs\n"
                "-n|--numa              Show NUMA information\n"
+               "-o|--ops               Show kmem_cache_ops\n"
                "-s|--shrink            Shrink slabs\n"
-               "-v|--validate          Validate slabs\n"
+               "-r|--report            Detailed report on single slabs\n"
+               "-S|--Size              Sort by size\n"
                "-t|--tracking          Show alloc/free information\n"
                "-T|--Totals            Show summary information\n"
-               "-l|--slabs             Show slabs\n"
-               "-S|--Size              Sort by size\n"
+               "-v|--validate          Validate slabs\n"
                "-z|--zero              Include empty slabs\n"
-               "-f|--first-alias       Show first alias\n"
-               "-i|--inverted          Inverted list\n"
                "-1|--1ref              Single reference\n"
+               "\nValid debug options (FZPUT may be combined)\n"
+               "a / A          Switch on all debug options (=FZUP)\n"
+               "-              Switch off all debug options\n"
+               "f / F          Sanity Checks (SLAB_DEBUG_FREE)\n"
+               "z / Z          Redzoning\n"
+               "p / P          Poisoning\n"
+               "u / U          Tracking\n"
+               "t / T          Tracing\n"
        );
 }
 
@@ -143,11 +169,10 @@ unsigned long get_obj_and_str(char *name, char **x)
 void set_obj(struct slabinfo *s, char *name, int n)
 {
        char x[100];
+       FILE *f;
 
        sprintf(x, "%s/%s", s->name, name);
-
-       FILE *f = fopen(x, "w");
-
+       f = fopen(x, "w");
        if (!f)
                fatal("Cannot write to %s\n", x);
 
@@ -155,6 +180,26 @@ void set_obj(struct slabinfo *s, char *name, int n)
        fclose(f);
 }
 
+unsigned long read_slab_obj(struct slabinfo *s, char *name)
+{
+       char x[100];
+       FILE *f;
+       int l;
+
+       sprintf(x, "%s/%s", s->name, name);
+       f = fopen(x, "r");
+       if (!f) {
+               buffer[0] = 0;
+               l = 0;
+       } else {
+               l = fread(buffer, 1, sizeof(buffer), f);
+               buffer[l] = 0;
+               fclose(f);
+       }
+       return l;
+}
+
+
 /*
  * Put a size string together
  */
@@ -226,7 +271,7 @@ int line = 0;
 
 void first_line(void)
 {
-       printf("Name                 Objects   Objsize    Space "
+       printf("Name                   Objects Objsize    Space "
                "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
 }
 
@@ -246,10 +291,7 @@ struct aliasinfo *find_one_alias(struct slabinfo *find)
                                        return best;
                        }
        }
-       if (best)
-               return best;
-       fatal("Cannot find alias for %s\n", find->name);
-       return NULL;
+       return best;
 }
 
 unsigned long slab_size(struct slabinfo *s)
@@ -257,6 +299,126 @@ unsigned long slab_size(struct slabinfo *s)
        return  s->slabs * (page_size << s->order);
 }
 
+void slab_numa(struct slabinfo *s, int mode)
+{
+       int node;
+
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (!highest_node) {
+               printf("\n%s: No NUMA information available.\n", s->name);
+               return;
+       }
+
+       if (skip_zero && !s->slabs)
+               return;
+
+       if (!line) {
+               printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
+               for(node = 0; node <= highest_node; node++)
+                       printf(" %4d", node);
+               printf("\n----------------------");
+               for(node = 0; node <= highest_node; node++)
+                       printf("-----");
+               printf("\n");
+       }
+       printf("%-21s ", mode ? "All slabs" : s->name);
+       for(node = 0; node <= highest_node; node++) {
+               char b[20];
+
+               store_size(b, s->numa[node]);
+               printf(" %4s", b);
+       }
+       printf("\n");
+       if (mode) {
+               printf("%-21s ", "Partial slabs");
+               for(node = 0; node <= highest_node; node++) {
+                       char b[20];
+
+                       store_size(b, s->numa_partial[node]);
+                       printf(" %4s", b);
+               }
+               printf("\n");
+       }
+       line++;
+}
+
+void show_tracking(struct slabinfo *s)
+{
+       printf("\n%s: Kernel object allocation\n", s->name);
+       printf("-----------------------------------------------------------------------\n");
+       if (read_slab_obj(s, "alloc_calls"))
+               printf(buffer);
+       else
+               printf("No Data\n");
+
+       printf("\n%s: Kernel object freeing\n", s->name);
+       printf("------------------------------------------------------------------------\n");
+       if (read_slab_obj(s, "free_calls"))
+               printf(buffer);
+       else
+               printf("No Data\n");
+
+}
+
+void ops(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (read_slab_obj(s, "ops")) {
+               printf("\n%s: kmem_cache operations\n", s->name);
+               printf("--------------------------------------------\n");
+               printf(buffer);
+       } else
+               printf("\n%s has no kmem_cache operations\n", s->name);
+}
+
+const char *onoff(int x)
+{
+       if (x)
+               return "On ";
+       return "Off";
+}
+
+void report(struct slabinfo *s)
+{
+       if (strcmp(s->name, "*") == 0)
+               return;
+       printf("\nSlabcache: %-20s  Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order);
+       if (s->hwcache_align)
+               printf("** Hardware cacheline aligned\n");
+       if (s->cache_dma)
+               printf("** Memory is allocated in a special DMA zone\n");
+       if (s->destroy_by_rcu)
+               printf("** Slabs are destroyed via RCU\n");
+       if (s->reclaim_account)
+               printf("** Reclaim accounting active\n");
+
+       printf("\nSizes (bytes)     Slabs              Debug                Memory\n");
+       printf("------------------------------------------------------------------------\n");
+       printf("Object : %7d  Total  : %7ld   Sanity Checks : %s  Total: %7ld\n",
+                       s->object_size, s->slabs, onoff(s->sanity_checks),
+                       s->slabs * (page_size << s->order));
+       printf("SlabObj: %7d  Full   : %7ld   Redzoning     : %s  Used : %7ld\n",
+                       s->slab_size, s->slabs - s->partial - s->cpu_slabs,
+                       onoff(s->red_zone), s->objects * s->object_size);
+       printf("SlabSiz: %7d  Partial: %7ld   Poisoning     : %s  Loss : %7ld\n",
+                       page_size << s->order, s->partial, onoff(s->poison),
+                       s->slabs * (page_size << s->order) - s->objects * s->object_size);
+       printf("Loss   : %7d  CpuSlab: %7d   Tracking      : %s  Lalig: %7ld\n",
+                       s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
+                       (s->slab_size - s->object_size) * s->objects);
+       printf("Align  : %7d  Objects: %7d   Tracing       : %s  Lpadd: %7ld\n",
+                       s->align, s->objs_per_slab, onoff(s->trace),
+                       ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
+                       s->slabs);
+
+       ops(s);
+       show_tracking(s);
+       slab_numa(s, 1);
+}
 
 void slabcache(struct slabinfo *s)
 {
@@ -265,7 +427,18 @@ void slabcache(struct slabinfo *s)
        char flags[20];
        char *p = flags;
 
-       if (skip_zero && !s->slabs)
+       if (strcmp(s->name, "*") == 0)
+               return;
+
+       if (actual_slabs == 1) {
+               report(s);
+               return;
+       }
+
+       if (skip_zero && !show_empty && !s->slabs)
+               return;
+
+       if (show_empty && s->slabs)
                return;
 
        store_size(size_str, slab_size(s));
@@ -303,48 +476,128 @@ void slabcache(struct slabinfo *s)
                flags);
 }
 
-void slab_numa(struct slabinfo *s)
+/*
+ * Analyze debug options. Return false if something is amiss.
+ */
+int debug_opt_scan(char *opt)
 {
-       int node;
+       if (!opt || !opt[0] || strcmp(opt, "-") == 0)
+               return 1;
+
+       if (strcasecmp(opt, "a") == 0) {
+               sanity = 1;
+               poison = 1;
+               redzone = 1;
+               tracking = 1;
+               return 1;
+       }
 
-       if (!highest_node)
-               fatal("No NUMA information available.\n");
+       for ( ; *opt; opt++)
+               switch (*opt) {
+               case 'F' : case 'f':
+                       if (sanity)
+                               return 0;
+                       sanity = 1;
+                       break;
+               case 'P' : case 'p':
+                       if (poison)
+                               return 0;
+                       poison = 1;
+                       break;
 
-       if (skip_zero && !s->slabs)
-               return;
+               case 'Z' : case 'z':
+                       if (redzone)
+                               return 0;
+                       redzone = 1;
+                       break;
 
-       if (!line) {
-               printf("\nSlab             Node ");
-               for(node = 0; node <= highest_node; node++)
-                       printf(" %4d", node);
-               printf("\n----------------------");
-               for(node = 0; node <= highest_node; node++)
-                       printf("-----");
-               printf("\n");
-       }
-       printf("%-21s ", s->name);
-       for(node = 0; node <= highest_node; node++) {
-               char b[20];
+               case 'U' : case 'u':
+                       if (tracking)
+                               return 0;
+                       tracking = 1;
+                       break;
 
-               store_size(b, s->numa[node]);
-               printf(" %4s", b);
-       }
-       printf("\n");
-       line++;
+               case 'T' : case 't':
+                       if (tracing)
+                               return 0;
+                       tracing = 1;
+                       break;
+               default:
+                       return 0;
+               }
+       return 1;
 }
 
-void show_tracking(struct slabinfo *s)
+int slab_empty(struct slabinfo *s)
 {
-       printf("\n%s: Calls to allocate a slab object\n", s->name);
-       printf("---------------------------------------------------\n");
-       if (read_obj("alloc_calls"))
-               printf(buffer);
+       if (s->objects > 0)
+               return 0;
 
-       printf("%s: Calls to free a slab object\n", s->name);
-       printf("-----------------------------------------------\n");
-       if (read_obj("free_calls"))
-               printf(buffer);
+       /*
+        * We may still have slabs even if there are no objects. Shrinking will
+        * remove them.
+        */
+       if (s->slabs != 0)
+               set_obj(s, "shrink", 1);
 
+       return 1;
+}
+
+void slab_debug(struct slabinfo *s)
+{
+       if (sanity && !s->sanity_checks) {
+               set_obj(s, "sanity", 1);
+       }
+       if (!sanity && s->sanity_checks) {
+               if (slab_empty(s))
+                       set_obj(s, "sanity", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
+       }
+       if (redzone && !s->red_zone) {
+               if (slab_empty(s))
+                       set_obj(s, "red_zone", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
+       }
+       if (!redzone && s->red_zone) {
+               if (slab_empty(s))
+                       set_obj(s, "red_zone", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
+       }
+       if (poison && !s->poison) {
+               if (slab_empty(s))
+                       set_obj(s, "poison", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
+       }
+       if (!poison && s->poison) {
+               if (slab_empty(s))
+                       set_obj(s, "poison", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
+       }
+       if (tracking && !s->store_user) {
+               if (slab_empty(s))
+                       set_obj(s, "store_user", 1);
+               else
+                       fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
+       }
+       if (!tracking && s->store_user) {
+               if (slab_empty(s))
+                       set_obj(s, "store_user", 0);
+               else
+                       fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
+       }
+       if (tracing && !s->trace) {
+               if (slabs == 1)
+                       set_obj(s, "trace", 1);
+               else
+                       fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
+       }
+       if (!tracing && s->trace)
+               set_obj(s, "trace", 1);
 }
 
 void totals(void)
@@ -673,7 +926,7 @@ void link_slabs(void)
 
        for (a = aliasinfo; a < aliasinfo + aliases; a++) {
 
-               for(s = slabinfo; s < slabinfo + slabs; s++)
+               for (s = slabinfo; s < slabinfo + slabs; s++)
                        if (strcmp(a->ref, s->name) == 0) {
                                a->slab = s;
                                s->refs++;
@@ -704,7 +957,7 @@ void alias(void)
                                        continue;
                                }
                        }
-                       printf("\n%-20s <- %s", a->slab->name, a->name);
+                       printf("\n%-12s <- %s", a->slab->name, a->name);
                        active = a->slab->name;
                }
                else
@@ -729,7 +982,12 @@ void rename_slabs(void)
 
                a = find_one_alias(s);
 
-               s->name = a->name;
+               if (a)
+                       s->name = a->name;
+               else {
+                       s->name = "*";
+                       actual_slabs--;
+               }
        }
 }
 
@@ -748,11 +1006,14 @@ void read_slab_dir(void)
        char *t;
        int count;
 
+       if (chdir("/sys/slab"))
+               fatal("SYSFS support for SLUB not active\n");
+
        dir = opendir(".");
        while ((de = readdir(dir))) {
                if (de->d_name[0] == '.' ||
-                               slab_mismatch(de->d_name))
-                       continue;
+                       (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+                               continue;
                switch (de->d_type) {
                   case DT_LNK:
                        alias->name = strdup(de->d_name);
@@ -807,6 +1068,7 @@ void read_slab_dir(void)
        }
        closedir(dir);
        slabs = slab - slabinfo;
+       actual_slabs = slabs;
        aliases = alias - aliasinfo;
        if (slabs > MAX_SLABS)
                fatal("Too many slabs\n");
@@ -825,34 +1087,37 @@ void output_slabs(void)
 
 
                if (show_numa)
-                       slab_numa(slab);
-               else
-               if (show_track)
+                       slab_numa(slab, 0);
+               else if (show_track)
                        show_tracking(slab);
-               else
-               if (validate)
+               else if (validate)
                        slab_validate(slab);
-               else
-               if (shrink)
+               else if (shrink)
                        slab_shrink(slab);
-               else {
-                       if (show_slab)
-                               slabcache(slab);
-               }
+               else if (set_debug)
+                       slab_debug(slab);
+               else if (show_ops)
+                       ops(slab);
+               else if (show_slab)
+                       slabcache(slab);
        }
 }
 
 struct option opts[] = {
        { "aliases", 0, NULL, 'a' },
-       { "slabs", 0, NULL, 'l' },
-       { "numa", 0, NULL, 'n' },
-       { "zero", 0, NULL, 'z' },
-       { "help", 0, NULL, 'h' },
-       { "validate", 0, NULL, 'v' },
+       { "debug", 2, NULL, 'd' },
+       { "empty", 0, NULL, 'e' },
        { "first-alias", 0, NULL, 'f' },
+       { "help", 0, NULL, 'h' },
+       { "inverted", 0, NULL, 'i'},
+       { "numa", 0, NULL, 'n' },
+       { "ops", 0, NULL, 'o' },
+       { "report", 0, NULL, 'r' },
        { "shrink", 0, NULL, 's' },
+       { "slabs", 0, NULL, 'l' },
        { "track", 0, NULL, 't'},
-       { "inverted", 0, NULL, 'i'},
+       { "validate", 0, NULL, 'v' },
+       { "zero", 0, NULL, 'z' },
        { "1ref", 0, NULL, '1'},
        { NULL, 0, NULL, 0 }
 };
@@ -864,10 +1129,9 @@ int main(int argc, char *argv[])
        char *pattern_source;
 
        page_size = getpagesize();
-       if (chdir("/sys/slab"))
-               fatal("This kernel does not have SLUB support.\n");
 
-       while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1)
+       while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
+                                               opts, NULL)) != -1)
        switch(c) {
                case '1':
                        show_single_ref = 1;
@@ -875,6 +1139,14 @@ int main(int argc, char *argv[])
                case 'a':
                        show_alias = 1;
                        break;
+               case 'd':
+                       set_debug = 1;
+                       if (!debug_opt_scan(optarg))
+                               fatal("Invalid debug option '%s'\n", optarg);
+                       break;
+               case 'e':
+                       show_empty = 1;
+                       break;
                case 'f':
                        show_first_alias = 1;
                        break;
@@ -887,6 +1159,12 @@ int main(int argc, char *argv[])
                case 'n':
                        show_numa = 1;
                        break;
+               case 'o':
+                       show_ops = 1;
+                       break;
+               case 'r':
+                       show_report = 1;
+                       break;
                case 's':
                        shrink = 1;
                        break;
@@ -914,8 +1192,8 @@ int main(int argc, char *argv[])
 
        }
 
-       if (!show_slab && !show_alias && !show_track
-               && !validate && !shrink)
+       if (!show_slab && !show_alias && !show_track && !show_report
+               && !validate && !shrink && !set_debug && !show_ops)
                        show_slab = 1;
 
        if (argc > optind)
index 41a4b477c57637b62824819e953830284ed4caa4..bd558ac5bb73ced7de418089a9ae499732cfe3c9 100644 (file)
@@ -1038,6 +1038,8 @@ S:        Maintained
 CONEXANT ACCESSRUNNER USB DRIVER
 P:     Simon Arlott
 M:     cxacru@fire.lp0.eu
+L:     accessrunner-general@lists.sourceforge.net
+W:     http://accessrunner.sourceforge.net/
 S:     Maintained
 
 CORETEMP HARDWARE MONITORING DRIVER
@@ -1716,12 +1718,6 @@ P:       H. Peter Anvin
 M:     hpa@zytor.com
 S:     Maintained
 
-i810 TCO TIMER WATCHDOG
-P:     Nils Faerber
-M:     nils@kernelconcepts.de
-W:     http://www.kernelconcepts.de/
-S:     Maintained
-
 IA64 (Itanium) PLATFORM
 P:     Tony Luck
 M:     tony.luck@intel.com
@@ -2646,6 +2642,12 @@ M:       corbet@lwn.net
 L:     video4linux-list@redhat.com
 S:     Maintained
 
+ONENAND FLASH DRIVER
+P:     Kyungmin Park
+M:     kyungmin.park@samsung.com
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+
 ONSTREAM SCSI TAPE DRIVER
 P:     Willem Riede
 M:     osst@riede.org
@@ -2800,7 +2802,7 @@ L:        linux-abi-devel@lists.sourceforge.net
 S:     Maintained
 
 PHRAM MTD DRIVER
-P:     Jörn Engel
+P:     Jörn Engel
 M:     joern@wh.fh-wedel.de
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
@@ -3074,7 +3076,7 @@ T:        git kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
 S:     Maintained
 
 SCSI TAPE DRIVER
-P:     Kai Mäkisara
+P:     Kai Mäkisara
 M:     Kai.Makisara@kolumbus.fi
 L:     linux-scsi@vger.kernel.org
 S:     Maintained
index 0d8fac3b03713020cf4ad3dc98eab209cbc0a5a1..d7c0984d4a8662a48fc47f2d922ab8cb7806b030 100644 (file)
@@ -354,6 +354,7 @@ config ARCH_SA1100
 config ARCH_S3C2410
        bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
        select GENERIC_GPIO
+       select GENERIC_TIME
        help
          Samsung S3C2410X CPU based systems, such as the Simtec Electronics
          BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
index ab9f2d4bd04ed0a15b948381070c99eff7d7626b..00ea4305ad5d2bb1e1d690544235a852793e5986 100644 (file)
@@ -47,8 +47,13 @@ comma = ,
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7)                :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7a,-march=armv5t -Wa$(comma)-march=armv7a)
 arch-$(CONFIG_CPU_32v6)                :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+# Only override the compiler option if ARMv6. The ARMv6K extensions are
+# always available in ARMv7
+ifeq ($(CONFIG_CPU_32v6),y)
 arch-$(CONFIG_CPU_32v6K)       :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+endif
 arch-$(CONFIG_CPU_32v5)                :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
 arch-$(CONFIG_CPU_32v4T)       :=-D__LINUX_ARM_ARCH__=4 -march=armv4t
 arch-$(CONFIG_CPU_32v4)                :=-D__LINUX_ARM_ARCH__=4 -march=armv4
index 0119c0d5f9788009b30cd135b3a8b51dda9c354d..5d78ffb8a9a7fe0e653f9356d5b873896492a53c 100644 (file)
@@ -33,7 +33,7 @@
  * numbers for r1.
  *
  */
-       __INIT
+       .section ".text.head", "ax"
        .type   stext, %function
 ENTRY(stext)
        msr     cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
index 1d35edacc01113af898946e8d5b33f4b7a0dc17d..41f98b4ba2ee256d5998a514dd20bcf250bad577 100644 (file)
@@ -73,7 +73,7 @@
  * crap here - that's what the boot loader (or in extreme, well justified
  * circumstances, zImage) is for.
  */
-       __INIT
+       .section ".text.head", "ax"
        .type   stext, %function
 ENTRY(stext)
        msr     cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
index a00cca0000bd2782bcfe50eee16e6c7b412f4aef..bd4ef53bc6b95ee03f8eac412e03563146a27a4f 100644 (file)
@@ -31,7 +31,7 @@ EXPORT_SYMBOL(init_mm);
  * The things we do for performance..
  */
 union thread_union init_thread_union
-       __attribute__((__section__(".init.task"))) =
+       __attribute__((__section__(".data.init_task"))) =
                { INIT_THREAD_INFO(init_task) };
 
 /*
index 1b061583408ed7f44158a7dfcf7b996e56f7a53f..79b7e5cf5416cff90059fd145ca6a2c76d253011 100644 (file)
@@ -116,8 +116,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 
                        offset += sym->st_value - loc;
                        if (offset & 3 ||
-                           offset <= (s32)0xfc000000 ||
-                           offset >= (s32)0x04000000) {
+                           offset <= (s32)0xfe000000 ||
+                           offset >= (s32)0x02000000) {
                                printk(KERN_ERR
                                       "%s: relocation out of range, section "
                                       "%d reloc %d sym '%s'\n", module->name,
index 070bcb7a63068188dfd7b39ad4be75dd3dede3d7..1b76d87fa335de634f7151c630cec6005ec340ec 100644 (file)
@@ -486,7 +486,7 @@ static void ipi_timer(void)
 }
 
 #ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void do_local_timer(struct pt_regs *regs)
+asmlinkage void __exception do_local_timer(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
        int cpu = smp_processor_id();
@@ -551,7 +551,7 @@ static void ipi_cpu_stop(unsigned int cpu)
  *
  *  Bit 0 - Inter-processor function call
  */
-asmlinkage void do_IPI(struct pt_regs *regs)
+asmlinkage void __exception do_IPI(struct pt_regs *regs)
 {
        unsigned int cpu = smp_processor_id();
        struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
index 6be67296f33326eea42bc44045cbc16e8f02efd1..e4156e7868ce5987ef5311c1b2c309cda121beb8 100644 (file)
@@ -23,11 +23,15 @@ SECTIONS
 #else
        . = PAGE_OFFSET + TEXT_OFFSET;
 #endif
-       .init : {                       /* Init code and data           */
+       .text.head : {
                _stext = .;
-                       _sinittext = .;
+               _sinittext = .;
+               *(.text.head)
+       }
+
+       .init : {                       /* Init code and data           */
                        *(.init.text)
-                       _einittext = .;
+               _einittext = .;
                __proc_info_begin = .;
                        *(.proc.info.init)
                __proc_info_end = .;
@@ -119,7 +123,7 @@ SECTIONS
                 * first, the init task union, aligned
                 * to an 8192 byte boundary.
                 */
-               *(.init.task)
+               *(.data.init_task)
 
 #ifdef CONFIG_XIP_KERNEL
                . = ALIGN(4096);
index e238ad8cfd8fefbe7d78b3692eb1892140223ad8..018d637f87fcba913048a2896193ec98edf38cd3 100644 (file)
@@ -107,7 +107,7 @@ config ARCH_AT91SAM9260_SAM9XE
        depends on ARCH_AT91SAM9260
        help
          Select this if you are using Atmel's AT91SAM9XE System-on-Chip.
-         They are basicaly AT91SAM9260s with various sizes of embedded Flash.
+         They are basically AT91SAM9260s with various sizes of embedded Flash.
 
 comment "AT91SAM9260 / AT91SAM9XE Board Type"
 
index 8781aaeb576b2d2738ead294ba6c21a182030b58..856c681ebbbcf9c3e9e64060bd52a1e690316e51 100644 (file)
@@ -22,6 +22,7 @@ comment "OMAP Board Type"
 config MACH_OMAP_INNOVATOR
        bool "TI Innovator"
        depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+       select OMAP_MCBSP
        help
           TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
           have such a board.
@@ -29,6 +30,7 @@ config MACH_OMAP_INNOVATOR
 config MACH_OMAP_H2
        bool "TI H2 Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       select OMAP_MCBSP
        help
          TI OMAP 1610/1611B H2 board support. Say Y here if you have such
          a board.
@@ -36,6 +38,7 @@ config MACH_OMAP_H2
 config MACH_OMAP_H3
        bool "TI H3 Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
+       select GPIOEXPANDER_OMAP
        help
          TI OMAP 1710 H3 board support. Say Y here if you have such
          a board.
@@ -43,7 +46,7 @@ config MACH_OMAP_H3
 config MACH_OMAP_OSK
        bool "TI OSK Support"
        depends on ARCH_OMAP1 && ARCH_OMAP16XX
-       select TPS65010
+       select OMAP_MCBSP
        help
          TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
@@ -84,7 +87,7 @@ config MACH_OMAP_PALMTE
           Support for the Palm Tungsten E PDA. Currently only the LCD panel
           is supported. To boot the kernel, you'll need a PalmOS compatible
           bootloader; check out http://palmtelinux.sourceforge.net for more
-          informations.
+          information.
           Say Y here if you have such a PDA, say NO otherwise.
 
 config MACH_NOKIA770
index 7165f74f78dac18f4c5c4f7fc08272ee683a8dd1..a8b9a00cea224d79393e71e68d77144b83522a43 100644 (file)
@@ -37,4 +37,3 @@ led-$(CONFIG_MACH_OMAP_INNOVATOR)     += leds-innovator.o
 led-$(CONFIG_MACH_OMAP_PERSEUS2)       += leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_OSK)            += leds-osk.o
 obj-$(CONFIG_LEDS)                     += $(led-y)
-
index 62e42c7a628e55ac1f86616064667ea2e0188534..f65baa95986ea9717632690404dd77c47a1cc1c5 100644 (file)
@@ -246,7 +246,7 @@ static void __init fsample_init_smc91x(void)
        mdelay(50);
 }
 
-void omap_fsample_init_irq(void)
+static void __init omap_fsample_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index 9d2346fb68f41da85c51dd0211a6e826121c0b33..7b260b7c537bb3040968b46e8284d87bf34ca129 100644 (file)
@@ -455,7 +455,7 @@ static void __init h3_init_smc91x(void)
        }
 }
 
-void h3_init_irq(void)
+static void __init h3_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index cb00530ad279392725581ae81b57c07a215eb1e6..7e63a41e37c699838471a97ab52004f28bd1a71d 100644 (file)
@@ -308,7 +308,7 @@ static void __init innovator_init_smc91x(void)
        }
 }
 
-void innovator_init_irq(void)
+static void __init innovator_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index fa4be962df67b454c09afc2ea956f11251904825..1d5c8d5097222ad1289b4edf8664febb66434b61 100644 (file)
@@ -246,7 +246,7 @@ static void __init perseus2_init_smc91x(void)
        mdelay(50);
 }
 
-void omap_perseus2_init_irq(void)
+static void __init omap_perseus2_init_irq(void)
 {
        omap1_init_common_hw();
        omap_init_irq();
index 6dcd10ab4496f765a7681731e85c1a8ee7c36f30..da8a3ac47e136c52dfc122641d866d207f1233b7 100644 (file)
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if    defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
-
-static u64 irda_dmamask = 0xffffffff;
-
-static struct platform_device omap1610ir_device = {
-       .name = "omap1610-ir",
-       .id = -1,
-       .dev = {
-               .dma_mask       = &irda_dmamask,
-       },
-};
-
-static void omap_init_irda(void)
-{
-       /* FIXME define and use a boot tag, members something like:
-        *  u8          uart;           // uart1, or uart3
-        * ... but driver only handles uart3 for now
-        *  s16         fir_sel;        // gpio for SIR vs FIR
-        * ... may prefer a callback for SIR/MIR/FIR mode select;
-        * while h2 uses a GPIO, H3 uses a gpio expander
-        */
-       if (machine_is_omap_h2()
-                       || machine_is_omap_h3())
-               (void) platform_device_register(&omap1610ir_device);
-}
-#else
-static inline void omap_init_irda(void) {}
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
@@ -90,6 +61,45 @@ static void omap_init_rtc(void)
 static inline void omap_init_rtc(void) {}
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#if defined(CONFIG_ARCH_OMAP15XX)
+#  define OMAP1_MBOX_SIZE      0x23
+#  define INT_DSP_MAILBOX1     INT_1510_DSP_MAILBOX1
+#elif defined(CONFIG_ARCH_OMAP16XX)
+#  define OMAP1_MBOX_SIZE      0x2f
+#  define INT_DSP_MAILBOX1     INT_1610_DSP_MAILBOX1
+#endif
+
+#define OMAP1_MBOX_BASE                IO_ADDRESS(OMAP16XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+       {
+               .start          = OMAP1_MBOX_BASE,
+               .end            = OMAP1_MBOX_BASE + OMAP1_MBOX_SIZE,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_DSP_MAILBOX1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mbox_device = {
+       .name           = "mailbox",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mbox_resources),
+       .resource       = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+       platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP1_STI_BASE         IO_ADDRESS(0xfffea000)
@@ -154,7 +164,8 @@ static int __init omap1_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_irda();
+
+       omap_init_mbox();
        omap_init_rtc();
        omap_init_sti();
 
index fab8b0b27cfbca4dd4c0a809dca6637369a0bcbc..81c4e738506c865430c27534755cde6780d01a19 100644 (file)
 #include <asm/io.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
-#include <asm/arch/omapfb.h>
 
 extern int omap1_clk_init(void);
 extern void omap_check_revision(void);
 extern void omap_sram_init(void);
+extern void omapfb_reserve_sdram(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -121,7 +121,7 @@ void __init omap1_map_common_io(void)
 #endif
 
        omap_sram_init();
-       omapfb_reserve_mem();
+       omapfb_reserve_sdram();
 }
 
 /*
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
new file mode 100644 (file)
index 0000000..d3abf56
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Mailbox reservation modules for DSP
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/resource.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_ARM2DSP1               0x00
+#define MAILBOX_ARM2DSP1b              0x04
+#define MAILBOX_DSP2ARM1               0x08
+#define MAILBOX_DSP2ARM1b              0x0c
+#define MAILBOX_DSP2ARM2               0x10
+#define MAILBOX_DSP2ARM2b              0x14
+#define MAILBOX_ARM2DSP1_Flag          0x18
+#define MAILBOX_DSP2ARM1_Flag          0x1c
+#define MAILBOX_DSP2ARM2_Flag          0x20
+
+unsigned long mbox_base;
+
+struct omap_mbox1_fifo {
+       unsigned long cmd;
+       unsigned long data;
+       unsigned long flag;
+};
+
+struct omap_mbox1_priv {
+       struct omap_mbox1_fifo tx_fifo;
+       struct omap_mbox1_fifo rx_fifo;
+};
+
+static inline int mbox_read_reg(unsigned int reg)
+{
+       return __raw_readw(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+       __raw_writew(val, mbox_base + reg);
+}
+
+/* msg */
+static inline mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+       mbox_msg_t msg;
+
+       msg = mbox_read_reg(fifo->data);
+       msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16;
+
+       return msg;
+}
+
+static inline void
+omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo;
+
+       mbox_write_reg(msg & 0xffff, fifo->data);
+       mbox_write_reg(msg >> 16, fifo->cmd);
+}
+
+static inline int omap1_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+       return 0;
+}
+
+static inline int omap1_mbox_fifo_full(struct omap_mbox *mbox)
+{
+       struct omap_mbox1_fifo *fifo =
+               &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+
+       return (mbox_read_reg(fifo->flag));
+}
+
+/* irq */
+static inline void
+omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_RX)
+               enable_irq(mbox->irq);
+}
+
+static inline void
+omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_RX)
+               disable_irq(mbox->irq);
+}
+
+static inline int
+omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+       if (irq == IRQ_TX)
+               return 0;
+       return 1;
+}
+
+static struct omap_mbox_ops omap1_mbox_ops = {
+       .type           = OMAP_MBOX_TYPE1,
+       .fifo_read      = omap1_mbox_fifo_read,
+       .fifo_write     = omap1_mbox_fifo_write,
+       .fifo_empty     = omap1_mbox_fifo_empty,
+       .fifo_full      = omap1_mbox_fifo_full,
+       .enable_irq     = omap1_mbox_enable_irq,
+       .disable_irq    = omap1_mbox_disable_irq,
+       .is_irq         = omap1_mbox_is_irq,
+};
+
+/* FIXME: the following struct should be created automatically by the user id */
+
+/* DSP */
+static struct omap_mbox1_priv omap1_mbox_dsp_priv = {
+       .tx_fifo = {
+               .cmd    = MAILBOX_ARM2DSP1b,
+               .data   = MAILBOX_ARM2DSP1,
+               .flag   = MAILBOX_ARM2DSP1_Flag,
+       },
+       .rx_fifo = {
+               .cmd    = MAILBOX_DSP2ARM1b,
+               .data   = MAILBOX_DSP2ARM1,
+               .flag   = MAILBOX_DSP2ARM1_Flag,
+       },
+};
+
+struct omap_mbox mbox_dsp_info = {
+       .name   = "dsp",
+       .ops    = &omap1_mbox_ops,
+       .priv   = &omap1_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+static int __init omap1_mbox_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret = 0;
+
+       if (pdev->num_resources != 2) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* MBOX base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+       mbox_base = res->start;
+
+       /* DSP IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid irq resource\n");
+               return -ENODEV;
+       }
+       mbox_dsp_info.irq = res->start;
+
+       ret = omap_mbox_register(&mbox_dsp_info);
+
+       return ret;
+}
+
+static int omap1_mbox_remove(struct platform_device *pdev)
+{
+       omap_mbox_unregister(&mbox_dsp_info);
+
+       return 0;
+}
+
+static struct platform_driver omap1_mbox_driver = {
+       .probe  = omap1_mbox_probe,
+       .remove = omap1_mbox_remove,
+       .driver = {
+               .name   = "mailbox",
+       },
+};
+
+static int __init omap1_mbox_init(void)
+{
+       return platform_driver_register(&omap1_mbox_driver);
+}
+
+static void __exit omap1_mbox_exit(void)
+{
+       platform_driver_unregister(&omap1_mbox_driver);
+}
+
+module_init(omap1_mbox_init);
+module_exit(omap1_mbox_exit);
+
+MODULE_LICENSE("GPL");
index aab97ccf1e63648889ddb515abd9c35ff85fd826..7393109f5c3027f4a9973294954d5bfb53d65f34 100644 (file)
@@ -9,6 +9,7 @@ config ARCH_OMAP2420
        bool "OMAP2420 support"
        depends on ARCH_OMAP24XX
        select OMAP_DM_TIMER
+       select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
        depends on ARCH_OMAP2
@@ -20,6 +21,7 @@ config MACH_OMAP_GENERIC
 config MACH_OMAP_H4
        bool "OMAP 2420 H4 board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
+       select OMAP_DEBUG_LEDS if LEDS || LEDS_OMAP_DEBUG
 
 config MACH_OMAP_APOLLON
        bool "OMAP 2420 Apollon board"
index 1e7ed6d22ca98efc6614ff56071d91ac4679af6f..452193f0153182f5407ce36f99fba726cc4ca037 100644 (file)
@@ -266,12 +266,26 @@ static struct platform_device h4_lcd_device = {
        .id             = -1,
 };
 
+static struct resource h4_led_resources[] = {
+       [0] = {
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device h4_led_device = {
+       .name           = "omap_dbg_led",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(h4_led_resources),
+       .resource       = h4_led_resources,
+};
+
 static struct platform_device *h4_devices[] __initdata = {
        &h4_smc91x_device,
        &h4_flash_device,
        &h4_irda_device,
        &h4_kp_device,
        &h4_lcd_device,
+       &h4_led_device,
 };
 
 static inline void __init h4_init_smc91x(void)
index aa4322451e8b5dbe10cfd76cf58fff09b9384abf..52ec2f2d636022300709012b263f623b7dfc2ab5 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/arch/mux.h>
 #include <asm/arch/gpio.h>
 
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define OMAP2_I2C_BASE2                0x48072000
 #define OMAP2_I2C_INT2         57
@@ -42,8 +42,8 @@ static struct resource i2c_resources2[] = {
 };
 
 static struct platform_device omap_i2c_device2 = {
-        .name           = "i2c_omap",
-        .id             = 2,
+       .name           = "i2c_omap",
+       .id             = 2,
        .num_resources  = ARRAY_SIZE(i2c_resources2),
        .resource       = i2c_resources2,
 };
@@ -66,6 +66,40 @@ static void omap_init_i2c(void) {}
 
 #endif
 
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+#define OMAP2_MBOX_BASE                IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+       {
+               .start          = OMAP2_MBOX_BASE,
+               .end            = OMAP2_MBOX_BASE + 0x11f,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_24XX_MAIL_U0_MPU,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = INT_24XX_MAIL_U3_MPU,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mbox_device = {
+       .name           = "mailbox",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(mbox_resources),
+       .resource       = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+       platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
 #if defined(CONFIG_OMAP_STI)
 
 #define OMAP2_STI_BASE         IO_ADDRESS(0x48068000)
@@ -111,29 +145,45 @@ static inline void omap_init_sti(void) {}
 #define OMAP2_MCSPI1_BASE              0x48098000
 #define OMAP2_MCSPI2_BASE              0x4809a000
 
-/* FIXME: use resources instead */
-
 static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
-       .base           = io_p2v(OMAP2_MCSPI1_BASE),
        .num_cs         = 4,
 };
 
+static struct resource omap2_mcspi1_resources[] = {
+       {
+               .start          = OMAP2_MCSPI1_BASE,
+               .end            = OMAP2_MCSPI1_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
 struct platform_device omap2_mcspi1 = {
        .name           = "omap2_mcspi",
        .id             = 1,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi1_resources),
+       .resource       = omap2_mcspi1_resources,
        .dev            = {
                .platform_data = &omap2_mcspi1_config,
        },
 };
 
 static struct omap2_mcspi_platform_config omap2_mcspi2_config = {
-       .base           = io_p2v(OMAP2_MCSPI2_BASE),
        .num_cs         = 2,
 };
 
+static struct resource omap2_mcspi2_resources[] = {
+       {
+               .start          = OMAP2_MCSPI2_BASE,
+               .end            = OMAP2_MCSPI2_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
 struct platform_device omap2_mcspi2 = {
        .name           = "omap2_mcspi",
        .id             = 2,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi2_resources),
+       .resource       = omap2_mcspi2_resources,
        .dev            = {
                .platform_data = &omap2_mcspi2_config,
        },
@@ -157,10 +207,10 @@ static int __init omap2_init_devices(void)
         * in alphabetical order so they're easier to sort through.
         */
        omap_init_i2c();
+       omap_init_mbox();
        omap_init_mcspi();
        omap_init_sti();
 
        return 0;
 }
 arch_initcall(omap2_init_devices);
-
index d8f57824423f63708ca42a5b6a118c5470fb6406..54c836a984565daa81115a2d2ae2ab4a0b8ce3d4 100644 (file)
@@ -246,14 +246,22 @@ static int gpmc_cs_mem_enabled(int cs)
        return l & (1 << 6);
 }
 
-static void gpmc_cs_set_reserved(int cs, int reserved)
+int gpmc_cs_set_reserved(int cs, int reserved)
 {
+       if (cs > GPMC_CS_NUM)
+               return -ENODEV;
+
        gpmc_cs_map &= ~(1 << cs);
        gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+
+       return 0;
 }
 
-static int gpmc_cs_reserved(int cs)
+int gpmc_cs_reserved(int cs)
 {
+       if (cs > GPMC_CS_NUM)
+               return -ENODEV;
+
        return gpmc_cs_map & (1 << cs);
 }
 
index a0728c33e5d9e60de43b6f867b1efcfd61c1561f..82dc70f6b7795652829a01fa5a1c360ca1fc9cae 100644 (file)
@@ -27,6 +27,7 @@ extern void omap_sram_init(void);
 extern int omap2_clk_init(void);
 extern void omap2_check_revision(void);
 extern void gpmc_init(void);
+extern void omapfb_reserve_sdram(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -40,9 +41,21 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .type           = MT_DEVICE
        },
        {
-               .virtual        = L4_24XX_VIRT,
-               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
-               .length         = L4_24XX_SIZE,
+               .virtual        = DSP_MEM_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+               .length         = DSP_MEM_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_IPI_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+               .length         = DSP_IPI_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_MMU_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+               .length         = DSP_MMU_24XX_SIZE,
                .type           = MT_DEVICE
        }
 };
@@ -60,7 +73,7 @@ void __init omap2_map_common_io(void)
 
        omap2_check_revision();
        omap_sram_init();
-       omapfb_reserve_mem();
+       omapfb_reserve_sdram();
 }
 
 void __init omap2_init_common_hw(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
new file mode 100644 (file)
index 0000000..b03cd06
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Mailbox reservation modules for OMAP2
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *        and  Paul Mundt <paul.mundt@nokia.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_REVISION               0x00
+#define MAILBOX_SYSCONFIG              0x10
+#define MAILBOX_SYSSTATUS              0x14
+#define MAILBOX_MESSAGE_0              0x40
+#define MAILBOX_MESSAGE_1              0x44
+#define MAILBOX_MESSAGE_2              0x48
+#define MAILBOX_MESSAGE_3              0x4c
+#define MAILBOX_MESSAGE_4              0x50
+#define MAILBOX_MESSAGE_5              0x54
+#define MAILBOX_FIFOSTATUS_0           0x80
+#define MAILBOX_FIFOSTATUS_1           0x84
+#define MAILBOX_FIFOSTATUS_2           0x88
+#define MAILBOX_FIFOSTATUS_3           0x8c
+#define MAILBOX_FIFOSTATUS_4           0x90
+#define MAILBOX_FIFOSTATUS_5           0x94
+#define MAILBOX_MSGSTATUS_0            0xc0
+#define MAILBOX_MSGSTATUS_1            0xc4
+#define MAILBOX_MSGSTATUS_2            0xc8
+#define MAILBOX_MSGSTATUS_3            0xcc
+#define MAILBOX_MSGSTATUS_4            0xd0
+#define MAILBOX_MSGSTATUS_5            0xd4
+#define MAILBOX_IRQSTATUS_0            0x100
+#define MAILBOX_IRQENABLE_0            0x104
+#define MAILBOX_IRQSTATUS_1            0x108
+#define MAILBOX_IRQENABLE_1            0x10c
+#define MAILBOX_IRQSTATUS_2            0x110
+#define MAILBOX_IRQENABLE_2            0x114
+#define MAILBOX_IRQSTATUS_3            0x118
+#define MAILBOX_IRQENABLE_3            0x11c
+
+static unsigned long mbox_base;
+
+#define MAILBOX_IRQ_NOTFULL(n)         (1 << (2 * (n) + 1))
+#define MAILBOX_IRQ_NEWMSG(n)          (1 << (2 * (n)))
+
+struct omap_mbox2_fifo {
+       unsigned long msg;
+       unsigned long fifo_stat;
+       unsigned long msg_stat;
+};
+
+struct omap_mbox2_priv {
+       struct omap_mbox2_fifo tx_fifo;
+       struct omap_mbox2_fifo rx_fifo;
+       unsigned long irqenable;
+       unsigned long irqstatus;
+       u32 newmsg_bit;
+       u32 notfull_bit;
+};
+
+static struct clk *mbox_ick_handle;
+
+static inline unsigned int mbox_read_reg(unsigned int reg)
+{
+       return __raw_readl(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+       __raw_writel(val, mbox_base + reg);
+}
+
+/* Mailbox H/W preparations */
+static inline int omap2_mbox_startup(struct omap_mbox *mbox)
+{
+       unsigned int l;
+
+       mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
+       if (IS_ERR(mbox_ick_handle)) {
+               printk("Could not get mailboxes_ick\n");
+               return -ENODEV;
+       }
+       clk_enable(mbox_ick_handle);
+
+       /* set smart-idle & autoidle */
+       l = mbox_read_reg(MAILBOX_SYSCONFIG);
+       l |= 0x00000011;
+       mbox_write_reg(l, MAILBOX_SYSCONFIG);
+
+       return 0;
+}
+
+static inline void omap2_mbox_shutdown(struct omap_mbox *mbox)
+{
+       clk_disable(mbox_ick_handle);
+       clk_put(mbox_ick_handle);
+}
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo =
+               &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+       return (mbox_msg_t) mbox_read_reg(fifo->msg);
+}
+
+static inline void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       struct omap_mbox2_fifo *fifo =
+               &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+       mbox_write_reg(msg, fifo->msg);
+}
+
+static inline int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo =
+               &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+       return (mbox_read_reg(fifo->msg_stat) == 0);
+}
+
+static inline int omap2_mbox_fifo_full(struct omap_mbox *mbox)
+{
+       struct omap_mbox2_fifo *fifo =
+               &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+       return (mbox_read_reg(fifo->fifo_stat));
+}
+
+/* Mailbox IRQ handle functions */
+static inline void omap2_mbox_enable_irq(struct omap_mbox *mbox,
+               omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       l = mbox_read_reg(p->irqenable);
+       l |= bit;
+       mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_disable_irq(struct omap_mbox *mbox,
+               omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       l = mbox_read_reg(p->irqenable);
+       l &= ~bit;
+       mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_ack_irq(struct omap_mbox *mbox,
+               omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       mbox_write_reg(bit, p->irqstatus);
+}
+
+static inline int omap2_mbox_is_irq(struct omap_mbox *mbox,
+               omap_mbox_type_t irq)
+{
+       struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+       u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+       u32 enable = mbox_read_reg(p->irqenable);
+       u32 status = mbox_read_reg(p->irqstatus);
+
+       return (enable & status & bit);
+}
+
+static struct omap_mbox_ops omap2_mbox_ops = {
+       .type           = OMAP_MBOX_TYPE2,
+       .startup        = omap2_mbox_startup,
+       .shutdown       = omap2_mbox_shutdown,
+       .fifo_read      = omap2_mbox_fifo_read,
+       .fifo_write     = omap2_mbox_fifo_write,
+       .fifo_empty     = omap2_mbox_fifo_empty,
+       .fifo_full      = omap2_mbox_fifo_full,
+       .enable_irq     = omap2_mbox_enable_irq,
+       .disable_irq    = omap2_mbox_disable_irq,
+       .ack_irq        = omap2_mbox_ack_irq,
+       .is_irq         = omap2_mbox_is_irq,
+};
+
+/*
+ * MAILBOX 0: ARM -> DSP,
+ * MAILBOX 1: ARM <- DSP.
+ * MAILBOX 2: ARM -> IVA,
+ * MAILBOX 3: ARM <- IVA.
+ */
+
+/* FIXME: the following structs should be filled automatically by the user id */
+
+/* DSP */
+static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
+       .tx_fifo = {
+               .msg            = MAILBOX_MESSAGE_0,
+               .fifo_stat      = MAILBOX_FIFOSTATUS_0,
+       },
+       .rx_fifo = {
+               .msg            = MAILBOX_MESSAGE_1,
+               .msg_stat       = MAILBOX_MSGSTATUS_1,
+       },
+       .irqenable      = MAILBOX_IRQENABLE_0,
+       .irqstatus      = MAILBOX_IRQSTATUS_0,
+       .notfull_bit    = MAILBOX_IRQ_NOTFULL(0),
+       .newmsg_bit     = MAILBOX_IRQ_NEWMSG(1),
+};
+
+struct omap_mbox mbox_dsp_info = {
+       .name   = "dsp",
+       .ops    = &omap2_mbox_ops,
+       .priv   = &omap2_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+/* IVA */
+static struct omap_mbox2_priv omap2_mbox_iva_priv = {
+       .tx_fifo = {
+               .msg            = MAILBOX_MESSAGE_2,
+               .fifo_stat      = MAILBOX_FIFOSTATUS_2,
+       },
+       .rx_fifo = {
+               .msg            = MAILBOX_MESSAGE_3,
+               .msg_stat       = MAILBOX_MSGSTATUS_3,
+       },
+       .irqenable      = MAILBOX_IRQENABLE_3,
+       .irqstatus      = MAILBOX_IRQSTATUS_3,
+       .notfull_bit    = MAILBOX_IRQ_NOTFULL(2),
+       .newmsg_bit     = MAILBOX_IRQ_NEWMSG(3),
+};
+
+static struct omap_mbox mbox_iva_info = {
+       .name   = "iva",
+       .ops    = &omap2_mbox_ops,
+       .priv   = &omap2_mbox_iva_priv,
+};
+
+static int __init omap2_mbox_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret = 0;
+
+       if (pdev->num_resources != 3) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* MBOX base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+       mbox_base = res->start;
+
+       /* DSP IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid irq resource\n");
+               return -ENODEV;
+       }
+       mbox_dsp_info.irq = res->start;
+
+       ret = omap_mbox_register(&mbox_dsp_info);
+
+       /* IVA IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid irq resource\n");
+               return -ENODEV;
+       }
+       mbox_iva_info.irq = res->start;
+
+       ret = omap_mbox_register(&mbox_iva_info);
+
+       return ret;
+}
+
+static int omap2_mbox_remove(struct platform_device *pdev)
+{
+       omap_mbox_unregister(&mbox_dsp_info);
+       return 0;
+}
+
+static struct platform_driver omap2_mbox_driver = {
+       .probe = omap2_mbox_probe,
+       .remove = omap2_mbox_remove,
+       .driver = {
+               .name = "mailbox",
+       },
+};
+
+static int __init omap2_mbox_init(void)
+{
+       return platform_driver_register(&omap2_mbox_driver);
+}
+
+static void __exit omap2_mbox_exit(void)
+{
+       platform_driver_unregister(&omap2_mbox_driver);
+}
+
+module_init(omap2_mbox_init);
+module_exit(omap2_mbox_exit);
+
+MODULE_LICENSE("GPL");
index 637aaba653901a23f640edfdfa7c2569c0a41c93..d1eeed2ad47c79f5ed1d94209233957001690f5f 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
+/* linux/arch/arm/mach-s3c2410/sleep.S
  *
  * Copyright (c) 2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
index e684e9b38216dce35440d32025208f2041a41454..b81391a4e374a3ddc013bd677364ef40501d1aea 100644 (file)
@@ -366,6 +366,19 @@ config CPU_32v6K
          enabled will not boot on processors with do not support these
          instructions.
 
+# ARMv7
+config CPU_V7
+       bool "Support ARM V7 processor"
+       depends on ARCH_INTEGRATOR
+       select CPU_32v6K
+       select CPU_32v7
+       select CPU_ABRT_EV7
+       select CPU_CACHE_V7
+       select CPU_CACHE_VIPT
+       select CPU_CP15_MMU
+       select CPU_COPY_V6 if MMU
+       select CPU_TLB_V6 if MMU
+
 # Figure out what processor architecture version we should be using.
 # This defines the compiler instruction set which depends on the machine type.
 config CPU_32v3
@@ -391,6 +404,9 @@ config CPU_32v5
 config CPU_32v6
        bool
 
+config CPU_32v7
+       bool
+
 # The abort model
 config CPU_ABRT_NOMMU
        bool
@@ -413,6 +429,9 @@ config CPU_ABRT_EV5TJ
 config CPU_ABRT_EV6
        bool
 
+config CPU_ABRT_EV7
+       bool
+
 # The cache model
 config CPU_CACHE_V3
        bool
@@ -429,6 +448,9 @@ config CPU_CACHE_V4WB
 config CPU_CACHE_V6
        bool
 
+config CPU_CACHE_V7
+       bool
+
 config CPU_CACHE_VIVT
        bool
 
@@ -503,7 +525,7 @@ comment "Processor Features"
 
 config ARM_THUMB
        bool "Support Thumb user binaries"
-       depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6
+       depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7
        default y
        help
          Say Y if you want to include kernel support for running user space
@@ -578,9 +600,15 @@ config CPU_CACHE_ROUND_ROBIN
          Say Y here to use the predictable round-robin cache replacement
          policy.  Unless you specifically require this or are unsure, say N.
 
+config CPU_L2CACHE_DISABLE
+       bool "Disable level 2 cache"
+       depends on CPU_V7
+       help
+         Say Y here to disable the level 2 cache.  If unsure, say N.
+
 config CPU_BPREDICT_DISABLE
        bool "Disable branch prediction"
-       depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3
+       depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
        help
          Say Y here to disable branch prediction.  If unsure, say N.
 
index 2f8b95947774dc8d263ce753ba7cb64e2299d241..b5bd335ff14aad48f44331c0c17e5462f38d433d 100644 (file)
@@ -24,12 +24,14 @@ obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
 obj-$(CONFIG_CPU_ABRT_EV5T)    += abort-ev5t.o
 obj-$(CONFIG_CPU_ABRT_EV5TJ)   += abort-ev5tj.o
 obj-$(CONFIG_CPU_ABRT_EV6)     += abort-ev6.o
+obj-$(CONFIG_CPU_ABRT_EV7)     += abort-ev7.o
 
 obj-$(CONFIG_CPU_CACHE_V3)     += cache-v3.o
 obj-$(CONFIG_CPU_CACHE_V4)     += cache-v4.o
 obj-$(CONFIG_CPU_CACHE_V4WT)   += cache-v4wt.o
 obj-$(CONFIG_CPU_CACHE_V4WB)   += cache-v4wb.o
 obj-$(CONFIG_CPU_CACHE_V6)     += cache-v6.o
+obj-$(CONFIG_CPU_CACHE_V7)     += cache-v7.o
 
 obj-$(CONFIG_CPU_COPY_V3)      += copypage-v3.o
 obj-$(CONFIG_CPU_COPY_V4WT)    += copypage-v4wt.o
@@ -66,5 +68,6 @@ obj-$(CONFIG_CPU_SA1100)      += proc-sa1100.o
 obj-$(CONFIG_CPU_XSCALE)       += proc-xscale.o
 obj-$(CONFIG_CPU_XSC3)         += proc-xsc3.o
 obj-$(CONFIG_CPU_V6)           += proc-v6.o
+obj-$(CONFIG_CPU_V7)           += proc-v7.o
 
 obj-$(CONFIG_CACHE_L2X0)       += cache-l2x0.o
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S
new file mode 100644 (file)
index 0000000..eb90bce
--- /dev/null
@@ -0,0 +1,32 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v7_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *        : r1 = FSR, bit 11 = write
+ *        : r2-r8 = corrupted
+ *        : r9 = preserved
+ *        : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ */
+       .align  5
+ENTRY(v7_early_abort)
+       /*
+        * The effect of data aborts on on the exclusive access monitor are
+        * UNPREDICTABLE. Do a CLREX to clear the state
+        */
+       clrex
+
+       mrc     p15, 0, r1, c5, c0, 0           @ get FSR
+       mrc     p15, 0, r0, c6, c0, 0           @ get FAR
+
+       /*
+        * V6 code adjusts the returned DFSR.
+        * New designs should not need to patch up faults.
+        */
+       mov     pc, lr
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
new file mode 100644 (file)
index 0000000..35ffc4d
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *  linux/arch/arm/mm/cache-v7.S
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *  Copyright (C) 2005 ARM Ltd.
+ *
+ * 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.
+ *
+ *  This is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+#include "proc-macros.S"
+
+/*
+ *     v7_flush_dcache_all()
+ *
+ *     Flush the whole D-cache.
+ *
+ *     Corrupted registers: r0-r5, r7, r9-r11
+ *
+ *     - mm    - mm_struct describing address space
+ */
+ENTRY(v7_flush_dcache_all)
+       mrc     p15, 1, r0, c0, c0, 1           @ read clidr
+       ands    r3, r0, #0x7000000              @ extract loc from clidr
+       mov     r3, r3, lsr #23                 @ left align loc bit field
+       beq     finished                        @ if loc is 0, then no need to clean
+       mov     r10, #0                         @ start clean at cache level 0
+loop1:
+       add     r2, r10, r10, lsr #1            @ work out 3x current cache level
+       mov     r1, r0, lsr r2                  @ extract cache type bits from clidr
+       and     r1, r1, #7                      @ mask of the bits for current cache only
+       cmp     r1, #2                          @ see what cache we have at this level
+       blt     skip                            @ skip if no cache, or just i-cache
+       mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
+       isb                                     @ isb to sych the new cssr&csidr
+       mrc     p15, 1, r1, c0, c0, 0           @ read the new csidr
+       and     r2, r1, #7                      @ extract the length of the cache lines
+       add     r2, r2, #4                      @ add 4 (line length offset)
+       ldr     r4, =0x3ff
+       ands    r4, r4, r1, lsr #3              @ find maximum number on the way size
+       clz     r5, r4                          @ find bit position of way size increment
+       ldr     r7, =0x7fff
+       ands    r7, r7, r1, lsr #13             @ extract max number of the index size
+loop2:
+       mov     r9, r4                          @ create working copy of max way size
+loop3:
+       orr     r11, r10, r9, lsl r5            @ factor way and cache number into r11
+       orr     r11, r11, r7, lsl r2            @ factor index number into r11
+       mcr     p15, 0, r11, c7, c14, 2         @ clean & invalidate by set/way
+       subs    r9, r9, #1                      @ decrement the way
+       bge     loop3
+       subs    r7, r7, #1                      @ decrement the index
+       bge     loop2
+skip:
+       add     r10, r10, #2                    @ increment cache number
+       cmp     r3, r10
+       bgt     loop1
+finished:
+       mov     r10, #0                         @ swith back to cache level 0
+       mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
+       isb
+       mov     pc, lr
+
+/*
+ *     v7_flush_cache_all()
+ *
+ *     Flush the entire cache system.
+ *  The data cache flush is now achieved using atomic clean / invalidates
+ *  working outwards from L1 cache. This is done using Set/Way based cache
+ *  maintainance instructions.
+ *  The instruction cache can still be invalidated back to the point of
+ *  unification in a single instruction.
+ *
+ */
+ENTRY(v7_flush_kern_cache_all)
+       stmfd   sp!, {r4-r5, r7, r9-r11, lr}
+       bl      v7_flush_dcache_all
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
+       ldmfd   sp!, {r4-r5, r7, r9-r11, lr}
+       mov     pc, lr
+
+/*
+ *     v7_flush_cache_all()
+ *
+ *     Flush all TLB entries in a particular address space
+ *
+ *     - mm    - mm_struct describing address space
+ */
+ENTRY(v7_flush_user_cache_all)
+       /*FALLTHROUGH*/
+
+/*
+ *     v7_flush_cache_range(start, end, flags)
+ *
+ *     Flush a range of TLB entries in the specified address space.
+ *
+ *     - start - start address (may not be aligned)
+ *     - end   - end address (exclusive, may not be aligned)
+ *     - flags - vm_area_struct flags describing address space
+ *
+ *     It is assumed that:
+ *     - we have a VIPT cache.
+ */
+ENTRY(v7_flush_user_cache_range)
+       mov     pc, lr
+
+/*
+ *     v7_coherent_kern_range(start,end)
+ *
+ *     Ensure that the I and D caches are coherent within specified
+ *     region.  This is typically used when code has been written to
+ *     a memory region, and will be executed.
+ *
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ *
+ *     It is assumed that:
+ *     - the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_kern_range)
+       /* FALLTHROUGH */
+
+/*
+ *     v7_coherent_user_range(start,end)
+ *
+ *     Ensure that the I and D caches are coherent within specified
+ *     region.  This is typically used when code has been written to
+ *     a memory region, and will be executed.
+ *
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ *
+ *     It is assumed that:
+ *     - the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_user_range)
+       dcache_line_size r2, r3
+       sub     r3, r2, #1
+       bic     r0, r0, r3
+1:     mcr     p15, 0, r0, c7, c11, 1          @ clean D line to the point of unification
+       dsb
+       mcr     p15, 0, r0, c7, c5, 1           @ invalidate I line
+       add     r0, r0, r2
+       cmp     r0, r1
+       blo     1b
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
+       dsb
+       isb
+       mov     pc, lr
+
+/*
+ *     v7_flush_kern_dcache_page(kaddr)
+ *
+ *     Ensure that the data held in the page kaddr is written back
+ *     to the page in question.
+ *
+ *     - kaddr   - kernel address (guaranteed to be page aligned)
+ */
+ENTRY(v7_flush_kern_dcache_page)
+       dcache_line_size r2, r3
+       add     r1, r0, #PAGE_SZ
+1:
+       mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
+       add     r0, r0, r2
+       cmp     r0, r1
+       blo     1b
+       dsb
+       mov     pc, lr
+
+/*
+ *     v7_dma_inv_range(start,end)
+ *
+ *     Invalidate the data cache within the specified region; we will
+ *     be performing a DMA operation in this region and we want to
+ *     purge old data in the cache.
+ *
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+ENTRY(v7_dma_inv_range)
+       dcache_line_size r2, r3
+       sub     r3, r2, #1
+       tst     r0, r3
+       bic     r0, r0, r3
+       mcrne   p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
+
+       tst     r1, r3
+       bic     r1, r1, r3
+       mcrne   p15, 0, r1, c7, c14, 1          @ clean & invalidate D / U line
+1:
+       mcr     p15, 0, r0, c7, c6, 1           @ invalidate D / U line
+       add     r0, r0, r2
+       cmp     r0, r1
+       blo     1b
+       dsb
+       mov     pc, lr
+
+/*
+ *     v7_dma_clean_range(start,end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+ENTRY(v7_dma_clean_range)
+       dcache_line_size r2, r3
+       sub     r3, r2, #1
+       bic     r0, r0, r3
+1:
+       mcr     p15, 0, r0, c7, c10, 1          @ clean D / U line
+       add     r0, r0, r2
+       cmp     r0, r1
+       blo     1b
+       dsb
+       mov     pc, lr
+
+/*
+ *     v7_dma_flush_range(start,end)
+ *     - start   - virtual start address of region
+ *     - end     - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range)
+       dcache_line_size r2, r3
+       sub     r3, r2, #1
+       bic     r0, r0, r3
+1:
+       mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
+       add     r0, r0, r2
+       cmp     r0, r1
+       blo     1b
+       dsb
+       mov     pc, lr
+
+       __INITDATA
+
+       .type   v7_cache_fns, #object
+ENTRY(v7_cache_fns)
+       .long   v7_flush_kern_cache_all
+       .long   v7_flush_user_cache_all
+       .long   v7_flush_user_cache_range
+       .long   v7_coherent_kern_range
+       .long   v7_coherent_user_range
+       .long   v7_flush_kern_dcache_page
+       .long   v7_dma_inv_range
+       .long   v7_dma_clean_range
+       .long   v7_dma_flush_range
+       .size   v7_cache_fns, . - v7_cache_fns
index 9da43a0fdcdffc5ff09b4e8fd1bdf6d95ac0452b..fc84fcc743804d16241a99ee5cb1c86f650dd048 100644 (file)
@@ -14,7 +14,8 @@
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
-unsigned int cpu_last_asid = { 1 << ASID_BITS };
+static DEFINE_SPINLOCK(cpu_asid_lock);
+unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 
 /*
  * We fork()ed a process, and we need a new context for the child
@@ -31,15 +32,16 @@ void __new_context(struct mm_struct *mm)
 {
        unsigned int asid;
 
+       spin_lock(&cpu_asid_lock);
        asid = ++cpu_last_asid;
        if (asid == 0)
-               asid = cpu_last_asid = 1 << ASID_BITS;
+               asid = cpu_last_asid = ASID_FIRST_VERSION;
 
        /*
         * If we've used up all our ASIDs, we need
         * to start a new version and flush the TLB.
         */
-       if ((asid & ~ASID_MASK) == 0) {
+       if (unlikely((asid & ~ASID_MASK) == 0)) {
                asid = ++cpu_last_asid;
                /* set the reserved ASID before flushing the TLB */
                asm("mcr        p15, 0, %0, c13, c0, 1  @ set reserved context ID\n"
@@ -47,7 +49,16 @@ void __new_context(struct mm_struct *mm)
                    : "r" (0));
                isb();
                flush_tlb_all();
+               if (icache_is_vivt_asid_tagged()) {
+                       asm("mcr        p15, 0, %0, c7, c5, 0   @ invalidate I-cache\n"
+                           "mcr        p15, 0, %0, c7, c5, 6   @ flush BTAC/BTB\n"
+                           :
+                           : "r" (0));
+                       dsb();
+               }
        }
+       spin_unlock(&cpu_asid_lock);
 
+       mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
        mm->context.id = asid;
 }
index 9e2c89eb2115bd644fc09d854d48ac7637fc3cad..b13150052a76bd6c5d6cc16b17a48d05978c16f8 100644 (file)
        .word   \ucset
 #endif
        .endm
+
+/*
+ * cache_line_size - get the cache line size from the CSIDR register
+ * (available on ARMv7+). It assumes that the CSSR register was configured
+ * to access the L1 data cache CSIDR.
+ */
+       .macro  dcache_line_size, reg, tmp
+       mrc     p15, 1, \tmp, c0, c0, 0         @ read CSIDR
+       and     \tmp, \tmp, #7                  @ cache line size encoding
+       mov     \reg, #16                       @ size offset
+       mov     \reg, \reg, lsl \tmp            @ actual cache line size
+       .endm
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
new file mode 100644 (file)
index 0000000..dd823dd
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ *  linux/arch/arm/mm/proc-v7.S
+ *
+ *  Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * 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.
+ *
+ *  This is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/elf.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+
+#include "proc-macros.S"
+
+#define TTB_C          (1 << 0)
+#define TTB_S          (1 << 1)
+#define TTB_RGN_OC_WT  (2 << 3)
+#define TTB_RGN_OC_WB  (3 << 3)
+
+ENTRY(cpu_v7_proc_init)
+       mov     pc, lr
+
+ENTRY(cpu_v7_proc_fin)
+       mov     pc, lr
+
+/*
+ *     cpu_v7_reset(loc)
+ *
+ *     Perform a soft reset of the system.  Put the CPU into the
+ *     same state as it would be if it had been reset, and branch
+ *     to what would be the reset vector.
+ *
+ *     - loc   - location to jump to for soft reset
+ *
+ *     It is assumed that:
+ */
+       .align  5
+ENTRY(cpu_v7_reset)
+       mov     pc, r0
+
+/*
+ *     cpu_v7_do_idle()
+ *
+ *     Idle the processor (eg, wait for interrupt).
+ *
+ *     IRQs are already disabled.
+ */
+ENTRY(cpu_v7_do_idle)
+       .long   0xe320f003                      @ ARM V7 WFI instruction
+       mov     pc, lr
+
+ENTRY(cpu_v7_dcache_clean_area)
+#ifndef TLB_CAN_READ_FROM_L1_CACHE
+       dcache_line_size r2, r3
+1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       add     r0, r0, r2
+       subs    r1, r1, r2
+       bhi     1b
+       dsb
+#endif
+       mov     pc, lr
+
+/*
+ *     cpu_v7_switch_mm(pgd_phys, tsk)
+ *
+ *     Set the translation table base pointer to be pgd_phys
+ *
+ *     - pgd_phys - physical address of new TTB
+ *
+ *     It is assumed that:
+ *     - we are not using split page tables
+ */
+ENTRY(cpu_v7_switch_mm)
+       mov     r2, #0
+       ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
+       orr     r0, r0, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
+       mcr     p15, 0, r2, c13, c0, 1          @ set reserved context ID
+       isb
+1:     mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+       isb
+       mcr     p15, 0, r1, c13, c0, 1          @ set context ID
+       isb
+       mov     pc, lr
+
+/*
+ *     cpu_v7_set_pte_ext(ptep, pte)
+ *
+ *     Set a level 2 translation table entry.
+ *
+ *     - ptep  - pointer to level 2 translation table entry
+ *               (hardware version is stored at -1024 bytes)
+ *     - pte   - PTE value to store
+ *     - ext   - value for extended PTE bits
+ *
+ *     Permissions:
+ *       YUWD  APX AP1 AP0     SVC     User
+ *       0xxx   0   0   0      no acc  no acc
+ *       100x   1   0   1      r/o     no acc
+ *       10x0   1   0   1      r/o     no acc
+ *       1011   0   0   1      r/w     no acc
+ *       110x   0   1   0      r/w     r/o
+ *       11x0   0   1   0      r/w     r/o
+ *       1111   0   1   1      r/w     r/w
+ */
+ENTRY(cpu_v7_set_pte_ext)
+       str     r1, [r0], #-2048                @ linux version
+
+       bic     r3, r1, #0x000003f0
+       bic     r3, r3, #0x00000003
+       orr     r3, r3, r2
+       orr     r3, r3, #PTE_EXT_AP0 | 2
+
+       tst     r1, #L_PTE_WRITE
+       tstne   r1, #L_PTE_DIRTY
+       orreq   r3, r3, #PTE_EXT_APX
+
+       tst     r1, #L_PTE_USER
+       orrne   r3, r3, #PTE_EXT_AP1
+       tstne   r3, #PTE_EXT_APX
+       bicne   r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
+
+       tst     r1, #L_PTE_YOUNG
+       biceq   r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
+
+       tst     r1, #L_PTE_EXEC
+       orreq   r3, r3, #PTE_EXT_XN
+
+       tst     r1, #L_PTE_PRESENT
+       moveq   r3, #0
+
+       str     r3, [r0]
+       mcr     p15, 0, r0, c7, c10, 1          @ flush_pte
+       mov     pc, lr
+
+cpu_v7_name:
+       .ascii  "ARMv7 Processor"
+       .align
+
+       .section ".text.init", #alloc, #execinstr
+
+/*
+ *     __v7_setup
+ *
+ *     Initialise TLB, Caches, and MMU state ready to switch the MMU
+ *     on.  Return in r0 the new CP15 C1 control register setting.
+ *
+ *     We automatically detect if we have a Harvard cache, and use the
+ *     Harvard cache control instructions insead of the unified cache
+ *     control instructions.
+ *
+ *     This should be able to cover all ARMv7 cores.
+ *
+ *     It is assumed that:
+ *     - cache type register is implemented
+ */
+__v7_setup:
+       adr     r12, __v7_setup_stack           @ the local stack
+       stmia   r12, {r0-r5, r7, r9, r11, lr}
+       bl      v7_flush_dcache_all
+       ldmia   r12, {r0-r5, r7, r9, r11, lr}
+       mov     r10, #0
+#ifdef HARVARD_CACHE
+       mcr     p15, 0, r10, c7, c5, 0          @ I+BTB cache invalidate
+#endif
+       dsb
+       mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
+       mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
+       orr     r4, r4, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
+       mcr     p15, 0, r4, c2, c0, 0           @ load TTB0
+       mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+       mov     r10, #0x1f                      @ domains 0, 1 = manager
+       mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
+#ifndef CONFIG_CPU_L2CACHE_DISABLE
+       @ L2 cache configuration in the L2 aux control register
+       mrc     p15, 1, r10, c9, c0, 2
+       bic     r10, r10, #(1 << 16)            @ L2 outer cache
+       mcr     p15, 1, r10, c9, c0, 2
+       @ L2 cache is enabled in the aux control register
+       mrc     p15, 0, r10, c1, c0, 1
+       orr     r10, r10, #2
+       mcr     p15, 0, r10, c1, c0, 1
+#endif
+       mrc     p15, 0, r0, c1, c0, 0           @ read control register
+       ldr     r10, cr1_clear                  @ get mask for bits to clear
+       bic     r0, r0, r10                     @ clear bits them
+       ldr     r10, cr1_set                    @ get mask for bits to set
+       orr     r0, r0, r10                     @ set them
+       mov     pc, lr                          @ return to head.S:__ret
+
+       /*
+        *         V X F   I D LR
+        * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
+        * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
+        *         0 110       0011 1.00 .111 1101 < we want
+        */
+       .type   cr1_clear, #object
+       .type   cr1_set, #object
+cr1_clear:
+       .word   0x0120c302
+cr1_set:
+       .word   0x00c0387d
+
+__v7_setup_stack:
+       .space  4 * 11                          @ 11 registers
+
+       .type   v7_processor_functions, #object
+ENTRY(v7_processor_functions)
+       .word   v7_early_abort
+       .word   cpu_v7_proc_init
+       .word   cpu_v7_proc_fin
+       .word   cpu_v7_reset
+       .word   cpu_v7_do_idle
+       .word   cpu_v7_dcache_clean_area
+       .word   cpu_v7_switch_mm
+       .word   cpu_v7_set_pte_ext
+       .size   v7_processor_functions, . - v7_processor_functions
+
+       .type   cpu_arch_name, #object
+cpu_arch_name:
+       .asciz  "armv7"
+       .size   cpu_arch_name, . - cpu_arch_name
+
+       .type   cpu_elf_name, #object
+cpu_elf_name:
+       .asciz  "v7"
+       .size   cpu_elf_name, . - cpu_elf_name
+       .align
+
+       .section ".proc.info.init", #alloc, #execinstr
+
+       /*
+        * Match any ARMv7 processor core.
+        */
+       .type   __v7_proc_info, #object
+__v7_proc_info:
+       .long   0x000f0000              @ Required ID value
+       .long   0x000f0000              @ Mask for ID
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_BUFFERABLE | \
+               PMD_SECT_CACHEABLE | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_XN | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       b       __v7_setup
+       .long   cpu_arch_name
+       .long   cpu_elf_name
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+       .long   cpu_v7_name
+       .long   v7_processor_functions
+       .long   v6wbi_tlb_fns
+       .long   v6_user_fns
+       .long   v7_cache_fns
+       .size   __v7_proc_info, . - __v7_proc_info
index 9e8d21eca4ecbf676d23d0b4d600682c969d41f2..cfc69f3842fda4eb97cb3a1edcfddfc154b9bbee 100644 (file)
@@ -20,6 +20,11 @@ endchoice
 
 comment "OMAP Feature Selections"
 
+config OMAP_DEBUG_LEDS
+       bool
+       help
+         For debug card leds on TI reference boards.
+
 config OMAP_RESET_CLOCKS
        bool "Reset unused clocks during boot"
        depends on ARCH_OMAP
@@ -58,6 +63,14 @@ config OMAP_MUX_WARNINGS
          to change the pin multiplexing setup.  When there are no warnings
          printed, it's safe to deselect OMAP_MUX for your product.
 
+config OMAP_MCBSP
+       bool "McBSP support"
+       depends on ARCH_OMAP
+       default y
+       help
+         Say Y here if you want support for the OMAP Multichannel
+         Buffered Serial Port.
+
 choice
         prompt "System timer"
        default OMAP_MPU_TIMER
index 2896b4546411c3237bc7374435958276916f4a36..41a3c1cf3bd44bd23b66836dbc79b0fd39abfb0f 100644 (file)
@@ -3,7 +3,8 @@
 #
 
 # Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o \
+        usb.o fb.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -16,4 +17,4 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
-
+obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
index f1179ad4be1bb0f63e3d95059c8e3188b5bcc1e4..0a603242f36712e1060542f6c14c97efd3100a76 100644 (file)
@@ -33,6 +33,41 @@ static DEFINE_SPINLOCK(clockfw_lock);
 
 static struct clk_functions *arch_clock;
 
+#ifdef CONFIG_PM_DEBUG
+
+static void print_parents(struct clk *clk)
+{
+       struct clk *p;
+       int printed = 0;
+
+       list_for_each_entry(p, &clocks, node) {
+               if (p->parent == clk && p->usecount) {
+                       if (!clk->usecount && !printed) {
+                               printk("MISMATCH: %s\n", clk->name);
+                               printed = 1;
+                       }
+                       printk("\t%-15s\n", p->name);
+               }
+       }
+}
+
+void clk_print_usecounts(void)
+{
+       unsigned long flags;
+       struct clk *p;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       list_for_each_entry(p, &clocks, node) {
+               if (p->usecount)
+                       printk("%-15s: %d\n", p->name, p->usecount);
+               print_parents(p);
+
+       }
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+
+#endif
+
 /*-------------------------------------------------------------------------
  * Standard clock functions defined in include/linux/clk.h
  *-------------------------------------------------------------------------*/
@@ -249,6 +284,8 @@ void followparent_recalc(struct clk *clk)
                return;
 
        clk->rate = clk->parent->rate;
+       if (unlikely(clk->flags & RATE_PROPAGATES))
+               propagate_rate(clk);
 }
 
 /* Propagate rate to children */
index fecd3d6259950def5af1ad18fcff6bf16fcd5710..dd8708ad0a71833339c5e3abc23cf4711604275c 100644 (file)
@@ -93,8 +93,12 @@ static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
         * in the kernel. */
        for (i = 0; i < omap_board_config_size; i++) {
                if (omap_board_config[i].tag == tag) {
-                       kinfo = &omap_board_config[i];
-                       break;
+                       if (skip == 0) {
+                               kinfo = &omap_board_config[i];
+                               break;
+                       } else {
+                               skip--;
+                       }
                }
        }
        if (kinfo == NULL)
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
new file mode 100644 (file)
index 0000000..9128a80
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * linux/arch/arm/plat-omap/debug-leds.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+
+/* Many OMAP development platforms reuse the same "debug board"; these
+ * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
+ * debug board (all green), accessed through FPGA registers.
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators
+ * in preference to the ones on the debug board, for a "Disco LED" effect.
+ *
+ * This driver exports either the original ARM LED API, the new generic
+ * one, or both.
+ */
+
+static spinlock_t                      lock;
+static struct h2p2_dbg_fpga __iomem    *fpga;
+static u16                             led_state, hw_led_state;
+
+
+#ifdef CONFIG_LEDS_OMAP_DEBUG
+#define new_led_api()  1
+#else
+#define new_led_api()  0
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/* original ARM debug LED API:
+ *  - timer and idle leds (some boards use non-FPGA leds here);
+ *  - up to 4 generic leds, easily accessed in-kernel (any context)
+ */
+
+#define GPIO_LED_RED           3
+#define GPIO_LED_GREEN         OMAP_MPUIO(4)
+
+#define LED_STATE_ENABLED      0x01
+#define LED_STATE_CLAIMED      0x02
+#define LED_TIMER_ON           0x04
+
+#define GPIO_IDLE              GPIO_LED_GREEN
+#define GPIO_TIMER             GPIO_LED_RED
+
+static void h2p2_dbg_leds_event(led_event_t evt)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&lock, flags);
+
+       if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+               goto done;
+
+       switch (evt) {
+       case led_start:
+               if (fpga)
+                       led_state |= LED_STATE_ENABLED;
+               break;
+
+       case led_stop:
+       case led_halted:
+               /* all leds off during suspend or shutdown */
+
+               if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
+                       omap_set_gpio_dataout(GPIO_TIMER, 0);
+                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+               }
+
+               __raw_writew(~0, &fpga->leds);
+               led_state &= ~LED_STATE_ENABLED;
+               goto done;
+
+       case led_claim:
+               led_state |= LED_STATE_CLAIMED;
+               hw_led_state = 0;
+               break;
+
+       case led_release:
+               led_state &= ~LED_STATE_CLAIMED;
+               break;
+
+#ifdef CONFIG_LEDS_TIMER
+       case led_timer:
+               led_state ^= LED_TIMER_ON;
+
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
+               else {
+                       omap_set_gpio_dataout(GPIO_TIMER,
+                                       led_state & LED_TIMER_ON);
+                       goto done;
+               }
+
+               break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+       /* LED lit iff busy */
+       case led_idle_start:
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
+               else {
+                       omap_set_gpio_dataout(GPIO_IDLE, 1);
+                       goto done;
+               }
+
+               break;
+
+       case led_idle_end:
+               if (machine_is_omap_perseus2() || machine_is_omap_h4())
+                       hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
+               else {
+                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       goto done;
+               }
+
+               break;
+#endif
+
+       case led_green_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
+               break;
+       case led_green_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
+               break;
+
+       case led_amber_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
+               break;
+       case led_amber_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
+               break;
+
+       case led_red_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_RED;
+               break;
+       case led_red_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+               break;
+
+       case led_blue_on:
+               hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+               break;
+       case led_blue_off:
+               hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
+               break;
+
+       default:
+               break;
+       }
+
+
+       /*
+        *  Actually burn the LEDs
+        */
+       if (led_state & LED_STATE_ENABLED)
+               __raw_writew(~hw_led_state, &fpga->leds);
+
+done:
+       spin_unlock_irqrestore(&lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* "new" LED API
+ *  - with syfs access and generic triggering
+ *  - not readily accessible to in-kernel drivers
+ */
+
+struct dbg_led {
+       struct led_classdev     cdev;
+       u16                     mask;
+};
+
+static struct dbg_led dbg_leds[] = {
+       /* REVISIT at least H2 uses different timer & cpu leds... */
+#ifndef CONFIG_LEDS_TIMER
+       { .mask = 1 << 0,  .cdev.name =  "d4:green",
+               .cdev.default_trigger = "heartbeat", },
+#endif
+#ifndef CONFIG_LEDS_CPU
+       { .mask = 1 << 1,  .cdev.name =  "d5:green", },         /* !idle */
+#endif
+       { .mask = 1 << 2,  .cdev.name =  "d6:green", },
+       { .mask = 1 << 3,  .cdev.name =  "d7:green", },
+
+       { .mask = 1 << 4,  .cdev.name =  "d8:green", },
+       { .mask = 1 << 5,  .cdev.name =  "d9:green", },
+       { .mask = 1 << 6,  .cdev.name = "d10:green", },
+       { .mask = 1 << 7,  .cdev.name = "d11:green", },
+
+       { .mask = 1 << 8,  .cdev.name = "d12:green", },
+       { .mask = 1 << 9,  .cdev.name = "d13:green", },
+       { .mask = 1 << 10, .cdev.name = "d14:green", },
+       { .mask = 1 << 11, .cdev.name = "d15:green", },
+
+#ifndef        CONFIG_LEDS
+       { .mask = 1 << 12, .cdev.name = "d16:green", },
+       { .mask = 1 << 13, .cdev.name = "d17:green", },
+       { .mask = 1 << 14, .cdev.name = "d18:green", },
+       { .mask = 1 << 15, .cdev.name = "d19:green", },
+#endif
+};
+
+static void
+fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+       struct dbg_led  *led = container_of(cdev, struct dbg_led, cdev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&lock, flags);
+       if (value == LED_OFF)
+               hw_led_state &= ~led->mask;
+       else
+               hw_led_state |= led->mask;
+       __raw_writew(~hw_led_state, &fpga->leds);
+       spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __init newled_init(struct device *dev)
+{
+       unsigned        i;
+       struct dbg_led  *led;
+       int             status;
+
+       for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
+               led->cdev.brightness_set = fpga_led_set;
+               status = led_classdev_register(dev, &led->cdev);
+               if (status < 0)
+                       break;
+       }
+       return;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int /* __init */ fpga_probe(struct platform_device *pdev)
+{
+       struct resource *iomem;
+
+       spin_lock_init(&lock);
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem)
+               return -ENODEV;
+
+       fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
+       __raw_writew(~0, &fpga->leds);
+
+#ifdef CONFIG_LEDS
+       leds_event = h2p2_dbg_leds_event;
+       leds_event(led_start);
+#endif
+
+       if (new_led_api()) {
+               newled_init(&pdev->dev);
+       }
+
+       return 0;
+}
+
+static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+       __raw_writew(~0, &fpga->leds);
+       return 0;
+}
+
+static int fpga_resume_early(struct platform_device *pdev)
+{
+       __raw_writew(~hw_led_state, &fpga->leds);
+       return 0;
+}
+
+
+static struct platform_driver led_driver = {
+       .driver.name    = "omap_dbg_led",
+       .probe          = fpga_probe,
+       .suspend_late   = fpga_suspend_late,
+       .resume_early   = fpga_resume_early,
+};
+
+static int __init fpga_init(void)
+{
+       if (machine_is_omap_h4()
+                       || machine_is_omap_h3()
+                       || machine_is_omap_h2()
+                       || machine_is_omap_perseus2()
+                       )
+               return platform_driver_register(&led_driver);
+       return 0;
+}
+fs_initcall(fpga_init);
index eeb33fed6f7c1928bf20e098c7deb94897a8f862..c5dab1d6417e113aeae93658b45a5d5730cdebb1 100644 (file)
 #include <asm/arch/gpio.h>
 #include <asm/arch/menelaus.h>
 
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if    defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+static struct dsp_platform_data dsp_pdata = {
+       .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
+};
+
+static struct resource omap_dsp_resources[] = {
+       {
+               .name   = "dsp_mmu",
+               .start  = -1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap_dsp_device = {
+       .name           = "dsp",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap_dsp_resources),
+       .resource       = omap_dsp_resources,
+       .dev = {
+               .platform_data = &dsp_pdata,
+       },
+};
+
+static inline void omap_init_dsp(void)
+{
+       struct resource *res;
+       int irq;
+
+       if (cpu_is_omap15xx())
+               irq = INT_1510_DSP_MMU;
+       else if (cpu_is_omap16xx())
+               irq = INT_1610_DSP_MMU;
+       else if (cpu_is_omap24xx())
+               irq = INT_24XX_DSP_MMU;
+
+       res = platform_get_resource_byname(&omap_dsp_device,
+                                          IORESOURCE_IRQ, "dsp_mmu");
+       res->start = irq;
+
+       platform_device_register(&omap_dsp_device);
+}
+
+int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
+{
+       static DEFINE_MUTEX(dsp_pdata_lock);
+
+       mutex_init(&kdev->lock);
+
+       mutex_lock(&dsp_pdata_lock);
+       list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+       mutex_unlock(&dsp_pdata_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(dsp_kfunc_device_register);
+
+#else
+static inline void omap_init_dsp(void) { }
+#endif /* CONFIG_OMAP_DSP */
+
+/*-------------------------------------------------------------------------*/
+#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
 
 #define        OMAP1_I2C_BASE          0xfffb3800
 #define OMAP2_I2C_BASE1                0x48070000
@@ -48,8 +112,8 @@ static struct resource i2c_resources1[] = {
 /* DMA not used; works around erratum writing to non-empty i2c fifo */
 
 static struct platform_device omap_i2c_device1 = {
-        .name           = "i2c_omap",
-        .id             = 1,
+       .name           = "i2c_omap",
+       .id             = 1,
        .num_resources  = ARRAY_SIZE(i2c_resources1),
        .resource       = i2c_resources1,
 };
@@ -376,7 +440,7 @@ static inline void omap_init_wdt(void) {}
 
 /*-------------------------------------------------------------------------*/
 
-#if    defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE)
+#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE)
 
 #ifdef CONFIG_ARCH_OMAP24XX
 #define        OMAP_RNG_BASE           0x480A0000
@@ -436,6 +500,7 @@ static int __init omap_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
+       omap_init_dsp();
        omap_init_i2c();
        omap_init_kp();
        omap_init_mmc();
@@ -446,4 +511,3 @@ static int __init omap_init_devices(void)
        return 0;
 }
 arch_initcall(omap_init_devices);
-
index f3f84fbf8b875da63e8cf10bf178745a2eff2a7d..2d86b106ff3e06b0dbc9ffe3a8e84b0945fb96b0 100644 (file)
@@ -925,10 +925,17 @@ static int omap2_dma_handle_ch(int ch)
 {
        u32 status = OMAP_DMA_CSR_REG(ch);
 
-       if (!status)
+       if (!status) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n", ch);
                return 0;
-       if (unlikely(dma_chan[ch].dev_id == -1))
+       }
+       if (unlikely(dma_chan[ch].dev_id == -1)) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "IRQ %04x for non-allocated DMA"
+                                       "channel %d\n", status, ch);
                return 0;
+       }
        if (unlikely(status & OMAP_DMA_DROP_IRQ))
                printk(KERN_INFO
                       "DMA synchronization event drop occurred with device "
@@ -959,11 +966,15 @@ static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
        int i;
 
        val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-
-       for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) {
-               int active = val & (1 << (i - 1));
-               if (active)
-                       omap2_dma_handle_ch(i - 1);
+       if (val == 0) {
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "Spurious DMA IRQ\n");
+               return IRQ_HANDLED;
+       }
+       for (i = 0; i < OMAP_LOGICAL_DMA_CH_COUNT && val != 0; i++) {
+               if (val & 1)
+                       omap2_dma_handle_ch(i);
+               val >>= 1;
        }
 
        return IRQ_HANDLED;
index 659619f235ca325234c1bdea44cd3c05926fc17a..36073dfaa4db57810c96f1674c39f5889c13fc93 100644 (file)
@@ -372,7 +372,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 
        /* When the functional clock disappears, too quick writes seem to
         * cause an abort. */
-       __delay(15000);
+       __delay(150000);
 }
 
 #endif
index 56acb8720f789ad7047daef09ba4ec6717e70d5b..4493bcff51729a2e4340d0d196ce67e10a1611ca 100644 (file)
@@ -1,3 +1,26 @@
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * 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 <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -16,6 +39,8 @@
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
 static struct omapfb_platform_data omapfb_config;
+static int config_invalid;
+static int configured_regions;
 
 static u64 omap_fb_dma_mask = ~(u32)0;
 
@@ -30,39 +55,270 @@ static struct platform_device omap_fb_device = {
        .num_resources = 0,
 };
 
-/* called from map_io */
-void omapfb_reserve_mem(void)
+static inline int ranges_overlap(unsigned long start1, unsigned long size1,
+                                unsigned long start2, unsigned long size2)
 {
-       const struct omap_fbmem_config *fbmem_conf;
+       return (start1 >= start2 && start1 < start2 + size2) ||
+              (start2 >= start1 && start2 < start1 + size1);
+}
 
-       omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
-       omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+static inline int range_included(unsigned long start1, unsigned long size1,
+                                unsigned long start2, unsigned long size2)
+{
+       return start1 >= start2 && start1 + size1 <= start2 + size2;
+}
 
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
 
-       if (fbmem_conf != NULL) {
-               /* indicate that the bootloader already initialized the
-                * fb device, so we'll skip that part in the fb driver
-                */
-               omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
-               omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
-               if (fbmem_conf->fb_sdram_size) {
-                       pr_info("Reserving %u bytes SDRAM for frame buffer\n",
-                               fbmem_conf->fb_sdram_size);
-                       reserve_bootmem(fbmem_conf->fb_sdram_start,
-                                       fbmem_conf->fb_sdram_size);
+/* Check if there is an overlapping region. */
+static int fbmem_region_reserved(unsigned long start, size_t size)
+{
+       struct omapfb_mem_region *rg;
+       int i;
+
+       rg = &omapfb_config.mem_desc.region[0];
+       for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) {
+               if (!rg->paddr)
+                       /* Empty slot. */
+                       continue;
+               if (ranges_overlap(start, size, rg->paddr, rg->size))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Get the region_idx`th region from board config/ATAG and convert it to
+ * our internal format.
+ */
+static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+{
+       const struct omap_fbmem_config  *conf;
+       u32                             paddr;
+
+       conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+                                 struct omap_fbmem_config, region_idx);
+       if (conf == NULL)
+               return -ENOENT;
+
+       paddr = conf->start;
+       /*
+        * Low bits encode the page allocation mode, if high bits
+        * are zero. Otherwise we need a page aligned fixed
+        * address.
+        */
+       memset(rg, 0, sizeof(*rg));
+       rg->type = paddr & ~PAGE_MASK;
+       rg->paddr = paddr & PAGE_MASK;
+       rg->size = PAGE_ALIGN(conf->size);
+       return 0;
+}
+
+static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
+                                 unsigned long mem_start,
+                                 unsigned long mem_size)
+{
+       /*
+        * Check if the configuration specifies the type explicitly.
+        * type = 0 && paddr = 0, a default don't care case maps to
+        * the SDRAM type.
+        */
+       if (rg->type || (!rg->type && !rg->paddr))
+               return 0;
+       if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
+               rg->type = mem_type;
+               return 0;
+       }
+       /* Can't determine it. */
+       return -1;
+}
+
+static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
+                             unsigned long start_avail, unsigned size_avail)
+{
+       unsigned long   paddr = rg->paddr;
+       size_t          size = rg->size;
+
+       if (rg->type > OMAPFB_MEMTYPE_MAX) {
+               printk(KERN_ERR
+                       "Invalid start address for FB region %d\n", region_idx);
+               return -EINVAL;
+       }
+
+       if (!rg->size) {
+               printk(KERN_ERR "Zero size for FB region %d\n", region_idx);
+               return -EINVAL;
+       }
+
+       if (!paddr)
+               /* Allocate this dynamically, leave paddr 0 for now. */
+               return 0;
+
+       /*
+        * Fixed region for the given RAM range. Check if it's already
+        * reserved by the FB code or someone else.
+        */
+       if (fbmem_region_reserved(paddr, size) ||
+           !range_included(paddr, size, start_avail, size_avail)) {
+               printk(KERN_ERR "Trying to use reserved memory "
+                       "for FB region %d\n", region_idx);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Called from map_io. We need to call to this early enough so that we
+ * can reserve the fixed SDRAM regions before VM could get hold of them.
+ */
+void omapfb_reserve_sdram(void)
+{
+       struct bootmem_data     *bdata;
+       unsigned long           sdram_start, sdram_size;
+       unsigned long           reserved;
+       int                     i;
+
+       if (config_invalid)
+               return;
+
+       bdata = NODE_DATA(0)->bdata;
+       sdram_start = bdata->node_boot_start;
+       sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
+       reserved = 0;
+       for (i = 0; ; i++) {
+               struct omapfb_mem_region        rg;
+
+               if (get_fbmem_region(i, &rg) < 0)
+                       break;
+               if (i == OMAPFB_PLANE_NUM) {
+                       printk(KERN_ERR
+                               "Extraneous FB mem configuration entries\n");
+                       config_invalid = 1;
+                       return;
                }
+               /* Check if it's our memory type. */
+               if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM,
+                                         sdram_start, sdram_size) < 0 ||
+                   (rg.type != OMAPFB_MEMTYPE_SDRAM))
+                       continue;
+               BUG_ON(omapfb_config.mem_desc.region[i].size);
+               if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) {
+                       config_invalid = 1;
+                       return;
+               }
+               if (rg.paddr)
+                       reserve_bootmem(rg.paddr, rg.size);
+               reserved += rg.size;
+               omapfb_config.mem_desc.region[i] = rg;
+               configured_regions++;
        }
+       omapfb_config.mem_desc.region_cnt = i;
+       if (reserved)
+               pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
+                        reserved);
+}
+
+/*
+ * Called at sram init time, before anything is pushed to the SRAM stack.
+ * Because of the stack scheme, we will allocate everything from the
+ * start of the lowest address region to the end of SRAM. This will also
+ * include padding for page alignment and possible holes between regions.
+ *
+ * As opposed to the SDRAM case, we'll also do any dynamic allocations at
+ * this point, since the driver built as a module would have problem with
+ * freeing / reallocating the regions.
+ */
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+                                 unsigned long sram_vstart,
+                                 unsigned long sram_size,
+                                 unsigned long pstart_avail,
+                                 unsigned long size_avail)
+{
+       struct omapfb_mem_region        rg;
+       unsigned long                   pend_avail;
+       unsigned long                   reserved;
+       int                             i;
+
+       if (config_invalid)
+               return 0;
+
+       reserved = 0;
+       pend_avail = pstart_avail + size_avail;
+       for (i = 0; ; i++) {
+               if (get_fbmem_region(i, &rg) < 0)
+                       break;
+               if (i == OMAPFB_PLANE_NUM) {
+                       printk(KERN_ERR
+                               "Extraneous FB mem configuration entries\n");
+                       config_invalid = 1;
+                       return 0;
+               }
+
+               /* Check if it's our memory type. */
+               if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM,
+                                         sram_pstart, sram_size) < 0 ||
+                   (rg.type != OMAPFB_MEMTYPE_SRAM))
+                       continue;
+               BUG_ON(omapfb_config.mem_desc.region[i].size);
+
+               if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) {
+                       config_invalid = 1;
+                       return 0;
+               }
+
+               if (!rg.paddr) {
+                       /* Dynamic allocation */
+                       if ((size_avail & PAGE_MASK) < rg.size) {
+                               printk("Not enough SRAM for FB region %d\n",
+                                       i);
+                               config_invalid = 1;
+                               return 0;
+                       }
+                       size_avail = (size_avail - rg.size) & PAGE_MASK;
+                       rg.paddr = pstart_avail + size_avail;
+               }
+               /* Reserve everything above the start of the region. */
+               if (pend_avail - rg.paddr > reserved)
+                       reserved = pend_avail - rg.paddr;
+               size_avail = pend_avail - reserved - pstart_avail;
+
+               /*
+                * We have a kernel mapping for this already, so the
+                * driver won't have to make one.
+                */
+               rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart);
+               omapfb_config.mem_desc.region[i] = rg;
+               configured_regions++;
+       }
+       omapfb_config.mem_desc.region_cnt = i;
+       if (reserved)
+               pr_info("Reserving %lu bytes SRAM for frame buffer\n",
+                        reserved);
+       return reserved;
+}
+
+void omapfb_set_ctrl_platform_data(void *data)
+{
+       omapfb_config.ctrl_platform_data = data;
 }
 
 static inline int omap_init_fb(void)
 {
        const struct omap_lcd_config *conf;
 
+       if (config_invalid)
+               return 0;
+       if (configured_regions != omapfb_config.mem_desc.region_cnt) {
+               printk(KERN_ERR "Invalid FB mem configuration entries\n");
+               return 0;
+       }
        conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
-       if (conf == NULL)
+       if (conf == NULL) {
+               if (configured_regions)
+                       /* FB mem config, but no LCD config? */
+                       printk(KERN_ERR "Missing LCD configuration\n");
                return 0;
-
+       }
        omapfb_config.lcd = *conf;
 
        return platform_device_register(&omap_fb_device);
@@ -72,7 +328,16 @@ arch_initcall(omap_init_fb);
 
 #else
 
-void omapfb_reserve_mem(void) {}
+void omapfb_reserve_sdram(void) {}
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+                                 unsigned long sram_vstart,
+                                 unsigned long sram_size,
+                                 unsigned long start_avail,
+                                 unsigned long size_avail)
+{
+       return 0;
+}
+
 
 #endif
 
index 9dc6d3617bdb8182f02b900522830331446f85fc..337455dfe64d493e64746d62caf38e7d169e71d2 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/sysdev.h>
 #include <linux/err.h>
@@ -1545,7 +1544,7 @@ void omap2_gpio_resume_after_retention(void)
  * This may get called early from board specific init
  * for boards that have interrupts routed via FPGA.
  */
-int omap_gpio_init(void)
+int __init omap_gpio_init(void)
 {
        if (!initialized)
                return _omap_gpio_init();
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
new file mode 100644 (file)
index 0000000..de7e6ef
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * OMAP mailbox driver
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *             Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/blkdev.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include "mailbox.h"
+
+static struct omap_mbox *mboxes;
+static DEFINE_RWLOCK(mboxes_lock);
+
+/* Mailbox Sequence Bit function */
+void omap_mbox_init_seq(struct omap_mbox *mbox)
+{
+       mbox_seq_init(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_init_seq);
+
+/*
+ * message sender
+ */
+static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
+{
+       int ret = 0, i = 1000;
+
+       while (mbox_fifo_full(mbox)) {
+               if (mbox->ops->type == OMAP_MBOX_TYPE2)
+                       return -1;
+               if (--i == 0)
+                       return -1;
+               udelay(1);
+       }
+
+       if (arg && mbox->txq->callback) {
+               ret = mbox->txq->callback(arg);
+               if (ret)
+                       goto out;
+       }
+
+       mbox_seq_toggle(mbox, &msg);
+       mbox_fifo_write(mbox, msg);
+ out:
+       return ret;
+}
+
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
+{
+       struct request *rq;
+       struct request_queue *q = mbox->txq->queue;
+       int ret = 0;
+
+       rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+       if (unlikely(!rq)) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       rq->data = (void *)msg;
+       blk_insert_request(q, rq, 0, arg);
+
+       schedule_work(&mbox->txq->work);
+ fail:
+       return ret;
+}
+EXPORT_SYMBOL(omap_mbox_msg_send);
+
+static void mbox_tx_work(struct work_struct *work)
+{
+       int ret;
+       struct request *rq;
+       struct omap_mbox_queue *mq = container_of(work,
+                               struct omap_mbox_queue, work);
+       struct omap_mbox *mbox = mq->queue->queuedata;
+       struct request_queue *q = mbox->txq->queue;
+
+       while (1) {
+               spin_lock(q->queue_lock);
+               rq = elv_next_request(q);
+               spin_unlock(q->queue_lock);
+
+               if (!rq)
+                       break;
+
+               ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special);
+               if (ret) {
+                       enable_mbox_irq(mbox, IRQ_TX);
+                       return;
+               }
+
+               spin_lock(q->queue_lock);
+               blkdev_dequeue_request(rq);
+               end_that_request_last(rq, 0);
+               spin_unlock(q->queue_lock);
+       }
+}
+
+/*
+ * Message receiver(workqueue)
+ */
+static void mbox_rx_work(struct work_struct *work)
+{
+       struct omap_mbox_queue *mq =
+                       container_of(work, struct omap_mbox_queue, work);
+       struct omap_mbox *mbox = mq->queue->queuedata;
+       struct request_queue *q = mbox->rxq->queue;
+       struct request *rq;
+       mbox_msg_t msg;
+       unsigned long flags;
+
+       if (mbox->rxq->callback == NULL) {
+               sysfs_notify(&mbox->dev.kobj, NULL, "mbox");
+               return;
+       }
+
+       while (1) {
+               spin_lock_irqsave(q->queue_lock, flags);
+               rq = elv_next_request(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+               if (!rq)
+                       break;
+
+               msg = (mbox_msg_t) rq->data;
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blkdev_dequeue_request(rq);
+               end_that_request_last(rq, 0);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               mbox->rxq->callback((void *)msg);
+       }
+}
+
+/*
+ * Mailbox interrupt handler
+ */
+static void mbox_txq_fn(request_queue_t * q)
+{
+}
+
+static void mbox_rxq_fn(request_queue_t * q)
+{
+}
+
+static void __mbox_tx_interrupt(struct omap_mbox *mbox)
+{
+       disable_mbox_irq(mbox, IRQ_TX);
+       ack_mbox_irq(mbox, IRQ_TX);
+       schedule_work(&mbox->txq->work);
+}
+
+static void __mbox_rx_interrupt(struct omap_mbox *mbox)
+{
+       struct request *rq;
+       mbox_msg_t msg;
+       request_queue_t *q = mbox->rxq->queue;
+
+       disable_mbox_irq(mbox, IRQ_RX);
+
+       while (!mbox_fifo_empty(mbox)) {
+               rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+               if (unlikely(!rq))
+                       goto nomem;
+
+               msg = mbox_fifo_read(mbox);
+               rq->data = (void *)msg;
+
+               if (unlikely(mbox_seq_test(mbox, msg))) {
+                       pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
+                       if (mbox->err_notify)
+                               mbox->err_notify();
+               }
+
+               blk_insert_request(q, rq, 0, NULL);
+               if (mbox->ops->type == OMAP_MBOX_TYPE1)
+                       break;
+       }
+
+       /* no more messages in the fifo. clear IRQ source. */
+       ack_mbox_irq(mbox, IRQ_RX);
+       enable_mbox_irq(mbox, IRQ_RX);
+       nomem:
+       schedule_work(&mbox->rxq->work);
+}
+
+static irqreturn_t mbox_interrupt(int irq, void *p)
+{
+       struct omap_mbox *mbox = (struct omap_mbox *)p;
+
+       if (is_mbox_irq(mbox, IRQ_TX))
+               __mbox_tx_interrupt(mbox);
+
+       if (is_mbox_irq(mbox, IRQ_RX))
+               __mbox_rx_interrupt(mbox);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t
+omap_mbox_write(struct device *dev, struct device_attribute *attr,
+               const char * buf, size_t count)
+{
+       int ret;
+       mbox_msg_t *p = (mbox_msg_t *)buf;
+       struct omap_mbox *mbox = dev_get_drvdata(dev);
+
+       for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) {
+               ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL);
+               if (ret)
+                       return -EAGAIN;
+               p++;
+       }
+
+       return (size_t)((char *)p - buf);
+}
+
+static ssize_t
+omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       unsigned long flags;
+       struct request *rq;
+       mbox_msg_t *p = (mbox_msg_t *) buf;
+       struct omap_mbox *mbox = dev_get_drvdata(dev);
+       struct request_queue *q = mbox->rxq->queue;
+
+       while (1) {
+               spin_lock_irqsave(q->queue_lock, flags);
+               rq = elv_next_request(q);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               if (!rq)
+                       break;
+
+               *p = (mbox_msg_t) rq->data;
+
+               spin_lock_irqsave(q->queue_lock, flags);
+               blkdev_dequeue_request(rq);
+               end_that_request_last(rq, 0);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               if (unlikely(mbox_seq_test(mbox, *p))) {
+                       pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
+                       continue;
+               }
+               p++;
+       }
+
+       pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+
+       return (size_t) ((char *)p - buf);
+}
+
+static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
+
+static ssize_t mbox_show(struct class *class, char *buf)
+{
+       return sprintf(buf, "mbox");
+}
+
+static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
+
+static struct class omap_mbox_class = {
+       .name = "omap_mbox",
+};
+
+static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
+                                       request_fn_proc * proc,
+                                       void (*work) (struct work_struct *))
+{
+       request_queue_t *q;
+       struct omap_mbox_queue *mq;
+
+       mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
+       if (!mq)
+               return NULL;
+
+       spin_lock_init(&mq->lock);
+
+       q = blk_init_queue(proc, &mq->lock);
+       if (!q)
+               goto error;
+       q->queuedata = mbox;
+       mq->queue = q;
+
+       INIT_WORK(&mq->work, work);
+
+       return mq;
+error:
+       kfree(mq);
+       return NULL;
+}
+
+static void mbox_queue_free(struct omap_mbox_queue *q)
+{
+       blk_cleanup_queue(q->queue);
+       kfree(q);
+}
+
+static int omap_mbox_init(struct omap_mbox *mbox)
+{
+       int ret;
+       struct omap_mbox_queue *mq;
+
+       if (likely(mbox->ops->startup)) {
+               ret = mbox->ops->startup(mbox);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       mbox->dev.class = &omap_mbox_class;
+       strlcpy(mbox->dev.bus_id, mbox->name, KOBJ_NAME_LEN);
+       dev_set_drvdata(&mbox->dev, mbox);
+
+       ret = device_register(&mbox->dev);
+       if (unlikely(ret))
+               goto fail_device_reg;
+
+       ret = device_create_file(&mbox->dev, &dev_attr_mbox);
+       if (unlikely(ret)) {
+               printk(KERN_ERR
+                       "device_create_file failed: %d\n", ret);
+               goto fail_create_mbox;
+       }
+
+       ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
+                               mbox->name, mbox);
+       if (unlikely(ret)) {
+               printk(KERN_ERR
+                       "failed to register mailbox interrupt:%d\n", ret);
+               goto fail_request_irq;
+       }
+       enable_mbox_irq(mbox, IRQ_RX);
+
+       mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
+       if (!mq) {
+               ret = -ENOMEM;
+               goto fail_alloc_txq;
+       }
+       mbox->txq = mq;
+
+       mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
+       if (!mq) {
+               ret = -ENOMEM;
+               goto fail_alloc_rxq;
+       }
+       mbox->rxq = mq;
+
+       return 0;
+
+ fail_alloc_rxq:
+       mbox_queue_free(mbox->txq);
+ fail_alloc_txq:
+       free_irq(mbox->irq, mbox);
+ fail_request_irq:
+       device_remove_file(&mbox->dev, &dev_attr_mbox);
+ fail_create_mbox:
+       device_unregister(&mbox->dev);
+ fail_device_reg:
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
+
+       return ret;
+}
+
+static void omap_mbox_fini(struct omap_mbox *mbox)
+{
+       mbox_queue_free(mbox->txq);
+       mbox_queue_free(mbox->rxq);
+
+       free_irq(mbox->irq, mbox);
+       device_remove_file(&mbox->dev, &dev_attr_mbox);
+       class_unregister(&omap_mbox_class);
+
+       if (unlikely(mbox->ops->shutdown))
+               mbox->ops->shutdown(mbox);
+}
+
+static struct omap_mbox **find_mboxes(const char *name)
+{
+       struct omap_mbox **p;
+
+       for (p = &mboxes; *p; p = &(*p)->next) {
+               if (strcmp((*p)->name, name) == 0)
+                       break;
+       }
+
+       return p;
+}
+
+struct omap_mbox *omap_mbox_get(const char *name)
+{
+       struct omap_mbox *mbox;
+       int ret;
+
+       read_lock(&mboxes_lock);
+       mbox = *(find_mboxes(name));
+       if (mbox == NULL) {
+               read_unlock(&mboxes_lock);
+               return ERR_PTR(-ENOENT);
+       }
+
+       read_unlock(&mboxes_lock);
+
+       ret = omap_mbox_init(mbox);
+       if (ret)
+               return ERR_PTR(-ENODEV);
+
+       return mbox;
+}
+EXPORT_SYMBOL(omap_mbox_get);
+
+void omap_mbox_put(struct omap_mbox *mbox)
+{
+       omap_mbox_fini(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_put);
+
+int omap_mbox_register(struct omap_mbox *mbox)
+{
+       int ret = 0;
+       struct omap_mbox **tmp;
+
+       if (!mbox)
+               return -EINVAL;
+       if (mbox->next)
+               return -EBUSY;
+
+       write_lock(&mboxes_lock);
+       tmp = find_mboxes(mbox->name);
+       if (*tmp)
+               ret = -EBUSY;
+       else
+               *tmp = mbox;
+       write_unlock(&mboxes_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(omap_mbox_register);
+
+int omap_mbox_unregister(struct omap_mbox *mbox)
+{
+       struct omap_mbox **tmp;
+
+       write_lock(&mboxes_lock);
+       tmp = &mboxes;
+       while (*tmp) {
+               if (mbox == *tmp) {
+                       *tmp = mbox->next;
+                       mbox->next = NULL;
+                       write_unlock(&mboxes_lock);
+                       return 0;
+               }
+               tmp = &(*tmp)->next;
+       }
+       write_unlock(&mboxes_lock);
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(omap_mbox_unregister);
+
+static int __init omap_mbox_class_init(void)
+{
+       int ret = class_register(&omap_mbox_class);
+       if (!ret)
+               ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
+
+       return ret;
+}
+
+static void __exit omap_mbox_class_exit(void)
+{
+       class_remove_file(&omap_mbox_class, &class_attr_mbox);
+       class_unregister(&omap_mbox_class);
+}
+
+subsys_initcall(omap_mbox_class_init);
+module_exit(omap_mbox_class_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h
new file mode 100644 (file)
index 0000000..67c6740
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Mailbox internal functions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * 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.
+ */
+
+#ifndef __ARCH_ARM_PLAT_MAILBOX_H
+#define __ARCH_ARM_PLAT_MAILBOX_H
+
+/*
+ * Mailbox sequence bit API
+ */
+#if defined(CONFIG_ARCH_OMAP1)
+#  define MBOX_USE_SEQ_BIT
+#elif defined(CONFIG_ARCH_OMAP2)
+#  define MBOX_USE_SEQ_BIT
+#endif
+
+#ifdef MBOX_USE_SEQ_BIT
+/* seq_rcv should be initialized with any value other than
+ * 0 and 1 << 31, to allow either value for the first
+ * message.  */
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+       /* any value other than 0 and 1 << 31 */
+       mbox->seq_rcv = 0xffffffff;
+}
+
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+       /* add seq_snd to msg */
+       *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
+       /* flip seq_snd */
+       mbox->seq_snd ^= 1 << 31;
+}
+
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       mbox_msg_t seq = msg & (1 << 31);
+       if (seq == mbox->seq_rcv)
+               return -1;
+       mbox->seq_rcv = seq;
+       return 0;
+}
+#else
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+}
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+}
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       return 0;
+}
+#endif
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
+{
+       return mbox->ops->fifo_read(mbox);
+}
+static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+       mbox->ops->fifo_write(mbox, msg);
+}
+static inline int mbox_fifo_empty(struct omap_mbox *mbox)
+{
+       return mbox->ops->fifo_empty(mbox);
+}
+static inline int mbox_fifo_full(struct omap_mbox *mbox)
+{
+       return mbox->ops->fifo_full(mbox);
+}
+
+/* Mailbox IRQ handle functions */
+static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+       mbox->ops->enable_irq(mbox, irq);
+}
+static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+       mbox->ops->disable_irq(mbox, irq);
+}
+static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+       if (mbox->ops->ack_irq)
+               mbox->ops->ack_irq(mbox, irq);
+}
+static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+       return mbox->ops->is_irq(mbox, irq);
+}
+
+#endif                         /* __ARCH_ARM_PLAT_MAILBOX_H */
index 19014b2ff4c6315a6e190c3c2c03e17c33eb184b..bc46f33aede3dc5bc9ebe9394bde2183faa126ed 100644 (file)
 
 #define ROUND_DOWN(value,boundary)     ((value) & (~((boundary)-1)))
 
+static unsigned long omap_sram_start;
 static unsigned long omap_sram_base;
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-unsigned long omap_fb_sram_start;
-unsigned long omap_fb_sram_size;
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+                                        unsigned long sram_vstart,
+                                        unsigned long sram_size,
+                                        unsigned long pstart_avail,
+                                        unsigned long size_avail);
 
-/* Depending on the target RAMFS firewall setup, the public usable amount of
+/*
+ * Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessable size for all device types is 2k. A GP
  * device allows ARM11 but not other initators for full size. This
  * functionality seems ok until some nice security API happens.
@@ -77,32 +82,6 @@ static int is_sram_locked(void)
                return 1; /* assume locked with no PPA or security driver */
 }
 
-void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
-                     unsigned long *start, unsigned long *size)
-{
-       const struct omap_fbmem_config *fbmem_conf;
-
-       fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
-       if (fbmem_conf != NULL) {
-               *start = fbmem_conf->fb_sram_start;
-               *size = fbmem_conf->fb_sram_size;
-       } else {
-               *size = 0;
-               *start = 0;
-       }
-
-       if (*size && (
-           *start < start_avail ||
-           *start + *size > start_avail + size_avail)) {
-               printk(KERN_ERR "invalid FB SRAM configuration\n");
-               *start = start_avail;
-               *size = size_avail;
-       }
-
-       if (*size)
-               pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
-}
-
 /*
  * The amount of SRAM depends on the core type.
  * Note that we cannot try to test for SRAM here because writes
@@ -111,16 +90,16 @@ void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
  */
 void __init omap_detect_sram(void)
 {
-       unsigned long sram_start;
+       unsigned long reserved;
 
        if (cpu_is_omap24xx()) {
                if (is_sram_locked()) {
                        omap_sram_base = OMAP2_SRAM_PUB_VA;
-                       sram_start = OMAP2_SRAM_PUB_PA;
+                       omap_sram_start = OMAP2_SRAM_PUB_PA;
                        omap_sram_size = 0x800; /* 2K */
                } else {
                        omap_sram_base = OMAP2_SRAM_VA;
-                       sram_start = OMAP2_SRAM_PA;
+                       omap_sram_start = OMAP2_SRAM_PA;
                        if (cpu_is_omap242x())
                                omap_sram_size = 0xa0000; /* 640K */
                        else if (cpu_is_omap243x())
@@ -128,7 +107,7 @@ void __init omap_detect_sram(void)
                }
        } else {
                omap_sram_base = OMAP1_SRAM_VA;
-               sram_start = OMAP1_SRAM_PA;
+               omap_sram_start = OMAP1_SRAM_PA;
 
                if (cpu_is_omap730())
                        omap_sram_size = 0x32000;       /* 200K */
@@ -144,12 +123,11 @@ void __init omap_detect_sram(void)
                        omap_sram_size = 0x4000;
                }
        }
-       get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
-                        omap_sram_size - SRAM_BOOTLOADER_SZ,
-                        &omap_fb_sram_start, &omap_fb_sram_size);
-       if (omap_fb_sram_size)
-               omap_sram_size -= sram_start + omap_sram_size -
-                                 omap_fb_sram_start;
+       reserved = omapfb_reserve_sram(omap_sram_start, omap_sram_base,
+                                      omap_sram_size,
+                                      omap_sram_start + SRAM_BOOTLOADER_SZ,
+                                      omap_sram_size - SRAM_BOOTLOADER_SZ);
+       omap_sram_size -= reserved;
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 }
 
index 7e8096809be2bc227ef4e8acb310455a92d8cbfb..25489aafb11398f16849bb7cb225ee624d07c5e7 100644 (file)
 #include <asm/arch/usb.h>
 #include <asm/arch/board.h>
 
+#ifdef CONFIG_ARCH_OMAP1
+
+#define INT_USB_IRQ_GEN                IH2_BASE + 20
+#define INT_USB_IRQ_NISO       IH2_BASE + 30
+#define INT_USB_IRQ_ISO                IH2_BASE + 29
+#define INT_USB_IRQ_HGEN       INT_USB_HHC_1
+#define INT_USB_IRQ_OTG                IH2_BASE + 8
+
+#else
+
+#define INT_USB_IRQ_GEN                INT_24XX_USB_IRQ_GEN
+#define INT_USB_IRQ_NISO       INT_24XX_USB_IRQ_NISO
+#define INT_USB_IRQ_ISO                INT_24XX_USB_IRQ_ISO
+#define INT_USB_IRQ_HGEN       INT_24XX_USB_IRQ_HGEN
+#define INT_USB_IRQ_OTG                INT_24XX_USB_IRQ_OTG
+
+#endif
+
+
 /* These routines should handle the standard chip-specific modes
  * for usb0/1/2 ports, covering basic mux and transceiver setup.
- * Call omap_usb_init() once, from INIT_MACHINE().
  *
  * Some board-*.c files will need to set up additional mux options,
  * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
@@ -96,19 +114,26 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
 {
        u32     syscon1 = 0;
 
+       if (cpu_is_omap24xx())
+               CONTROL_DEVCONF_REG &= ~USBT0WRMODEI(USB_BIDIR_TLL);
+
        if (nwires == 0) {
-               if (!cpu_is_omap15xx()) {
+               if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
                        /* pulldown D+/D- */
                        USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
                }
                return 0;
        }
 
-       if (is_device)
-               omap_cfg_reg(W4_USB_PUEN);
+       if (is_device) {
+               if (cpu_is_omap24xx())
+                       omap_cfg_reg(J20_24XX_USB0_PUEN);
+               else
+                       omap_cfg_reg(W4_USB_PUEN);
+       }
 
-       /* internal transceiver */
-       if (nwires == 2) {
+       /* internal transceiver (unavailable on 17xx, 24xx) */
+       if (!cpu_class_is_omap2() && nwires == 2) {
                // omap_cfg_reg(P9_USB_DP);
                // omap_cfg_reg(R8_USB_DM);
 
@@ -136,29 +161,50 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
                return 0;
        }
 
-       omap_cfg_reg(V6_USB0_TXD);
-       omap_cfg_reg(W9_USB0_TXEN);
-       omap_cfg_reg(W5_USB0_SE0);
+       if (cpu_is_omap24xx()) {
+               omap_cfg_reg(K18_24XX_USB0_DAT);
+               omap_cfg_reg(K19_24XX_USB0_TXEN);
+               omap_cfg_reg(J14_24XX_USB0_SE0);
+               if (nwires != 3)
+                       omap_cfg_reg(J18_24XX_USB0_RCV);
+       } else {
+               omap_cfg_reg(V6_USB0_TXD);
+               omap_cfg_reg(W9_USB0_TXEN);
+               omap_cfg_reg(W5_USB0_SE0);
+               if (nwires != 3)
+                       omap_cfg_reg(Y5_USB0_RCV);
+       }
 
-       /* NOTE:  SPEED and SUSP aren't configured here */
+       /* NOTE:  SPEED and SUSP aren't configured here.  OTG hosts
+        * may be able to use I2C requests to set those bits along
+        * with VBUS switching and overcurrent detction.
+        */
 
-       if (nwires != 3)
-               omap_cfg_reg(Y5_USB0_RCV);
-       if (nwires != 6)
+       if (cpu_class_is_omap1() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
        switch (nwires) {
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
                break;
        case 6:
                syscon1 = 3;
-               omap_cfg_reg(AA9_USB0_VP);
-               omap_cfg_reg(R9_USB0_VM);
-               USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               if (cpu_is_omap24xx()) {
+                       omap_cfg_reg(J19_24XX_USB0_VP);
+                       omap_cfg_reg(K20_24XX_USB0_VM);
+                       CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_UNIDIR);
+               } else {
+                       omap_cfg_reg(AA9_USB0_VP);
+                       omap_cfg_reg(R9_USB0_VM);
+                       USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+               }
                break;
        default:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -171,14 +217,22 @@ static u32 __init omap_usb1_init(unsigned nwires)
 {
        u32     syscon1 = 0;
 
-       if (nwires != 6 && !cpu_is_omap15xx())
+       if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+       if (cpu_is_omap24xx())
+               CONTROL_DEVCONF_REG &= ~USBT1WRMODEI(USB_BIDIR_TLL);
+
        if (nwires == 0)
                return 0;
 
        /* external transceiver */
-       omap_cfg_reg(USB1_TXD);
-       omap_cfg_reg(USB1_TXEN);
+       if (cpu_class_is_omap1()) {
+               omap_cfg_reg(USB1_TXD);
+               omap_cfg_reg(USB1_TXEN);
+               if (nwires != 3)
+                       omap_cfg_reg(USB1_RCV);
+       }
+
        if (cpu_is_omap15xx()) {
                omap_cfg_reg(USB1_SEO);
                omap_cfg_reg(USB1_SPEED);
@@ -190,20 +244,38 @@ static u32 __init omap_usb1_init(unsigned nwires)
        } else if (cpu_is_omap1710()) {
                omap_cfg_reg(R13_1710_USB1_SE0);
                // SUSP
+       } else if (cpu_is_omap24xx()) {
+               /* NOTE:  board-specific code must set up pin muxing for usb1,
+                * since each signal could come out on either of two balls.
+                */
        } else {
-               pr_debug("usb unrecognized\n");
+               pr_debug("usb%d cpu unrecognized\n", 1);
+               return 0;
        }
-       if (nwires != 3)
-               omap_cfg_reg(USB1_RCV);
 
        switch (nwires) {
+       case 2:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM
+                */
+               syscon1 = 1;
+               CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR_TLL);
+               break;
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
                break;
        case 6:
+               if (cpu_is_omap24xx())
+                       goto bad;
                syscon1 = 3;
                omap_cfg_reg(USB1_VP);
                omap_cfg_reg(USB1_VM);
@@ -211,6 +283,7 @@ static u32 __init omap_usb1_init(unsigned nwires)
                        USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
                break;
        default:
+bad:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
                        1, nwires);
        }
@@ -221,10 +294,17 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
 {
        u32     syscon1 = 0;
 
-       /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
+       if (cpu_is_omap24xx()) {
+               CONTROL_DEVCONF_REG &= ~(USBT2WRMODEI(USB_BIDIR_TLL)
+                                       | USBT2TLL5PI);
+               alt_pingroup = 0;
+       }
+
+       /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
        if (alt_pingroup || nwires == 0)
                return 0;
-       if (nwires != 6 && !cpu_is_omap15xx())
+
+       if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
                USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
 
        /* external transceiver */
@@ -242,19 +322,54 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
                if (nwires != 3)
                        omap_cfg_reg(Y5_USB2_RCV);
                // FIXME omap_cfg_reg(USB2_SPEED);
+       } else if (cpu_is_omap24xx()) {
+               omap_cfg_reg(Y11_24XX_USB2_DAT);
+               omap_cfg_reg(AA10_24XX_USB2_SE0);
+               if (nwires > 2)
+                       omap_cfg_reg(AA12_24XX_USB2_TXEN);
+               if (nwires > 3)
+                       omap_cfg_reg(AA6_24XX_USB2_RCV);
        } else {
-               pr_debug("usb unrecognized\n");
+               pr_debug("usb%d cpu unrecognized\n", 1);
+               return 0;
        }
-       // omap_cfg_reg(USB2_SUSP);
+       // if (cpu_class_is_omap1()) omap_cfg_reg(USB2_SUSP);
 
        switch (nwires) {
+       case 2:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM
+                */
+               syscon1 = 1;
+               CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR_TLL);
+               break;
        case 3:
                syscon1 = 2;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
                break;
        case 4:
                syscon1 = 1;
+               if (cpu_is_omap24xx())
+                       CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
+               break;
+       case 5:
+               if (!cpu_is_omap24xx())
+                       goto bad;
+               omap_cfg_reg(AA4_24XX_USB2_TLLSE0);
+               /* NOTE: board-specific code must override this setting if
+                * this TLL link is not using DP/DM.  Something must also
+                * set up OTG_SYSCON2.HMC_TLL{ATTACH,SPEED}
+                */
+               syscon1 = 3;
+               CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_UNIDIR_TLL)
+                                       | USBT2TLL5PI;
                break;
        case 6:
+               if (cpu_is_omap24xx())
+                       goto bad;
                syscon1 = 3;
                if (cpu_is_omap15xx()) {
                        omap_cfg_reg(USB2_VP);
@@ -266,6 +381,7 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
                }
                break;
        default:
+bad:
                printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
                        2, nwires);
        }
@@ -294,13 +410,13 @@ static struct resource udc_resources[] = {
                .end            = UDC_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {            /* general IRQ */
-               .start          = IH2_BASE + 20,
+               .start          = INT_USB_IRQ_GEN,
                .flags          = IORESOURCE_IRQ,
        }, {            /* PIO IRQ */
-               .start          = IH2_BASE + 30,
+               .start          = INT_USB_IRQ_NISO,
                .flags          = IORESOURCE_IRQ,
        }, {            /* SOF IRQ */
-               .start          = IH2_BASE + 29,
+               .start          = INT_USB_IRQ_ISO,
                .flags          = IORESOURCE_IRQ,
        },
 };
@@ -329,11 +445,11 @@ static u64 ohci_dmamask = ~(u32)0;
 static struct resource ohci_resources[] = {
        {
                .start  = OMAP_OHCI_BASE,
-               .end    = OMAP_OHCI_BASE + 4096 - 1,
+               .end    = OMAP_OHCI_BASE + 0xff,
                .flags  = IORESOURCE_MEM,
        },
        {
-               .start  = INT_USB_HHC_1,
+               .start  = INT_USB_IRQ_HGEN,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -361,7 +477,7 @@ static struct resource otg_resources[] = {
                .end            = OTG_BASE + 0xff,
                .flags          = IORESOURCE_MEM,
        }, {
-               .start          = IH2_BASE + 8,
+               .start          = INT_USB_IRQ_OTG,
                .flags          = IORESOURCE_IRQ,
        },
 };
@@ -385,7 +501,7 @@ static struct platform_device otg_device = {
 
 
 // FIXME correct answer depends on hmc_mode,
-// as does any nonzero value for config->otg port number
+// as does (on omap1) any nonzero value for config->otg port number
 #ifdef CONFIG_USB_GADGET_OMAP
 #define        is_usb0_device(config)  1
 #else
@@ -426,12 +542,13 @@ omap_otg_init(struct omap_usb_config *config)
        if (config->otg)
                syscon |= OTG_EN;
 #endif
-       pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
+       if (cpu_class_is_omap1())
+               pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
        pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
        OTG_SYSCON_2_REG = syscon;
 
        printk("USB: hmc %d", config->hmc_mode);
-       if (alt_pingroup)
+       if (!alt_pingroup)
                printk(", usb2 alt %d wires", config->pins[2]);
        else if (config->pins[0])
                printk(", usb0 %d wires%s", config->pins[0],
@@ -444,10 +561,12 @@ omap_otg_init(struct omap_usb_config *config)
                printk(", Mini-AB on usb%d", config->otg - 1);
        printk("\n");
 
-       /* leave USB clocks/controllers off until needed */
-       ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
-       ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
-       ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+       if (cpu_class_is_omap1()) {
+               /* leave USB clocks/controllers off until needed */
+               ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+               ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+               ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+       }
        syscon = OTG_SYSCON_1_REG;
        syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
 
@@ -585,7 +704,7 @@ omap_usb_init(void)
        }
        platform_data = *config;
 
-       if (cpu_is_omap730() || cpu_is_omap16xx())
+       if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
                omap_otg_init(&platform_data);
        else if (cpu_is_omap15xx())
                omap_1510_usb_init(&platform_data);
index 435349dc3243fa352bd17d315f3921254f752d3c..7b7ae790b00da07ebfede651cd10d2bfa1706e89 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/sleep.S
+/* linux/arch/arm/plat-s3c24xx/sleep.S
  *
  * Copyright (c) 2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
index 6115fc1f0cfab65c06277da9bfc46e8de89ade6c..dc6bc01f232cb3a1b2574ef40e8ff043070ddd7a 100644 (file)
@@ -16,7 +16,7 @@ AFLAGS                += -mrelax -mno-pic
 CFLAGS_MODULE  += -mno-relax
 LDFLAGS_vmlinux        += --relax
 
-cpuflags-$(CONFIG_CPU_AP7000)  += -mcpu=ap7000
+cpuflags-$(CONFIG_CPU_AT32AP7000)      += -mcpu=ap7000
 
 CFLAGS         += $(cpuflags-y)
 AFLAGS         += $(cpuflags-y)
index 4e4181ed1c6d52a70a5308a50aa4a2a7761099f0..13f988402613a038133f0e84289565210382600a 100644 (file)
@@ -330,13 +330,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 {
        struct pt_regs *childregs;
 
-       childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1;
+       childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
        *childregs = *regs;
 
        if (user_mode(regs))
                childregs->sp = usp;
        else
-               childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE;
+               childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
 
        childregs->r12 = 0; /* Set return value for child */
 
@@ -403,7 +403,7 @@ unsigned long get_wchan(struct task_struct *p)
        if (!p || p == current || p->state == TASK_RUNNING)
                return 0;
 
-       stack_page = (unsigned long)p->thread_info;
+       stack_page = (unsigned long)task_stack_page(p);
        BUG_ON(!stack_page);
 
        /*
index 8ac74dddbbdee588b45bdf5598f3b229226fd32a..3c36c2d1614827894a4bfff8d823ce9bf194d1ba 100644 (file)
@@ -24,7 +24,7 @@
 
 static struct pt_regs *get_user_regs(struct task_struct *tsk)
 {
-       return (struct pt_regs *)((unsigned long) tsk->thread_info +
+       return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
                                  THREAD_SIZE - sizeof(struct pt_regs));
 }
 
index 7c279586fbbac96b6445adc074ec56848c213e7f..07f6a6fa340de67e07eef9c0f57156008516c0b2 100644 (file)
@@ -291,4 +291,5 @@ sys_call_table:
        .long   sys_shmget              /* 275 */
        .long   sys_shmdt
        .long   sys_shmctl
+       .long   sys_utimensat
        .long   sys_ni_syscall          /* r8 is saturated at nr_syscalls */
index 4de9edf96ed26c3c8fc8632d1235c300f398cdf5..86d107511dd4dc1290e765714a2b560432e85a17 100644 (file)
@@ -123,7 +123,7 @@ asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
 
 /* This way of handling undefined instructions is stolen from ARM */
 static LIST_HEAD(undef_hook);
-static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(undef_lock);
 
 void register_undef_hook(struct undef_hook *hook)
 {
index 7ad20cfb48a821b117d5c25d55b002b978f5059c..e7f72c995a3251361a912521537455ca16de9f11 100644 (file)
@@ -35,7 +35,7 @@ SECTIONS
                        _einittext = .;
                . = ALIGN(4);
                __tagtable_begin = .;
-                       *(.taglist)
+                       *(.taglist.init)
                __tagtable_end = .;
                        *(.init.data)
                . = ALIGN(16);
index 00c435452d7e500e473b3cbbeb1b4f1d939d5659..0f8c89c9f83243532c57dded20c5fc1be0893b91 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "clock.h"
 
-static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clk_lock);
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
index b68d669f823de0a39f1f8bedebc3f5bd13429264..099212d4567c5d33d649c2c0988ec538dfb49803 100644 (file)
@@ -112,16 +112,21 @@ void dma_free_coherent(struct device *dev, size_t size,
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-#if 0
 void *dma_alloc_writecombine(struct device *dev, size_t size,
                             dma_addr_t *handle, gfp_t gfp)
 {
        struct page *page;
+       dma_addr_t phys;
 
        page = __dma_alloc(dev, size, handle, gfp);
+       if (!page)
+               return NULL;
+
+       phys = page_to_phys(page);
+       *handle = phys;
 
        /* Now, map the page into P3 with write-combining turned on */
-       return __ioremap(page_to_phys(page), size, _PAGE_BUFFER);
+       return __ioremap(phys, size, _PAGE_BUFFER);
 }
 EXPORT_SYMBOL(dma_alloc_writecombine);
 
@@ -132,8 +137,7 @@ void dma_free_writecombine(struct device *dev, size_t size,
 
        iounmap(cpu_addr);
 
-       page = bus_to_page(handle);
+       page = phys_to_page(handle);
        __dma_free(dev, size, page, handle);
 }
 EXPORT_SYMBOL(dma_free_writecombine);
-#endif
index 41d9a9f897002f5536ecca2eeae0ad07b09d7cbd..e455f4504509518c9791163fd05d20d443434735 100644 (file)
@@ -46,7 +46,7 @@ int main(void)
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(TASK_MM, offsetof(struct task_struct, mm));
        DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
        DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
index d7c8e514cb92185c406dd290a4b7164c3044cc12..e718bb4a1ef027fdc050f51d4303cbe11a8905d0 100644 (file)
@@ -73,7 +73,7 @@
 static inline struct pt_regs *get_user_regs(struct task_struct *task)
 {
        return (struct pt_regs *)
-           ((unsigned long)task->thread_info +
+           ((unsigned long)task_stack_page(task) +
             (THREAD_SIZE - sizeof(struct pt_regs)));
 }
 
@@ -99,7 +99,7 @@ static inline long get_reg(struct task_struct *task, int regno)
        unsigned char *reg_ptr;
 
        struct pt_regs *regs =
-           (struct pt_regs *)((unsigned long)task->thread_info +
+           (struct pt_regs *)((unsigned long)task_stack_page(task) +
                               (THREAD_SIZE - sizeof(struct pt_regs)));
        reg_ptr = (char *)regs;
 
@@ -125,7 +125,7 @@ put_reg(struct task_struct *task, int regno, unsigned long data)
        char * reg_ptr;
 
        struct pt_regs *regs =
-           (struct pt_regs *)((unsigned long)task->thread_info +
+           (struct pt_regs *)((unsigned long)task_stack_page(task) +
                               (THREAD_SIZE - sizeof(struct pt_regs)));
        reg_ptr = (char *)regs;
 
index f64624fc4504bef716e5971ae5290011c5fed9f0..1d859c16931e3628853b80bdefa4664bda69b863 100644 (file)
@@ -603,7 +603,7 @@ config ETRAX_CARDBUS
         select HOTPLUG
         select PCCARD_NONSTATIC
         help
-        Enabled the ETRAX Carbus driver.
+        Enabled the ETRAX Cardbus driver.
 
 config PCI
        bool
index eed694312a795a4e6cae4c6a6d4e579e781beaf3..114738a4558280b264eed8589d91618352320a87 100644 (file)
@@ -45,15 +45,15 @@ config TIME_LOW_RES
        bool
        default y
 
-config ARCH_HAS_ILOG2_U32
+config QUICKLIST
        bool
        default y
 
-config ARCH_HAS_ILOG2_U64
+config ARCH_HAS_ILOG2_U32
        bool
        default y
 
-config ARCH_USES_SLAB_PAGE_STRUCT
+config ARCH_HAS_ILOG2_U64
        bool
        default y
 
index 940ac306e9a0e5b13bf54ff610ec4fc1601a769e..43dc08ec7511eff6b3dba5b4a632ac9dc34d7ba2 100644 (file)
@@ -1482,6 +1482,16 @@ sys_call_table:
        .long sys_faccessat
        .long sys_pselect6
        .long sys_ppoll
+       .long sys_unshare               /* 310 */
+       .long sys_set_robust_list
+       .long sys_get_robust_list
+       .long sys_splice
+       .long sys_sync_file_range
+       .long sys_tee                   /* 315 */
+       .long sys_vmsplice
+       .long sys_move_pages
+       .long sys_getcpu
+       .long sys_epoll_pwait
 
 
 syscall_table_size = (. - sys_call_table)
index 9550f37fb62c112b1a58d2908ab9363493acc55c..1e7a101cbf4c8c645c894adfdf9f718f6b0e76eb 100644 (file)
@@ -1195,7 +1195,7 @@ static void gdbstub_check_breakpoint(void)
 /*
  *
  */
-static void __attribute__((unused)) gdbstub_show_regs(void)
+static void __maybe_unused gdbstub_show_regs(void)
 {
        unsigned long *reg;
        int loop;
@@ -1223,7 +1223,7 @@ static void __attribute__((unused)) gdbstub_show_regs(void)
 /*
  * dump debugging regs
  */
-static void __attribute__((unused)) gdbstub_dump_debugregs(void)
+static void __maybe_unused gdbstub_dump_debugregs(void)
 {
        gdbstub_printk("DCR    %08lx  ", __debug_status.dcr);
        gdbstub_printk("BRR    %08lx\n", __debug_status.brr);
@@ -2079,25 +2079,25 @@ void gdbstub_exit(int status)
  * GDB wants to call malloc() and free() to allocate memory for calling kernel
  * functions directly from its command line
  */
-static void *malloc(size_t size) __attribute__((unused));
+static void *malloc(size_t size) __maybe_unused;
 static void *malloc(size_t size)
 {
        return kmalloc(size, GFP_ATOMIC);
 }
 
-static void free(void *p) __attribute__((unused));
+static void free(void *p) __maybe_unused;
 static void free(void *p)
 {
        kfree(p);
 }
 
-static uint32_t ___get_HSR0(void) __attribute__((unused));
+static uint32_t ___get_HSR0(void) __maybe_unused;
 static uint32_t ___get_HSR0(void)
 {
        return __get_HSR(0);
 }
 
-static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused));
+static uint32_t ___set_HSR0(uint32_t x) __maybe_unused;
 static uint32_t ___set_HSR0(uint32_t x)
 {
        __set_HSR(0, x);
index 515a5cea5469e1c3bb5ab53315a441246baf7902..9583a338e9d6022b7529dcffa34201917502151d 100644 (file)
 #include <linux/elf.h>
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
+#include <linux/pagemap.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
+#include <asm/tlb.h>
 #include <asm/gdb-stub.h>
 #include <asm/mb-regs.h>
 
@@ -88,6 +90,8 @@ void cpu_idle(void)
                while (!need_resched()) {
                        irq_stat[cpu].idle_timestamp = jiffies;
 
+                       check_pgt_cache();
+
                        if (!frv_dma_inprogress && idle)
                                idle();
                }
index 8ea3ca2aba621f9390e304e6bf97a1dc140a1e3e..aa3c795d5354aa97084c0f82c23ab3abe3e25359 100644 (file)
@@ -191,7 +191,7 @@ static struct clock_cmode __pminitdata clock_cmodes_fr555[16] = {
 static const struct clock_cmode __pminitdata *clock_cmodes;
 static int __pminitdata clock_doubled;
 
-static struct uart_port __initdata __frv_uart0 = {
+static struct uart_port __pminitdata __frv_uart0 = {
        .uartclk                = 0,
        .membase                = (char *) UART0_BASE,
        .irq                    = IRQ_CPU_UART0,
@@ -200,7 +200,7 @@ static struct uart_port __initdata __frv_uart0 = {
        .flags                  = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
 };
 
-static struct uart_port __initdata __frv_uart1 = {
+static struct uart_port __pminitdata __frv_uart1 = {
        .uartclk                = 0,
        .membase                = (char *) UART1_BASE,
        .irq                    = IRQ_CPU_UART1,
index cac2c01a3a561d3545bdd58a52768e4445e75497..385fd30b142f5cf28951373df0acd80cd45245c8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/elf-fdpic.h>
+#include <asm/mman.h>
 
 /*****************************************************************************/
 /*
index 598a26ab8ad85af99981d8786d08f62362d82f52..7787c3cc52c6923d58e305b4ae10c4e3ab6b87e1 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/quicklist.h>
 #include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((aligned(PAGE_SIZE)));
-struct kmem_cache *pgd_cache;
 
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
@@ -100,7 +100,7 @@ static inline void pgd_list_del(pgd_t *pgd)
                set_page_private(next, (unsigned long) pprev);
 }
 
-void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_ctor(void *pgd)
 {
        unsigned long flags;
 
@@ -120,7 +120,7 @@ void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
 }
 
 /* never called when PTRS_PER_PMD > 1 */
-void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_dtor(void *pgd)
 {
        unsigned long flags; /* can be called from interrupt context */
 
@@ -133,7 +133,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *pgd;
 
-       pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
+       pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
        if (!pgd)
                return pgd;
 
@@ -143,15 +143,15 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 void pgd_free(pgd_t *pgd)
 {
        /* in the non-PAE case, clear_page_tables() clears user pgd entries */
-       kmem_cache_free(pgd_cache, pgd);
+       quicklist_free(0, pgd_dtor, pgd);
 }
 
 void __init pgtable_cache_init(void)
 {
-       pgd_cache = kmem_cache_create("pgd",
-                                     PTRS_PER_PGD * sizeof(pgd_t),
-                                     PTRS_PER_PGD * sizeof(pgd_t),
-                                     SLAB_PANIC,
-                                     pgd_ctor,
-                                     pgd_dtor);
 }
+
+void check_pgt_cache(void)
+{
+       quicklist_trim(0, pgd_dtor, 25, 16);
+}
+
index e0e9bcb015a905f9bb4be1ff1174b55772ddbb6b..554efe604a085ae31046423e60b227a5ceb7dbc8 100644 (file)
@@ -21,12 +21,12 @@ config GDB_MAGICPRINT
        bool "Message Output for GDB MagicPrint service"
        depends on (H8300H_SIM || H8S_SIM)
        help
-         kernel messages output useing MagicPrint service from GDB
+         kernel messages output using MagicPrint service from GDB
 
 config SYSCALL_PRINT
        bool "SystemCall trace print"
        help
-         outout history of systemcall
+         output history of systemcall
 
 config GDB_DEBUG
        bool "Use gdb stub"
index b78b82ad28a3868466b7b5a5c974fc83eea90884..fc30b4fd0914fcb607d4449b48cea1ff86772f36 100644 (file)
@@ -30,7 +30,7 @@ int main(void)
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(TASK_MM, offsetof(struct task_struct, mm));
        DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
index dab98fd99e63efa3ee58504a40c4a10ae930583f..54e21c3f2057359df65ae62bc10b6d7e67c89288 100644 (file)
@@ -31,7 +31,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_mknod)
        .long SYMBOL_NAME(sys_chmod)            /* 15 */
        .long SYMBOL_NAME(sys_chown16)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old break syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old break syscall holder */
        .long SYMBOL_NAME(sys_stat)
        .long SYMBOL_NAME(sys_lseek)
        .long SYMBOL_NAME(sys_getpid)           /* 20 */
@@ -45,11 +45,11 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_fstat)
        .long SYMBOL_NAME(sys_pause)
        .long SYMBOL_NAME(sys_utime)            /* 30 */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old stty syscall holder */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old gtty syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old stty syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old gtty syscall holder */
        .long SYMBOL_NAME(sys_access)
        .long SYMBOL_NAME(sys_nice)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 35 */                /* old ftime syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* 35 old ftime syscall holder */
        .long SYMBOL_NAME(sys_sync)
        .long SYMBOL_NAME(sys_kill)
        .long SYMBOL_NAME(sys_rename)
@@ -58,7 +58,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_dup)
        .long SYMBOL_NAME(sys_pipe)
        .long SYMBOL_NAME(sys_times)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old prof syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old prof syscall holder */
        .long SYMBOL_NAME(sys_brk)              /* 45 */
        .long SYMBOL_NAME(sys_setgid16)
        .long SYMBOL_NAME(sys_getgid16)
@@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_geteuid16)
        .long SYMBOL_NAME(sys_getegid16)        /* 50 */
        .long SYMBOL_NAME(sys_acct)
-       .long SYMBOL_NAME(sys_umount)                                   /* recycled never used phys() */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old lock syscall holder */
+       .long SYMBOL_NAME(sys_umount)           /* recycled never used phys() */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old lock syscall holder */
        .long SYMBOL_NAME(sys_ioctl)
        .long SYMBOL_NAME(sys_fcntl)            /* 55 */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old mpx syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old mpx syscall holder */
        .long SYMBOL_NAME(sys_setpgid)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old ulimit syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old ulimit syscall holder */
        .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_umask)            /* 60 */
        .long SYMBOL_NAME(sys_chroot)
@@ -112,7 +112,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_fchown16)         /* 95 */
        .long SYMBOL_NAME(sys_getpriority)
        .long SYMBOL_NAME(sys_setpriority)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old profil syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old profil syscall holder */
        .long SYMBOL_NAME(sys_statfs)
        .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
        .long SYMBOL_NAME(sys_ni_syscall)       /* ioperm for i386 */
@@ -202,8 +202,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_capset)           /* 185 */
        .long SYMBOL_NAME(sys_sigaltstack)
        .long SYMBOL_NAME(sys_sendfile)
-       .long SYMBOL_NAME(sys_ni_syscall)               /* streams1 */
-       .long SYMBOL_NAME(sys_ni_syscall)               /* streams2 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* streams1 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* streams2 */
        .long SYMBOL_NAME(sys_vfork)            /* 190 */
        .long SYMBOL_NAME(sys_getrlimit)
        .long SYMBOL_NAME(sys_mmap2)
@@ -236,10 +236,10 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_getdents64)       /* 220 */
        .long SYMBOL_NAME(sys_fcntl64)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for TUX */
-       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved TUX */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved Security */
        .long SYMBOL_NAME(sys_gettid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 225 */ /* sys_readahead */
+       .long SYMBOL_NAME(sys_readahead)        /* 225 */
        .long SYMBOL_NAME(sys_setxattr)
        .long SYMBOL_NAME(sys_lsetxattr)
        .long SYMBOL_NAME(sys_fsetxattr)
@@ -257,8 +257,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_futex)            /* 240 */
        .long SYMBOL_NAME(sys_sched_setaffinity)
        .long SYMBOL_NAME(sys_sched_getaffinity)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_set_thread_area */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_get_thread_area */
+       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_io_setup)         /* 245 */
        .long SYMBOL_NAME(sys_io_destroy)
        .long SYMBOL_NAME(sys_io_getevents)
@@ -288,8 +288,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_utimes)
        .long SYMBOL_NAME(sys_fadvise64_64)
        .long SYMBOL_NAME(sys_ni_syscall)       /* sys_vserver */
-       .long SYMBOL_NAME(sys_mbind)
-       .long SYMBOL_NAME(sys_get_mempolicy)
+       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_get_mempolicy)    /* 275 */
        .long SYMBOL_NAME(sys_set_mempolicy)
        .long SYMBOL_NAME(sys_mq_open)
        .long SYMBOL_NAME(sys_mq_unlink)
@@ -297,16 +297,42 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_mq_timedreceive)  /* 280 */
        .long SYMBOL_NAME(sys_mq_notify)
        .long SYMBOL_NAME(sys_mq_getsetattr)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for kexec */
        .long SYMBOL_NAME(sys_waitid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 285 */ /* available */
-       .long SYMBOL_NAME(sys_add_key)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_kexec_load */
+       .long SYMBOL_NAME(sys_add_key)          /* 285 */
        .long SYMBOL_NAME(sys_request_key)
        .long SYMBOL_NAME(sys_keyctl)
-
-       .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
-               .long SYMBOL_NAME(sys_ni_syscall)
-       .endr
+       .long SYMBOL_NAME(sys_ioprio_set)
+       .long SYMBOL_NAME(sys_ioprio_get)       /* 290 */
+       .long SYMBOL_NAME(sys_inotify_init)
+       .long SYMBOL_NAME(sys_inotify_add_watch)
+       .long SYMBOL_NAME(sys_inotify_rm_watch)
+       .long SYMBOL_NAME(sys_migrate_pages)
+       .long SYMBOL_NAME(sys_openat)           /* 295 */
+       .long SYMBOL_NAME(sys_mkdirat)
+       .long SYMBOL_NAME(sys_mknodat)
+       .long SYMBOL_NAME(sys_fchownat)
+       .long SYMBOL_NAME(sys_futimesat)
+       .long SYMBOL_NAME(sys_fstatat64)        /* 300 */
+       .long SYMBOL_NAME(sys_unlinkat)
+       .long SYMBOL_NAME(sys_renameat)
+       .long SYMBOL_NAME(sys_linkat)
+       .long SYMBOL_NAME(sys_symlinkat)
+       .long SYMBOL_NAME(sys_readlinkat)       /* 305 */
+       .long SYMBOL_NAME(sys_fchmodat)
+       .long SYMBOL_NAME(sys_faccessat)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_pselect6 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_ppoll */
+       .long SYMBOL_NAME(sys_unshare)          /* 310 */
+       .long SYMBOL_NAME(sys_set_robust_list)
+       .long SYMBOL_NAME(sys_get_robust_list)
+       .long SYMBOL_NAME(sys_splice)
+       .long SYMBOL_NAME(sys_sync_file_range)
+       .long SYMBOL_NAME(sys_tee)              /* 315 */
+       .long SYMBOL_NAME(sys_vmsplice)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_move_pages */
+       .long SYMBOL_NAME(sys_getcpu)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_epoll_pwait */
 
        .macro  call_sp addr
        mov.l   #SYMBOL_NAME(\addr),er6
index 64ad10f984a1027d5037f679524841d1829f1530..30944ee2e61a04ea401277cee8cd8f7af9f4b75b 100644 (file)
@@ -858,9 +858,9 @@ config RELOCATABLE
        bool "Build a relocatable kernel(EXPERIMENTAL)"
        depends on EXPERIMENTAL
        help
-         This build a kernel image that retains relocation information
+         This builds a kernel image that retains relocation information
           so it can be loaded someplace besides the default 1MB.
-         The relocations tend to the kernel binary about 10% larger,
+         The relocations tend to make the kernel binary about 10% larger,
           but are discarded at runtime.
 
          One use is for the kexec on panic case where the recovery kernel
index dce6124cb842a8307625ef673b8d97c4c99007cd..d7f6fb0b30f234895c90554e34303d6f76990115 100644 (file)
@@ -108,7 +108,7 @@ config MCORE2
        bool "Core 2/newer Xeon"
        help
          Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and 53xx)
-         CPUs. You can distingush newer from older Xeons by the CPU family
+         CPUs. You can distinguish newer from older Xeons by the CPU family
          in /proc/cpuinfo. Newer ones have 6.
 
 config MPENTIUM4
@@ -172,7 +172,7 @@ config MWINCHIP3D
        help
          Select this for an IDT Winchip-2A or 3.  Linux and GCC
          treat this chip as a 586TSC with some extended instructions
-         and alignment reqirements.  Also enable out of order memory
+         and alignment requirements.  Also enable out of order memory
          stores for this CPU, which can increase performance of some
          operations.
 
index 5e2280cf4456296feffb3a815dc937deccf59cfc..8143c9516cb429ebdacf3e2fa3f2c7b10bec963e 100644 (file)
@@ -496,11 +496,9 @@ mode_set:
        cmpb    $VIDEO_FIRST_V7>>8, %ah
        jz      setv7
        
-#ifdef CONFIG_FB
        cmpb    $VIDEO_FIRST_VESA>>8, %ah
        jnc     check_vesa
-#endif
-
+       
        orb     %ah, %ah
        jz      setmenu
        
index 80b4c5d421b1366915028b2002af39cdae851c95..e5be819492ef1daf5bed9ff653dfeaee6f117e24 100644 (file)
@@ -733,9 +733,11 @@ static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
        sys_dev = get_cpu_sysdev(cpu);
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cache_add_dev(sys_dev);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                cache_remove_dev(sys_dev);
                break;
        }
index 065005c3f16879c40fe82e59a53ebc8d95f240c8..7ba7c3abd3a4a74866899b7d6d6cae38f3113b93 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/arch/i386/kerne/cpu/mcheck/therm_throt.c
+ * linux/arch/i386/kernel/cpu/mcheck/therm_throt.c
  *
  * Thermal throttle event support code (such as syslog messaging and rate
  * limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
@@ -137,10 +137,12 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
        mutex_lock(&therm_cpu_lock);
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                err = thermal_throttle_add_dev(sys_dev);
                WARN_ON(err);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                thermal_throttle_remove_dev(sys_dev);
                break;
        }
index 6471a5a13202db49b8f0fbd79d355047ac008a89..200fb3f9ebfbda2ec232deec234ded94128f4cfb 100644 (file)
@@ -77,8 +77,10 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
        set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
        
        /* If we can run i686 user-space code, call us an i686 */
-#define USER686 (X86_FEATURE_TSC|X86_FEATURE_CX8|X86_FEATURE_CMOV)
-        if ( c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686 )
+#define USER686 ((1 << X86_FEATURE_TSC)|\
+                (1 << X86_FEATURE_CX8)|\
+                (1 << X86_FEATURE_CMOV))
+        if (c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686)
                c->x86 = 6;
 
 #ifdef CONFIG_SYSCTL
index eeae0d992337dd3e7c543e683adcc45233abb697..5c2faa10e9fac42f604d0af086af0618835c289d 100644 (file)
@@ -169,9 +169,11 @@ static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long ac
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cpuid_device_create(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
                break;
        }
index 9b10af65faaadbf400a6f219338dc9c76e61f6e4..f74dfc419b56739f3cc7e854271f5106ef701911 100644 (file)
@@ -71,12 +71,6 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_
 .section .text.head,"ax",@progbits
 ENTRY(startup_32)
 
-#ifdef CONFIG_PARAVIRT
-        movl %cs, %eax
-        testl $0x3, %eax
-        jnz startup_paravirt
-#endif
-
 /*
  * Set segments to known values.
  */
@@ -501,38 +495,6 @@ ignore_int:
        iret
 
 .section .text
-#ifdef CONFIG_PARAVIRT
-startup_paravirt:
-       cld
-       movl $(init_thread_union+THREAD_SIZE),%esp
-
-       /* We take pains to preserve all the regs. */
-       pushl   %edx
-       pushl   %ecx
-       pushl   %eax
-
-       pushl   $__start_paravirtprobe
-1:
-       movl    0(%esp), %eax
-       cmpl    $__stop_paravirtprobe, %eax
-       je      unhandled_paravirt
-       pushl   (%eax)
-       movl    8(%esp), %eax
-       call    *(%esp)
-       popl    %eax
-
-       movl    4(%esp), %eax
-       movl    8(%esp), %ecx
-       movl    12(%esp), %edx
-
-       addl    $4, (%esp)
-       jmp     1b
-
-unhandled_paravirt:
-       /* Nothing wanted us: we're screwed. */
-       ud2
-#endif
-
 /*
  * Real beginning of normal "text" segment
  */
index cbe7ec8dbb9f5311ac385ab29bd4cc9266835f5a..83f825f2e2d7db0ee5b5a002d78792219fb64b8f 100644 (file)
@@ -567,7 +567,7 @@ static int cpu_request_microcode(int cpu)
        return error;
 }
 
-static int apply_microcode_on_cpu(int cpu)
+static int apply_microcode_check_cpu(int cpu)
 {
        struct cpuinfo_x86 *c = cpu_data + cpu;
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu)
        unsigned int val[2];
        int err = 0;
 
+       /* Check if the microcode is available */
        if (!uci->mc)
-               return -EINVAL;
+               return 0;
 
        old = current->cpus_allowed;
        set_cpus_allowed(current, cpumask_of_cpu(cpu));
@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu)
        return err;
 }
 
-static void microcode_init_cpu(int cpu)
+static void microcode_init_cpu(int cpu, int resume)
 {
        cpumask_t old;
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu)
        set_cpus_allowed(current, cpumask_of_cpu(cpu));
        mutex_lock(&microcode_mutex);
        collect_cpu_info(cpu);
-       if (uci->valid && system_state == SYSTEM_RUNNING &&
-           !suspend_cpu_hotplug)
+       if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
                cpu_request_microcode(cpu);
        mutex_unlock(&microcode_mutex);
        set_cpus_allowed(current, old);
@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = {
        .name = "microcode",
 };
 
-static int mc_sysdev_add(struct sys_device *sys_dev)
+static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
 {
        int err, cpu = sys_dev->id;
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
                return 0;
 
        pr_debug("Microcode:CPU %d added\n", cpu);
-       /* If suspend_cpu_hotplug is set, the system is resuming and we should
-        * use the data from before the suspend.
-        */
-       if (suspend_cpu_hotplug) {
-               err = apply_microcode_on_cpu(cpu);
-               if (err)
-                       microcode_fini_cpu(cpu);
-       }
-       if (!uci->valid)
-               memset(uci, 0, sizeof(*uci));
+       memset(uci, 0, sizeof(*uci));
 
        err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
        if (err)
                return err;
 
-       if (!uci->valid)
-               microcode_init_cpu(cpu);
+       microcode_init_cpu(cpu, resume);
 
        return 0;
 }
 
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+       return __mc_sysdev_add(sys_dev, 0);
+}
+
 static int mc_sysdev_remove(struct sys_device *sys_dev)
 {
        int cpu = sys_dev->id;
 
        if (!cpu_online(cpu))
                return 0;
+
        pr_debug("Microcode:CPU %d removed\n", cpu);
-       /* If suspend_cpu_hotplug is set, the system is suspending and we should
-        * keep the microcode in memory for the resume.
-        */
-       if (!suspend_cpu_hotplug)
-               microcode_fini_cpu(cpu);
+       microcode_fini_cpu(cpu);
        sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
        return 0;
 }
@@ -774,13 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 
        sys_dev = get_cpu_sysdev(cpu);
        switch (action) {
+       case CPU_UP_CANCELED_FROZEN:
+               /* The CPU refused to come up during a system resume */
+               microcode_fini_cpu(cpu);
+               break;
        case CPU_ONLINE:
        case CPU_DOWN_FAILED:
                mc_sysdev_add(sys_dev);
                break;
+       case CPU_ONLINE_FROZEN:
+               /* System-wide resume is in progress, try to apply microcode */
+               if (apply_microcode_check_cpu(cpu)) {
+                       /* The application of microcode failed */
+                       microcode_fini_cpu(cpu);
+                       __mc_sysdev_add(sys_dev, 1);
+                       break;
+               }
+       case CPU_DOWN_FAILED_FROZEN:
+               if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+                       printk(KERN_ERR "Microcode: Failed to create the sysfs "
+                               "group for CPU%d\n", cpu);
+               break;
        case CPU_DOWN_PREPARE:
                mc_sysdev_remove(sys_dev);
                break;
+       case CPU_DOWN_PREPARE_FROZEN:
+               /* Suspend is in progress, only remove the interface */
+               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+               break;
        }
        return NOTIFY_OK;
 }
index 8cd0a91ce107c84aa525a11fc90331a40cbe7d34..0c1069b8d638031571618701a6f2e09044fd4b59 100644 (file)
@@ -153,9 +153,11 @@ static int msr_class_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                msr_device_create(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
                break;
        }
index 5c10f376bce1e36b437c6a76ba28e5a6c4eb0026..faab09abca5e33a3bb1cff6b50848a788bc20349 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/efi.h>
 #include <linux/bcd.h>
-#include <linux/start_kernel.h>
 #include <linux/highmem.h>
 
 #include <asm/bug.h>
index 0772678ceecf376753f834753441821c83ca3d53..bf6adce52267c2b94d2c4dac064f508a43c6492b 100644 (file)
@@ -320,3 +320,6 @@ ENTRY(sys_call_table)
        .long sys_getcpu
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
+       .long sys_signalfd
+       .long sys_timerfd
+       .long sys_eventfd
index 4bec0cbf407ae4f6e0f0d158578e28bad9e1ee77..c05e7e861b29404e9c226d05a33d2c712e5a13ee 100644 (file)
@@ -305,7 +305,7 @@ void show_registers(struct pt_regs *regs)
               regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
        printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
                TASK_COMM_LEN, current->comm, current->pid,
-               current_thread_info(), current, current->thread_info);
+               current_thread_info(), current, task_thread_info(current));
        /*
         * When in-kernel, we also print out the stack and code at the
         * time of the fault..
index 23e8614edeee42e10728364f386a49976ced06ff..80bec6640230c9df5e4e9264c055685728004123 100644 (file)
@@ -78,12 +78,6 @@ SECTIONS
        CONSTRUCTORS
        } :data
 
-  .paravirtprobe : AT(ADDR(.paravirtprobe) - LOAD_OFFSET) {
-       __start_paravirtprobe = .;
-       *(.paravirtprobe)
-       __stop_paravirtprobe = .;
-  }
-
   . = ALIGN(4096);
   .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
        __nosave_begin = .;
index a7b3999bb37a8e4ab63b8f189de86e2619ee89fb..74f3da634423e36dbcbea79f04e4d236a4802132 100644 (file)
@@ -119,9 +119,7 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        return 0;       
 }
 
-#ifdef CONFIG_SMP
 int hard_smp_processor_id(void)
 {
        return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID));
 }
-#endif
index 8fe7e4593d5fe7aca75b81d35bbb70863427bcb2..9b77b39b71a6dde7a2f4e17aa39af680a13e27ff 100644 (file)
@@ -292,8 +292,8 @@ machine_emergency_restart(void)
 void
 mca_nmi_hook(void)
 {
-       __u8 dumpval __attribute__((unused)) = inb(0xf823);
-       __u8 swnmi __attribute__((unused)) = inb(0xf813);
+       __u8 dumpval __maybe_unused = inb(0xf823);
+       __u8 swnmi __maybe_unused = inb(0xf813);
 
        /* FIXME: assume dump switch pressed */
        /* check to see if the dump switch was pressed */
index 1cf11af96de25341d919e59c83138525aa202380..3de9f9ba2da6aed8be73921f3f416ed8af444a49 100644 (file)
@@ -6,7 +6,7 @@
    in the right sequence from here. */
 static __init int pci_access_init(void)
 {
-       int type __attribute__((unused)) = 0;
+       int type __maybe_unused = 0;
 
 #ifdef CONFIG_PCI_DIRECT
        type = pci_direct_probe();
index e23af4b6ae8c173ee20b456805bd556ac86a83fb..6e41471449c034f0cd32265590608fcfe68b604c 100644 (file)
@@ -468,7 +468,7 @@ config KEXEC
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
+         but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
          The name comes from the similiarity to the exec system call.
index 687e5fdc968377fcead5c80c909f9f7aa8e02f5b..99b665e2b1d569b1e2b622c0be300be3bd3edd1b 100644 (file)
@@ -52,43 +52,6 @@ ENTRY(ia32_clone)
        br.ret.sptk.many rp
 END(ia32_clone)
 
-ENTRY(sys32_rt_sigsuspend)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-       alloc loc1=ar.pfs,8,2,3,0               // preserve all eight input regs
-       mov loc0=rp
-       mov out0=in0                            // mask
-       mov out1=in1                            // sigsetsize
-       mov out2=sp                             // out2 = &sigscratch
-       .fframe 16
-       adds sp=-16,sp                          // allocate dummy "sigscratch"
-       ;;
-       .body
-       br.call.sptk.many rp=ia32_rt_sigsuspend
-1:     .restore sp
-       adds sp=16,sp
-       mov rp=loc0
-       mov ar.pfs=loc1
-       br.ret.sptk.many rp
-END(sys32_rt_sigsuspend)
-
-ENTRY(sys32_sigsuspend)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-       alloc loc1=ar.pfs,8,2,3,0               // preserve all eight input regs
-       mov loc0=rp
-       mov out0=in2                            // mask (first two args are ignored)
-       ;;
-       mov out1=sp                             // out1 = &sigscratch
-       .fframe 16
-       adds sp=-16,sp                          // allocate dummy "sigscratch"
-       .body
-       br.call.sptk.many rp=ia32_sigsuspend
-1:     .restore sp
-       adds sp=16,sp
-       mov rp=loc0
-       mov ar.pfs=loc1
-       br.ret.sptk.many rp
-END(sys32_sigsuspend)
-
 GLOBAL_ENTRY(ia32_ret_from_clone)
        PT_REGS_UNWIND_INFO(0)
 {      /*
@@ -389,7 +352,7 @@ ia32_syscall_table:
        data8 sys_rt_sigpending
        data8 compat_sys_rt_sigtimedwait
        data8 sys32_rt_sigqueueinfo
-       data8 sys32_rt_sigsuspend
+       data8 compat_sys_rt_sigsuspend
        data8 sys32_pread         /* 180 */
        data8 sys32_pwrite
        data8 sys_chown /* 16-bit version */
index 10510e5852048011e3d3892cf274cc8e42912f5a..85e82f32e480c4707de98d4fcdb73e801f2ebc95 100644 (file)
@@ -451,59 +451,20 @@ sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int r
                sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler);
 }
 
-long
-__ia32_rt_sigsuspend (compat_sigset_t *sset, unsigned int sigsetsize, struct sigscratch *scr)
+asmlinkage long
+sys32_sigsuspend (int history0, int history1, old_sigset_t mask)
 {
-       extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall);
-       sigset_t oldset, set;
-
-       scr->scratch_unat = 0;  /* avoid leaking kernel bits to user level */
-       memset(&set, 0, sizeof(set));
-
-       memcpy(&set.sig, &sset->sig, sigsetsize);
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-
+       mask &= _BLOCKABLE;
        spin_lock_irq(&current->sighand->siglock);
-       {
-               oldset = current->blocked;
-               current->blocked = set;
-               recalc_sigpending();
-       }
+       current->saved_sigmask = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
-       /*
-        * The return below usually returns to the signal handler.  We need to pre-set the
-        * correct error code here to ensure that the right values get saved in sigcontext
-        * by ia64_do_signal.
-        */
-       scr->pt.r8 = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (ia64_do_signal(&oldset, scr, 1))
-                       return -EINTR;
-       }
-}
-
-asmlinkage long
-ia32_rt_sigsuspend (compat_sigset_t __user *uset, unsigned int sigsetsize, struct sigscratch *scr)
-{
-       compat_sigset_t set;
-
-       if (sigsetsize > sizeof(compat_sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&set.sig, &uset->sig, sigsetsize))
-               return -EFAULT;
-
-       return __ia32_rt_sigsuspend(&set, sigsetsize, scr);
-}
-
-asmlinkage long
-ia32_sigsuspend (unsigned int mask, struct sigscratch *scr)
-{
-       return __ia32_rt_sigsuspend((compat_sigset_t *) &mask, sizeof(mask), scr);
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+       return -ERESTARTNOHAND;
 }
 
 asmlinkage long
@@ -810,7 +771,11 @@ get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
        }
        /* Legacy stack switching not supported */
 
-       return (void __user *)((esp - frame_size) & -8ul);
+       esp -= frame_size;
+       /* Align the stack pointer according to the i386 ABI,
+        * i.e. so that on function entry ((sp + 4) & 15) == 0. */
+       esp = ((esp + 4) & -16ul) - 4;
+       return (void __user *) esp;
 }
 
 static int
index 55fd2d5471e127df16d9edb7a54b161bb4255767..b50bf208678ea6c981f3e1b4e439b69e80887e4f 100644 (file)
@@ -1199,32 +1199,6 @@ ENTRY(notify_resume_user)
        br.ret.sptk.many rp
 END(notify_resume_user)
 
-GLOBAL_ENTRY(sys_rt_sigsuspend)
-       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-       alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
-       mov r9=ar.unat
-       mov loc0=rp                             // save return address
-       mov out0=in0                            // mask
-       mov out1=in1                            // sigsetsize
-       adds out2=8,sp                          // out2=&sigscratch->ar_pfs
-       ;;
-       .fframe 16
-       .spillsp ar.unat, 16
-       st8 [sp]=r9,-16                         // allocate space for ar.unat and save it
-       st8 [out2]=loc1,-8                      // save ar.pfs, out2=&sigscratch
-       .body
-       br.call.sptk.many rp=ia64_rt_sigsuspend
-.ret17:        .restore sp
-       adds sp=16,sp                           // pop scratch stack space
-       ;;
-       ld8 r9=[sp]                             // load new unat from sw->caller_unat
-       mov rp=loc0
-       ;;
-       mov ar.unat=r9
-       mov ar.pfs=loc1
-       br.ret.sptk.many rp
-END(sys_rt_sigsuspend)
-
 ENTRY(sys_rt_sigreturn)
        PT_REGS_UNWIND_INFO(0)
        /*
@@ -1598,8 +1572,8 @@ sys_call_table:
        data8 sys_readlinkat
        data8 sys_fchmodat
        data8 sys_faccessat
-       data8 sys_ni_syscall                    // reserved for pselect
-       data8 sys_ni_syscall                    // 1295 reserved for ppoll
+       data8 sys_pselect6
+       data8 sys_ppoll
        data8 sys_unshare
        data8 sys_splice
        data8 sys_set_robust_list
index d3e9f33e8bddcc816d2a213fb7361e9b1fad7ce8..6a49600cf337f5e468e857ccce5088f12917bfe8 100644 (file)
@@ -236,9 +236,11 @@ static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
        sys_dev = get_cpu_sysdev(cpu);
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                err_inject_add_dev(sys_dev);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                err_inject_remove_dev(sys_dev);
                break;
        }
index 93d9ab14ba24fa7bd64acd1a3888d5654c490df1..37f46527d233eef451ead5c8b6adcc2b24e33ca9 100644 (file)
@@ -1012,7 +1012,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 /*
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
  */
-void __init
+void __devinit
 iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                          unsigned long polarity,
                          unsigned long trigger)
index 1c5044a809584b592ac5b069f7cc69fa0eead7e1..bc47049f060f6348e5bb0a19874d89da86b131f6 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/machvec.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
 
 #ifdef CONFIG_PERFMON
 # include <asm/perfmon.h>
@@ -126,8 +127,10 @@ void destroy_irq(unsigned int irq)
 
 #ifdef CONFIG_SMP
 #      define IS_RESCHEDULE(vec)       (vec == IA64_IPI_RESCHEDULE)
+#      define IS_LOCAL_TLB_FLUSH(vec)  (vec == IA64_IPI_LOCAL_TLB_FLUSH)
 #else
 #      define IS_RESCHEDULE(vec)       (0)
+#      define IS_LOCAL_TLB_FLUSH(vec)  (0)
 #endif
 /*
  * That's where the IVT branches when we get an external
@@ -179,8 +182,11 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
        saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
        ia64_srlz_d();
        while (vector != IA64_SPURIOUS_INT_VECTOR) {
-               if (unlikely(IS_RESCHEDULE(vector)))
-                        kstat_this_cpu.irqs[vector]++;
+               if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
+                       smp_local_flush_tlb();
+                       kstat_this_cpu.irqs[vector]++;
+               } else if (unlikely(IS_RESCHEDULE(vector)))
+                       kstat_this_cpu.irqs[vector]++;
                else {
                        ia64_setreg(_IA64_REG_CR_TPR, vector);
                        ia64_srlz_d();
@@ -226,8 +232,11 @@ void ia64_process_pending_intr(void)
          * Perform normal interrupt style processing
          */
        while (vector != IA64_SPURIOUS_INT_VECTOR) {
-               if (unlikely(IS_RESCHEDULE(vector)))
-                        kstat_this_cpu.irqs[vector]++;
+               if (unlikely(IS_LOCAL_TLB_FLUSH(vector))) {
+                       smp_local_flush_tlb();
+                       kstat_this_cpu.irqs[vector]++;
+               } else if (unlikely(IS_RESCHEDULE(vector)))
+                       kstat_this_cpu.irqs[vector]++;
                else {
                        struct pt_regs *old_regs = set_irq_regs(NULL);
 
@@ -259,12 +268,12 @@ void ia64_process_pending_intr(void)
 
 
 #ifdef CONFIG_SMP
-extern irqreturn_t handle_IPI (int irq, void *dev_id);
 
 static irqreturn_t dummy_handler (int irq, void *dev_id)
 {
        BUG();
 }
+extern irqreturn_t handle_IPI (int irq, void *dev_id);
 
 static struct irqaction ipi_irqaction = {
        .handler =      handle_IPI,
@@ -277,6 +286,13 @@ static struct irqaction resched_irqaction = {
        .flags =        IRQF_DISABLED,
        .name =         "resched"
 };
+
+static struct irqaction tlb_irqaction = {
+       .handler =      dummy_handler,
+       .flags =        IRQF_DISABLED,
+       .name =         "tlb_flush"
+};
+
 #endif
 
 void
@@ -302,6 +318,7 @@ init_IRQ (void)
 #ifdef CONFIG_SMP
        register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
        register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
+       register_percpu_irq(IA64_IPI_LOCAL_TLB_FLUSH, &tlb_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
        pfm_init_percpu();
index 1d7cc7e2ce32f28b5f30c2c68a6246bc8d3317c7..f8ae709de0b5341e48abaaf13ac1bd011dd98ee0 100644 (file)
@@ -1689,7 +1689,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset,
        ti->preempt_count = 1;
        ti->task = p;
        ti->cpu = cpu;
-       p->thread_info = ti;
+       p->stack = ti;
        p->state = TASK_UNINTERRUPTIBLE;
        cpu_set(cpu, p->cpus_allowed);
        INIT_LIST_HEAD(&p->tasks);
index a71df9ae03976ccbba7eb5154a639e941938ca44..85829e27785c74912a04a153b163674f38549de0 100644 (file)
@@ -975,9 +975,11 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                create_palinfo_proc_entries(hotcpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                remove_palinfo_proc_entries(hotcpu);
                break;
        }
index 8bb571a8a73840447a23531c49cccb4602008c5c..d1c3ed9943e52d8ccad85553e1d1008ae7dc3629 100644 (file)
@@ -155,7 +155,7 @@ show_regs (struct pt_regs *regs)
 }
 
 void
-do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
+do_notify_resume_user (sigset_t *unused, struct sigscratch *scr, long in_syscall)
 {
        if (fsys_mode(current, &scr->pt)) {
                /* defer signal-handling etc. until we return to privilege-level 0.  */
@@ -170,8 +170,8 @@ do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall
 #endif
 
        /* deal with pending signal delivery */
-       if (test_thread_flag(TIF_SIGPENDING))
-               ia64_do_signal(oldset, scr, in_syscall);
+       if (test_thread_flag(TIF_SIGPENDING)||test_thread_flag(TIF_RESTORE_SIGMASK))
+               ia64_do_signal(scr, in_syscall);
 }
 
 static int pal_halt        = 1;
@@ -236,6 +236,7 @@ void cpu_idle_wait(void)
 {
        unsigned int cpu, this_cpu = get_cpu();
        cpumask_t map;
+       cpumask_t tmp = current->cpus_allowed;
 
        set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
        put_cpu();
@@ -257,6 +258,7 @@ void cpu_idle_wait(void)
                }
                cpus_and(map, map, cpu_online_map);
        } while (!cpus_empty(map));
+       set_cpus_allowed(current, tmp);
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
index ae473e3f2a0d55a772444da79ca2766235fa6033..903babd22d623293a8a160b6a308d9614707a4b3 100644 (file)
@@ -94,7 +94,7 @@ GLOBAL_ENTRY(relocate_new_kernel)
 4:
         srlz.i
         ;;
-       //purge TR entry for kernel text and data
+       // purge TR entry for kernel text and data
         movl r16=KERNEL_START
         mov r18=KERNEL_TR_PAGE_SHIFT<<2
         ;;
@@ -104,15 +104,6 @@ GLOBAL_ENTRY(relocate_new_kernel)
         srlz.i
         ;;
 
-       // purge TR entry for percpu data
-        movl r16=PERCPU_ADDR
-        mov r18=PERCPU_PAGE_SHIFT<<2
-        ;;
-        ptr.d r16,r18
-        ;;
-        srlz.d
-       ;;
-
         // purge TR entry for pal code
         mov r16=in3
         mov r18=IA64_GRANULE_SHIFT<<2
index a51f1d0bfb707c392385eed759ecf7b4d0300b6a..89f6b138a62cc2c7f82f7c0fed22c7fbafcc065a 100644 (file)
@@ -582,6 +582,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
        struct salinfo_data *data;
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                spin_lock_irqsave(&data_saved_lock, flags);
                for (i = 0, data = salinfo_data;
                     i < ARRAY_SIZE(salinfo_data);
@@ -592,6 +593,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
                spin_unlock_irqrestore(&data_saved_lock, flags);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                spin_lock_irqsave(&data_saved_lock, flags);
                for (i = 0, data = salinfo_data;
                     i < ARRAY_SIZE(salinfo_data);
index 6e19da122ae3a75952513aaa49166f511440c2ac..9df1efe7487d8ae5d23826db03f59958aa4e0d30 100644 (file)
@@ -786,7 +786,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
        c->unimpl_pa_mask = ~((1L<<63) | ((1L << phys_addr_size) - 1));
 }
 
-void
+void __init
 setup_per_cpu_areas (void)
 {
        /* start_kernel() requires this... */
index 37b986cb86e0e3e57c64ce9d0b5fb6803658d790..9fd9a1933b3dc784df6dff6b837a7081a21096cd 100644 (file)
@@ -22,4 +22,4 @@ struct sigframe {
        struct sigcontext sc;
 };
 
-extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);
+extern void ia64_do_signal (struct sigscratch *, long);
index 0dcd56da600181937e8670f1fc6cedc468d650f9..aeec8184e862535e6676b2cafae699f502fa56f0 100644 (file)
 # define GET_SIGSET(k,u)       __get_user((k)->sig[0], &(u)->sig[0])
 #endif
 
-long
-ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch *scr)
-{
-       sigset_t oldset, set;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (!access_ok(VERIFY_READ, uset, sigsetsize))
-               return -EFAULT;
-
-       if (GET_SIGSET(&set, uset))
-               return -EFAULT;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       {
-               oldset = current->blocked;
-               current->blocked = set;
-               recalc_sigpending();
-       }
-       spin_unlock_irq(&current->sighand->siglock);
-
-       /*
-        * The return below usually returns to the signal handler.  We need to
-        * pre-set the correct error code here to ensure that the right values
-        * get saved in sigcontext by ia64_do_signal.
-        */
-       scr->pt.r8 = EINTR;
-       scr->pt.r10 = -1;
-
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (ia64_do_signal(&oldset, scr, 1))
-                       return -EINTR;
-       }
-}
-
 asmlinkage long
 sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2,
                 long arg3, long arg4, long arg5, long arg6, long arg7,
@@ -477,10 +436,11 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
  * Note that `init' is a special process: it doesn't get signals it doesn't want to
  * handle.  Thus you cannot kill init even with a SIGKILL even by mistake.
  */
-long
-ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
+void
+ia64_do_signal (struct sigscratch *scr, long in_syscall)
 {
        struct k_sigaction ka;
+       sigset_t *oldset;
        siginfo_t info;
        long restart = in_syscall;
        long errno = scr->pt.r8;
@@ -492,9 +452,11 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
         * doing anything if so.
         */
        if (!user_mode(&scr->pt))
-               return 0;
+               return;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        /*
@@ -557,8 +519,15 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
                 * Whee!  Actually deliver the signal.  If the delivery failed, we need to
                 * continue to iterate in this loop so we can deliver the SIGSEGV...
                 */
-               if (handle_signal(signr, &ka, &info, oldset, scr))
-                       return 1;
+               if (handle_signal(signr, &ka, &info, oldset, scr)) {
+                       /* a signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TIF_RESTORE_SIGMASK flag */
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+                       return;
+               }
        }
 
        /* Did we come from a system call? */
@@ -584,5 +553,11 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
                        }
                }
        }
-       return 0;
+
+       /* if there's no signal to deliver, we just put the saved sigmask
+        * back */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
 }
index 55ddd809b02d47aa72fc7b1f251c851aeffddc40..221de38045604ef1f791a015f61e2a399ca00a89 100644 (file)
 #include <asm/unistd.h>
 #include <asm/mca.h>
 
+/*
+ * Note: alignment of 4 entries/cacheline was empirically determined
+ * to be a good tradeoff between hot cachelines & spreading the array
+ * across too many cacheline.
+ */
+static struct local_tlb_flush_counts {
+       unsigned int count;
+} __attribute__((__aligned__(32))) local_tlb_flush_counts[NR_CPUS];
+
+static DEFINE_PER_CPU(unsigned int, shadow_flush_counts[NR_CPUS]) ____cacheline_aligned;
+
+
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
  * requirements. It also looks cleaner.
@@ -248,6 +260,62 @@ smp_send_reschedule (int cpu)
        platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
 }
 
+/*
+ * Called with preeemption disabled.
+ */
+static void
+smp_send_local_flush_tlb (int cpu)
+{
+       platform_send_ipi(cpu, IA64_IPI_LOCAL_TLB_FLUSH, IA64_IPI_DM_INT, 0);
+}
+
+void
+smp_local_flush_tlb(void)
+{
+       /*
+        * Use atomic ops. Otherwise, the load/increment/store sequence from
+        * a "++" operation can have the line stolen between the load & store.
+        * The overhead of the atomic op in negligible in this case & offers
+        * significant benefit for the brief periods where lots of cpus
+        * are simultaneously flushing TLBs.
+        */
+       ia64_fetchadd(1, &local_tlb_flush_counts[smp_processor_id()].count, acq);
+       local_flush_tlb_all();
+}
+
+#define FLUSH_DELAY    5 /* Usec backoff to eliminate excessive cacheline bouncing */
+
+void
+smp_flush_tlb_cpumask(cpumask_t xcpumask)
+{
+       unsigned int *counts = __ia64_per_cpu_var(shadow_flush_counts);
+       cpumask_t cpumask = xcpumask;
+       int mycpu, cpu, flush_mycpu = 0;
+
+       preempt_disable();
+       mycpu = smp_processor_id();
+
+       for_each_cpu_mask(cpu, cpumask)
+               counts[cpu] = local_tlb_flush_counts[cpu].count;
+
+       mb();
+       for_each_cpu_mask(cpu, cpumask) {
+               if (cpu == mycpu)
+                       flush_mycpu = 1;
+               else
+                       smp_send_local_flush_tlb(cpu);
+       }
+
+       if (flush_mycpu)
+               smp_local_flush_tlb();
+
+       for_each_cpu_mask(cpu, cpumask)
+               while(counts[cpu] == local_tlb_flush_counts[cpu].count)
+                       udelay(FLUSH_DELAY);
+
+       preempt_enable();
+}
+
 void
 smp_flush_tlb_all (void)
 {
index 687500ddb4b872a59676396dd04cbed4c7a214ef..94ae3c87d828c5d251d78eceff617d4dc08494e0 100644 (file)
@@ -412,9 +412,11 @@ static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
        sys_dev = get_cpu_sysdev(cpu);
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cache_add_dev(sys_dev);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                cache_remove_dev(sys_dev);
                break;
        }
index 5bfb8be02b702cd018e91fcce985970f9b7dab40..b8e0d70bf9893f21451d7baad5f6dfd033bac527 100644 (file)
@@ -43,9 +43,9 @@ die (const char *str, struct pt_regs *regs, long err)
                u32 lock_owner;
                int lock_owner_depth;
        } die = {
-               .lock =                 SPIN_LOCK_UNLOCKED,
-               .lock_owner =           -1,
-               .lock_owner_depth =     0
+               .lock = __SPIN_LOCK_UNLOCKED(die.lock),
+               .lock_owner = -1,
+               .lock_owner_depth = 0
        };
        static int die_counter;
        int cpu = get_cpu();
index 93d5a3b41f69e9e0bb2efb32c982e6113edbc809..fe1426266b9bf3092191c83183e174e746a58684 100644 (file)
@@ -60,6 +60,7 @@
 #  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__)
+#  undef inline
 #  define inline
 #else /* !UNW_DEBUG */
 #  define UNW_DEBUG_ON(n)  0
@@ -145,7 +146,7 @@ static struct {
 # endif
 } unw = {
        .tables = &unw.kernel_table,
-       .lock = SPIN_LOCK_UNLOCKED,
+       .lock = __SPIN_LOCK_UNLOCKED(unw.lock),
        .save_order = {
                UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
                UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
@@ -1943,9 +1944,9 @@ EXPORT_SYMBOL(unw_unwind);
 int
 unw_unwind_to_user (struct unw_frame_info *info)
 {
-       unsigned long ip, sp, pr = 0;
+       unsigned long ip, sp, pr = info->pr;
 
-       while (unw_unwind(info) >= 0) {
+       do {
                unw_get_sp(info, &sp);
                if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)
                    < IA64_PT_REGS_SIZE) {
@@ -1963,7 +1964,7 @@ unw_unwind_to_user (struct unw_frame_info *info)
                                __FUNCTION__, ip);
                        return -1;
                }
-       }
+       } while (unw_unwind(info) >= 0);
        unw_get_ip(info, &ip);
        UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",
                   __FUNCTION__, ip);
index ffad7624436c84e02e62b7e38b72066bc689492f..fa4e6d4810f3cc2c1c8e6c74fd431e79fe53a350 100644 (file)
@@ -32,9 +32,9 @@ static struct {
 } purge;
 
 struct ia64_ctx ia64_ctx = {
-       .lock =         SPIN_LOCK_UNLOCKED,
-       .next =         1,
-       .max_ctx =      ~0U
+       .lock = __SPIN_LOCK_UNLOCKED(ia64_ctx.lock),
+       .next = 1,
+       .max_ctx = ~0U
 };
 
 DEFINE_PER_CPU(u8, ia64_need_tlb_flush);
index 8d2a1bfbfe7c03f4d4b7e687fbf1a978d5dd1c71..7f6d2360a2620f66f96487c4b37898f9a2dac13e 100644 (file)
@@ -59,6 +59,22 @@ void sn_intr_free(nasid_t local_nasid, int local_widget,
                        (u64) sn_irq_info->irq_cookie, 0, 0);
 }
 
+u64 sn_intr_redirect(nasid_t local_nasid, int local_widget,
+                     struct sn_irq_info *sn_irq_info,
+                     nasid_t req_nasid, int req_slice)
+{
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
+                       (u64) SAL_INTR_REDIRECT, (u64) local_nasid,
+                       (u64) local_widget, __pa(sn_irq_info),
+                       (u64) req_nasid, (u64) req_slice, 0);
+
+       return ret_stuff.status;
+}
+
 static unsigned int sn_startup_irq(unsigned int irq)
 {
        return 0;
@@ -127,15 +143,8 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
        struct sn_irq_info *new_irq_info;
        struct sn_pcibus_provider *pci_provider;
 
-       new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
-       if (new_irq_info == NULL)
-               return NULL;
-
-       memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
-
-       bridge = (u64) new_irq_info->irq_bridge;
+       bridge = (u64) sn_irq_info->irq_bridge;
        if (!bridge) {
-               kfree(new_irq_info);
                return NULL; /* irq is not a device interrupt */
        }
 
@@ -145,8 +154,25 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
                local_widget = TIO_SWIN_WIDGETNUM(bridge);
        else
                local_widget = SWIN_WIDGETNUM(bridge);
-
        vector = sn_irq_info->irq_irq;
+
+       /* Make use of SAL_INTR_REDIRECT if PROM supports it */
+       status = sn_intr_redirect(local_nasid, local_widget, sn_irq_info, nasid, slice);
+       if (!status) {
+               new_irq_info = sn_irq_info;
+               goto finish_up;
+       }
+
+       /*
+        * PROM does not support SAL_INTR_REDIRECT, or it failed.
+        * Revert to old method.
+        */
+       new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+       if (new_irq_info == NULL)
+               return NULL;
+
+       memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
        /* Free the old PROM new_irq_info structure */
        sn_intr_free(local_nasid, local_widget, new_irq_info);
        unregister_intr_pda(new_irq_info);
@@ -162,11 +188,18 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
                return NULL;
        }
 
+       register_intr_pda(new_irq_info);
+       spin_lock(&sn_irq_info_lock);
+       list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+       spin_unlock(&sn_irq_info_lock);
+       call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+
+
+finish_up:
        /* Update kernels new_irq_info with new target info */
        cpuid = nasid_slice_to_cpuid(new_irq_info->irq_nasid,
                                     new_irq_info->irq_slice);
        new_irq_info->irq_cpuid = cpuid;
-       register_intr_pda(new_irq_info);
 
        pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
 
@@ -178,11 +211,6 @@ struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
            pci_provider && pci_provider->target_interrupt)
                (pci_provider->target_interrupt)(new_irq_info);
 
-       spin_lock(&sn_irq_info_lock);
-       list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
-       spin_unlock(&sn_irq_info_lock);
-       call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
-
 #ifdef CONFIG_SMP
        cpuphys = cpu_physical_id(cpuid);
        set_irq_affinity_info((vector & 0xff), cpuphys, 0);
index 601747b1e22aa82c54dba040f6cb31034436facf..5d318b579fb1b01b3fb4f89c95c849a31d2939aa 100644 (file)
@@ -46,6 +46,9 @@ DECLARE_PER_CPU(struct ptc_stats, ptcstats);
 
 static  __cacheline_aligned DEFINE_SPINLOCK(sn2_global_ptc_lock);
 
+/* 0 = old algorithm (no IPI flushes), 1 = ipi deadlock flush, 2 = ipi instead of SHUB ptc, >2 = always ipi */
+static int sn2_flush_opt = 0;
+
 extern unsigned long
 sn2_ptc_deadlock_recovery_core(volatile unsigned long *, unsigned long,
                               volatile unsigned long *, unsigned long,
@@ -76,6 +79,8 @@ struct ptc_stats {
        unsigned long shub_itc_clocks;
        unsigned long shub_itc_clocks_max;
        unsigned long shub_ptc_flushes_not_my_mm;
+       unsigned long shub_ipi_flushes;
+       unsigned long shub_ipi_flushes_itc_clocks;
 };
 
 #define sn2_ptctest    0
@@ -121,6 +126,18 @@ void sn_tlb_migrate_finish(struct mm_struct *mm)
                flush_tlb_mm(mm);
 }
 
+static void
+sn2_ipi_flush_all_tlb(struct mm_struct *mm)
+{
+       unsigned long itc;
+
+       itc = ia64_get_itc();
+       smp_flush_tlb_cpumask(mm->cpu_vm_mask);
+       itc = ia64_get_itc() - itc;
+       __get_cpu_var(ptcstats).shub_ipi_flushes_itc_clocks += itc;
+       __get_cpu_var(ptcstats).shub_ipi_flushes++;
+}
+
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
  * @mm: mm_struct containing virtual address range
@@ -154,7 +171,12 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
        unsigned long itc, itc2, flags, data0 = 0, data1 = 0, rr_value, old_rr = 0;
        short nasids[MAX_NUMNODES], nix;
        nodemask_t nodes_flushed;
-       int active, max_active, deadlock;
+       int active, max_active, deadlock, flush_opt = sn2_flush_opt;
+
+       if (flush_opt > 2) {
+               sn2_ipi_flush_all_tlb(mm);
+               return;
+       }
 
        nodes_clear(nodes_flushed);
        i = 0;
@@ -189,6 +211,12 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
                return;
        }
 
+       if (flush_opt == 2) {
+               sn2_ipi_flush_all_tlb(mm);
+               preempt_enable();
+               return;
+       }
+
        itc = ia64_get_itc();
        nix = 0;
        for_each_node_mask(cnode, nodes_flushed)
@@ -256,6 +284,8 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
                        }
                        if (active >= max_active || i == (nix - 1)) {
                                if ((deadlock = wait_piowc())) {
+                                       if (flush_opt == 1)
+                                               goto done;
                                        sn2_ptc_deadlock_recovery(nasids, ibegin, i, mynasid, ptc0, data0, ptc1, data1);
                                        if (reset_max_active_on_deadlock())
                                                max_active = 1;
@@ -267,6 +297,7 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
                start += (1UL << nbits);
        } while (start < end);
 
+done:
        itc2 = ia64_get_itc() - itc2;
        __get_cpu_var(ptcstats).shub_itc_clocks += itc2;
        if (itc2 > __get_cpu_var(ptcstats).shub_itc_clocks_max)
@@ -279,6 +310,11 @@ sn2_global_tlb_purge(struct mm_struct *mm, unsigned long start,
 
        spin_unlock_irqrestore(PTC_LOCK(shub1), flags);
 
+       if (flush_opt == 1 && deadlock) {
+               __get_cpu_var(ptcstats).deadlocks++;
+               sn2_ipi_flush_all_tlb(mm);
+       }
+
        preempt_enable();
 }
 
@@ -425,24 +461,42 @@ static int sn2_ptc_seq_show(struct seq_file *file, void *data)
 
        if (!cpu) {
                seq_printf(file,
-                          "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2\n");
-               seq_printf(file, "# ptctest %d\n", sn2_ptctest);
+                          "# cpu ptc_l newrid ptc_flushes nodes_flushed deadlocks lock_nsec shub_nsec shub_nsec_max not_my_mm deadlock2 ipi_fluches ipi_nsec\n");
+               seq_printf(file, "# ptctest %d, flushopt %d\n", sn2_ptctest, sn2_flush_opt);
        }
 
        if (cpu < NR_CPUS && cpu_online(cpu)) {
                stat = &per_cpu(ptcstats, cpu);
-               seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
+               seq_printf(file, "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", cpu, stat->ptc_l,
                                stat->change_rid, stat->shub_ptc_flushes, stat->nodes_flushed,
                                stat->deadlocks,
                                1000 * stat->lock_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
                                1000 * stat->shub_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec,
                                1000 * stat->shub_itc_clocks_max / per_cpu(cpu_info, cpu).cyc_per_usec,
                                stat->shub_ptc_flushes_not_my_mm,
-                               stat->deadlocks2);
+                               stat->deadlocks2,
+                               stat->shub_ipi_flushes,
+                               1000 * stat->shub_ipi_flushes_itc_clocks / per_cpu(cpu_info, cpu).cyc_per_usec);
        }
        return 0;
 }
 
+static ssize_t sn2_ptc_proc_write(struct file *file, const char __user *user, size_t count, loff_t *data)
+{
+       int cpu;
+       char optstr[64];
+
+       if (copy_from_user(optstr, user, count))
+               return -EFAULT;
+       optstr[count - 1] = '\0';
+       sn2_flush_opt = simple_strtoul(optstr, NULL, 0);
+
+       for_each_online_cpu(cpu)
+               memset(&per_cpu(ptcstats, cpu), 0, sizeof(struct ptc_stats));
+
+       return count;
+}
+
 static struct seq_operations sn2_ptc_seq_ops = {
        .start = sn2_ptc_seq_start,
        .next = sn2_ptc_seq_next,
@@ -458,6 +512,7 @@ static int sn2_ptc_proc_open(struct inode *inode, struct file *file)
 static const struct file_operations proc_sn2_ptc_operations = {
        .open = sn2_ptc_proc_open,
        .read = seq_read,
+       .write = sn2_ptc_proc_write,
        .llseek = seq_lseek,
        .release = seq_release,
 };
index 9740d6b8ae11c407ae56d4c88bf6b179056deceb..c3bb8a755b00a3f13cdfc891a2b42ddbe0d63b63 100644 (file)
@@ -241,6 +241,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+        bool
+        default y
+
 config PREEMPT
        bool "Preemptible Kernel"
        help
index 8bb74b10dca76707a2d7c52e4fb3399fd3f26fbf..49a6d16a3d585d5b2a4d567ce7256162340130cc 100644 (file)
@@ -163,7 +163,8 @@ ENTRY(tme_handler)
 
        ; pte_data = (unsigned long)pte_val(*pte);
        ld      r2, @r3                 ; r2: pte data
-       or3     r2, r2, #2              ; _PAGE_PRESENT(=2)
+       and3    r3, r2, #2              ; _PAGE_PRESENT(=2) check
+       beqz    r3, 3f
 
        .fillinsn
 5:
@@ -264,11 +265,8 @@ ENTRY(tme_handler)
 ;
        and3    r1, r1, #0xeff
        ldi     r4, #611                ; _KERNPG_TABLE(=611)
-       beq     r1, r4, 4f              ; !pmd_bad(*pmd) ?
-       .fillinsn
-3:
-       ldi     r1, #0                  ; r1: pte_data = 0
-       bra     5f
+       bne     r1, r4, 3f              ; !pmd_bad(*pmd) ?
+
        .fillinsn
 4:
        ; pte = pte_offset(pmd, address);
@@ -282,8 +280,10 @@ ENTRY(tme_handler)
        add     r4, r3                  ; r4: pte
        ; pte_data = (unsigned long)pte_val(*pte);
        ld      r1, @r4                 ; r1: pte_data
-       .fillinsn
+       and3    r3, r1, #2              ; _PAGE_PRESENT(=2) check
+       beqz    r3, 3f
 
+       .fillinsn
 ;; set tlb
 ; r0: address, r1: pte_data, r2: entry
 ; r3,r4: (free)
@@ -295,8 +295,7 @@ ENTRY(tme_handler)
        and3    r4, r4, #(MMU_CONTEXT_ASID_MASK)
        or      r3, r4
        st      r3, @r2
-       or3     r4, r1, #2              ; _PAGE_PRESENT(=2)
-       st      r4, @(4,r2)             ; set_tlb_data(entry, pte_data);
+       st      r1, @(4,r2)             ; set_tlb_data(entry, pte_data);
 
        ld      r4, @sp+
        ld      r3, @sp+
@@ -306,6 +305,11 @@ ENTRY(tme_handler)
        ld      sp, @sp+
        rte
 
+       .fillinsn
+3:
+       ldi     r1, #2                  ; r1: pte_data = 0 | _PAGE_PRESENT(=2)
+       bra     5b
+
 #else
 #error unknown isa configuration
 #endif
index 763c9aa0b4fdb3c7ff4909f8f543f331cf775090..9ff47bd09aee0027362a2dbcd75194add548fab9 100644 (file)
@@ -5,7 +5,7 @@ source "lib/Kconfig.debug"
 config FULLDEBUG
        bool "Full Symbolic/Source Debugging support"
        help
-         Enable debuging symbols on kernel build.
+         Enable debugging symbols on kernel build.
 
 config HIGHPROFILE
        bool "Use fast second timer for profiling"
index b988c7bdc6e4d6fd78656b68b1e41fdea1131da0..7cd183d346ef6b06264f8f2b95a5ea154b001125 100644 (file)
@@ -31,7 +31,7 @@ int main(void)
        DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
        DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(TASK_MM, offsetof(struct task_struct, mm));
        DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
index b7cb048bc7715b02d7fd82a8788f9909887f54d7..16ecea3c08136540f0bb8cc685f39fd71c8d84a8 100644 (file)
@@ -956,7 +956,7 @@ choice
          byte order. These modes require different kernels and a different
          Linux distribution.  In general there is one preferred byteorder for a
          particular system but some systems are just as commonly used in the
-         one or the other endianess.
+         one or the other endianness.
 
 config CPU_BIG_ENDIAN
        bool "Big endian"
@@ -1750,7 +1750,7 @@ config ARCH_DISCONTIGMEM_ENABLE
        bool
        default y if SGI_IP27
        help
-         Say Y to upport efficient handling of discontiguous physical memory,
+         Say Y to support efficient handling of discontiguous physical memory,
          for architectures which are either NUMA (Non-Uniform Memory Access)
          or have huge holes in the physical address space for other reasons.
          See <file:Documentation/vm/numa> for more.
@@ -1938,7 +1938,7 @@ config KEXEC
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
+         but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
          The name comes from the similiarity to the exec system call.
index f2f742df32c7375f887e747e8272b47d12613b2a..4892db88a86a5c84f7ecc8145c8f3b2d2b8309a5 100644 (file)
@@ -92,7 +92,7 @@ cflags-y += -ffreestanding
 # when fed the toolchain default!
 #
 # Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of
-# 2006-10-10 don't properly change the the predefined symbols if -EB / -EL
+# 2006-10-10 don't properly change the predefined symbols if -EB / -EL
 # are used, so we kludge that here.  A bug has been filed at
 # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413.
 #
index 761a779d5c4f67a8620f6efe481f0c2829d002d1..3b27309d54b18542b51e601780c32fefa513901b 100644 (file)
@@ -82,7 +82,7 @@ void output_task_defines(void)
 {
        text("/* MIPS task_struct offsets. */");
        offset("#define TASK_STATE         ", struct task_struct, state);
-       offset("#define TASK_THREAD_INFO   ", struct task_struct, thread_info);
+       offset("#define TASK_THREAD_INFO   ", struct task_struct, stack);
        offset("#define TASK_FLAGS         ", struct task_struct, flags);
        offset("#define TASK_MM            ", struct task_struct, mm);
        offset("#define TASK_PID           ", struct task_struct, pid);
index 5dcfab6b288efbbca69046a3bc66970736d84cc8..b361edb83dc63e009e9a1a39281e9c132e946bfe 100644 (file)
@@ -560,7 +560,7 @@ void smtc_boot_secondary(int cpu, struct task_struct *idle)
        write_tc_gpr_sp(__KSTK_TOS(idle));
 
        /* global pointer */
-       write_tc_gpr_gp((unsigned long)idle->thread_info);
+       write_tc_gpr_gp((unsigned long)task_thread_info(idle));
 
        smtc_status |= SMTC_MTC_ACTIVE;
        write_tc_c0_tchalt(0);
index 7a7444874e80341522eb1cadd0c3b2d078d7b8d2..0ad39e53f7b1a0122d185c952fa03b5c64a99c79 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/pci.h>
 
 /*
- * Set the the BCM1250, etc. PCI host bridge's TRDY timeout
+ * Set the BCM1250, etc. PCI host bridge's TRDY timeout
  * to the finite max.
  */
 static void __init quirk_sb1250_pci(struct pci_dev *dev)
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
                        quirk_sb1250_ht);
 
 /*
- * Set the the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
+ * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
  */
 static void __init quirk_sp1011(struct pci_dev *dev)
 {
index 54fdb959149c4236f1e0a95204c1debbb94ac305..d3b7917a87cb559e68893ad40327d0ea5346a7e9 100644 (file)
@@ -54,7 +54,7 @@
 
 int main(void)
 {
-       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(TASK_STATE, offsetof(struct task_struct, state));
        DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
        DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
index 808d2ef80e2f77459760c7aa044f51e00926b4df..ccc5410af996a5cf87a45d6e2eda9a7a97f31df6 100644 (file)
@@ -120,19 +120,6 @@ config GENERIC_BUG
 config SYS_SUPPORTS_APM_EMULATION
        bool
 
-#
-# Powerpc uses the slab allocator to manage its ptes and the
-# page structs of ptes are used for splitting the page table
-# lock for configurations supporting more than SPLIT_PTLOCK_CPUS.
-#
-# In that special configuration the page structs of slabs are modified.
-# This setting disables the selection of SLUB as a slab allocator.
-#
-config ARCH_USES_SLAB_PAGE_STRUCT
-       bool
-       default y
-       depends on SPLIT_PTLOCK_CPUS <= NR_CPUS
-
 config DEFAULT_UIMAGE
        bool
        help
@@ -352,6 +339,11 @@ config PPC_STD_MMU_32
        def_bool y
        depends on PPC_STD_MMU && PPC32
 
+config PPC_MM_SLICES
+       bool
+       default y if HUGETLB_PAGE
+       default n
+
 config VIRT_CPU_ACCOUNTING
        bool "Deterministic task and CPU time accounting"
        depends on PPC64
@@ -541,9 +533,15 @@ config NODES_SPAN_OTHER_NODES
        def_bool y
        depends on NEED_MULTIPLE_NODES
 
+config PPC_HAS_HASH_64K
+       bool
+       depends on PPC64
+       default n
+
 config PPC_64K_PAGES
        bool "64k page size"
        depends on PPC64
+       select PPC_HAS_HASH_64K
        help
          This option changes the kernel logical page size to 64k. On machines
          without processor support for 64k pages, the kernel will simulate
index f70e795c262ea42bd14b52deaaba78f8ea7f59fe..346cd3befe1e2252bb0c132e20d3b9f33aefd8ad 100644 (file)
@@ -32,7 +32,7 @@ config HCALL_STATS
        depends on PPC_PSERIES && DEBUG_FS
        help
          Adds code to keep track of the number of hypervisor calls made and
-         the amount of time spent in hypervisor callsr.  Wall time spent in
+         the amount of time spent in hypervisor calls.  Wall time spent in
          each call is always calculated, and if available CPU cycles spent
          are also calculated.  A directory named hcall_inst is added at the
          root of the debugfs filesystem.  Within the hcall_inst directory
index 93b76069601049e58319b1ce3e08234263f9c6d8..112dd5198fe2d4d4406fb5e29cf6b665eda6b1d1 100644 (file)
                        interrupt-parent = < &ipic >;
                        interrupts = <42 8>;
                        bus-range = <0 0>;
-                       ranges = <02000000 0 a0000000 90000000 0 10000000
+                       ranges = <02000000 0 90000000 90000000 0 10000000
                                  42000000 0 80000000 80000000 0 10000000
                                  01000000 0 00000000 d0000000 0 00100000>;
                        clock-frequency = <0>;
index 07bcc5194d2babd0d9f24e312986fc634af43c4c..df773fafe9d179f886e68628fee8c826614e3887 100644 (file)
                        interrupt-parent = < &ipic >;
                        interrupts = <42 8>;
                        bus-range = <0 0>;
-                       ranges = <02000000 0 a0000000 a0000000 0 10000000
+                       ranges = <02000000 0 90000000 90000000 0 10000000
                                  42000000 0 80000000 80000000 0 10000000
                                  01000000 0 00000000 e2000000 0 00100000>;
                        clock-frequency = <3f940aa>;
                        interrupts = <42 8>;
                        bus-range = <0 0>;
                        ranges = <02000000 0 b0000000 b0000000 0 10000000
-                                 42000000 0 90000000 90000000 0 10000000
+                                 42000000 0 a0000000 a0000000 0 10000000
                                  01000000 0 00000000 e2100000 0 00100000>;
                        clock-frequency = <3f940aa>;
                        #interrupt-cells = <1>;
index a1fe97197ead13349d170cfa0812ed9388e8db07..91b657b339b442ded7dcd1f169a681ef7bf5ee07 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc4
-# Thu Jan 11 20:55:33 2007
+# Linux kernel version: 2.6.21
+# Tue May  8 12:32:16 2007
 #
 CONFIG_PPC64=y
 CONFIG_64BIT=y
@@ -60,6 +60,7 @@ CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -70,6 +71,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
@@ -132,15 +134,26 @@ CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_ISERIES is not set
 # CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
 # CONFIG_PPC_PMAC is not set
 # CONFIG_PPC_MAPLE is not set
 # CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+# CONFIG_PPC_PS3 is not set
 CONFIG_PPC_CELL=y
 # CONFIG_PPC_CELL_NATIVE is not set
 # CONFIG_PPC_IBM_CELL_BLADE is not set
-# CONFIG_PPC_PS3 is not set
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_PQ2ADS is not set
 CONFIG_PPC_UDBG_BEAT=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
 # CONFIG_U3_DART is not set
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
@@ -149,15 +162,7 @@ CONFIG_PPC_UDBG_BEAT=y
 # CONFIG_PPC_INDIRECT_IO is not set
 # CONFIG_GENERIC_IOMAP is not set
 # CONFIG_CPU_FREQ is not set
-# CONFIG_WANT_EARLY_SERIAL is not set
-# CONFIG_MPIC is not set
-
-#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=y
-CONFIG_SPU_BASE=y
-# CONFIG_CBE_RAS is not set
+# CONFIG_CPM2 is not set
 
 #
 # Kernel options
@@ -183,7 +188,6 @@ CONFIG_NUMA=y
 CONFIG_NODES_SHIFT=4
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_DEFAULT=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_SELECT_MEMORY_MODEL=y
 # CONFIG_FLATMEM_MANUAL is not set
@@ -199,6 +203,7 @@ CONFIG_MEMORY_HOTPLUG_SPARSE=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
 CONFIG_ARCH_MEMORY_PROBE=y
 CONFIG_NODES_SPAN_OTHER_NODES=y
 # CONFIG_PPC_64K_PAGES is not set
@@ -207,14 +212,14 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 # CONFIG_PM is not set
 CONFIG_SECCOMP=y
+# CONFIG_WANT_DEVICE_TREE is not set
 CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
 #
+CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_ISA_DMA=y
-# CONFIG_MPIC_WEIRD is not set
-# CONFIG_PPC_I8259 is not set
 # CONFIG_PPC_INDIRECT_PCI is not set
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
@@ -240,13 +245,13 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
@@ -262,7 +267,7 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
@@ -280,6 +285,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
@@ -302,17 +308,21 @@ CONFIG_NETFILTER=y
 #
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
 # CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
 CONFIG_IP_NF_QUEUE=m
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 
 #
 # IPv6: Netfilter Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
 
 #
 # DCCP Configuration (EXPERIMENTAL)
@@ -352,6 +362,13 @@ CONFIG_IP_NF_QUEUE=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
 # CONFIG_IEEE80211 is not set
 
 #
@@ -365,16 +382,13 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 
 #
 # Connector - unified userspace <-> kernelspace linker
 #
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
 
 #
@@ -385,6 +399,7 @@ CONFIG_FW_LOADER=y
 #
 # Plug and Play support
 #
+# CONFIG_PNPACPI is not set
 
 #
 # Block devices
@@ -404,7 +419,6 @@ CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=131072
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 
@@ -443,7 +457,6 @@ CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -458,6 +471,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_BLK_DEV_JMICRON is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
 # CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -468,11 +482,11 @@ CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_CELLEB=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -546,6 +560,7 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 
 #
@@ -591,12 +606,7 @@ CONFIG_DM_MULTIPATH=m
 # I2O device support
 #
 # CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_MAC_EMUMOUSEBTN is not set
-# CONFIG_WINDFARM is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
 
 #
 # Network device support
@@ -652,15 +662,18 @@ CONFIG_MII=y
 # CONFIG_BNX2 is not set
 CONFIG_SPIDER_NET=y
 # CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
 
 #
 # Ethernet (10000 Mbit)
 #
 # CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
+# CONFIG_PASEMI_MAC is not set
 
 #
 # Token Ring devices
@@ -668,9 +681,10 @@ CONFIG_SPIDER_NET=y
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
 # Wan interfaces
@@ -770,6 +784,7 @@ CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_TXX9=y
 CONFIG_HAS_TXX9_SERIAL=y
+CONFIG_SERIAL_TXX9_NR_UARTS=3
 CONFIG_SERIAL_TXX9_CONSOLE=y
 # CONFIG_SERIAL_TXX9_STDSERIAL is not set
 # CONFIG_SERIAL_JSM is not set
@@ -890,6 +905,11 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_HWMON is not set
 # CONFIG_HWMON_VID is not set
 
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
 #
 # Multimedia devices
 #
@@ -904,7 +924,7 @@ CONFIG_I2C_ALGOBIT=y
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 # CONFIG_FB is not set
 # CONFIG_FB_IBM_GXT4500 is not set
 
@@ -913,7 +933,6 @@ CONFIG_I2C_ALGOBIT=y
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -924,6 +943,15 @@ CONFIG_DUMMY_CONSOLE=y
 # HID Devices
 #
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
 
 #
 # USB support
@@ -938,9 +966,8 @@ CONFIG_USB=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_MULTITHREAD_PROBE is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -953,6 +980,7 @@ CONFIG_USB_EHCI_HCD=m
 CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
 CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -989,10 +1017,6 @@ CONFIG_USB_STORAGE=m
 #
 # USB Input Devices
 #
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_ACECAD is not set
@@ -1005,6 +1029,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_USB_ATI_REMOTE2 is not set
 # CONFIG_USB_KEYSPAN_REMOTE is not set
 # CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
 
 #
 # USB Imaging devices
@@ -1042,6 +1067,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
@@ -1052,6 +1078,7 @@ CONFIG_USB_MON=y
 # CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 
 #
@@ -1108,6 +1135,10 @@ CONFIG_USB_MON=y
 # DMA Devices
 #
 
+#
+# Auxiliary Display support
+#
+
 #
 # Virtualization
 #
@@ -1293,6 +1324,8 @@ CONFIG_NLS_ISO8859_15=m
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
 
 #
 # Library routines
@@ -1305,7 +1338,8 @@ CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=m
 CONFIG_ZLIB_DEFLATE=m
 CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
 
 #
 # Instrumentation Support
@@ -1323,15 +1357,16 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_RWSEMS is not set
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1341,8 +1376,10 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_FORCED_INLINING is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
 # CONFIG_DEBUG_STACKOVERFLOW is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_DEBUGGER=y
 CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
@@ -1356,6 +1393,7 @@ CONFIG_PPC_EARLY_DEBUG=y
 # CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
 # CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
 # CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
 CONFIG_PPC_EARLY_DEBUG_BEAT=y
 
 #
@@ -1385,8 +1423,10 @@ CONFIG_CRYPTO_TGR192=m
 # CONFIG_CRYPTO_GF128MUL is not set
 CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
 CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_TWOFISH_COMMON=m
@@ -1401,6 +1441,7 @@ CONFIG_CRYPTO_ANUBIS=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
 CONFIG_CRYPTO_TEST=m
 
 #
index 8f48560b7ee2f9e445dfa764bcae1e99c3cb3dc2..2cb1d948779614040ec6ae3f303a7627c8dbee66 100644 (file)
@@ -58,7 +58,7 @@ int main(void)
 #ifdef CONFIG_PPC64
        DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
 #else
-       DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
 #endif /* CONFIG_PPC64 */
 
@@ -122,12 +122,18 @@ int main(void)
        DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
        DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
        DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
-       DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
        DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp));
-#ifdef CONFIG_HUGETLB_PAGE
-       DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
-       DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
-#endif /* CONFIG_HUGETLB_PAGE */
+#ifdef CONFIG_PPC_MM_SLICES
+       DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
+                                           context.low_slices_psize));
+       DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct,
+                                           context.high_slices_psize));
+       DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
+       DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp));
+#else
+       DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+
+#endif /* CONFIG_PPC_MM_SLICES */
        DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
        DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
        DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
index 9ed4931af1641253cce9dfce6c52fd6deb91c230..068377a2a8dc021b008f7cb56d3d82b2e94994cb 100644 (file)
@@ -173,7 +173,7 @@ void local_irq_restore(unsigned long en)
                lv1_get_version_info(&tmp);
        }
 
-       hard_irq_enable();
+       __hard_irq_enable();
 }
 #endif /* CONFIG_PPC64 */
 
index 584d1e3c013d24cac3a2eb5d17a7eb66a52d8e85..af11285ffbd1d2b7f69acfbc8aacd5ddc6f1ddca 100644 (file)
@@ -10,7 +10,8 @@
 #include <asm/pgtable.h>
 #include <asm/iseries/lpar_map.h>
 
-const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
+/* The # is to stop gcc trying to make .text nonexecutable */
+const struct LparMap __attribute__((__section__(".text #"))) xLparMap = {
        .xNumberEsids = HvEsidsToMap,
        .xNumberRanges = HvRangesToMap,
        .xSegmentTableOffs = STAB0_PAGE,
index 6d05a1f377b5e1a56fb3294a4ec22661442c34fc..b0409e19b1c156fcb05935f512f1642f84253249 100644 (file)
@@ -1098,35 +1098,24 @@ static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
                                unsigned long *start_virt, unsigned long *size)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
-       struct pci_bus_region region;
        struct resource *res;
 
-       if (bus->self) {
+       if (bus->self)
                res = bus->resource[0];
-               pcibios_resource_to_bus(bus->self, &region, res);
-               *start_phys = hose->io_base_phys + region.start;
-               *start_virt = (unsigned long) hose->io_base_virt + 
-                               region.start;
-               if (region.end > region.start) 
-                       *size = region.end - region.start + 1;
-               else {
-                       printk("%s(): unexpected region 0x%lx->0x%lx\n", 
-                                       __FUNCTION__, region.start, region.end);
-                       return 1;
-               }
-               
-       } else {
+       else
                /* Root Bus */
                res = &hose->io_resource;
-               *start_phys = hose->io_base_phys + res->start;
-               *start_virt = (unsigned long) hose->io_base_virt + res->start;
-               if (res->end > res->start)
-                       *size = res->end - res->start + 1;
-               else {
-                       printk("%s(): unexpected region 0x%lx->0x%lx\n", 
-                                       __FUNCTION__, res->start, res->end);
-                       return 1;
-               }
+
+       *start_virt = pci_io_base + res->start;
+       *start_phys = *start_virt + hose->io_base_phys
+               - (unsigned long) hose->io_base_virt;
+
+       if (res->end > res->start)
+               *size = res->end - res->start + 1;
+       else {
+               printk("%s(): unexpected region 0x%lx->0x%lx\n",
+                      __FUNCTION__, res->start, res->end);
+               return 1;
        }
 
        return 0;
index caef555f2dc06a1f1b20e225d3b272d36c378ee9..c065b555036881b138b3c70ba378bb6392a07db7 100644 (file)
@@ -716,11 +716,40 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
        return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+static void __init early_init_dt_check_for_initrd(unsigned long node)
+{
+       unsigned long l;
+       u32 *prop;
+
+       DBG("Looking for initrd properties... ");
+
+       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+       if (prop) {
+               initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+
+               prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+               if (prop) {
+                       initrd_end = (unsigned long)
+                                       __va(of_read_ulong(prop, l/4));
+                       initrd_below_start_ok = 1;
+               } else {
+                       initrd_start = 0;
+               }
+       }
+
+       DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
+}
+#else
+static inline void early_init_dt_check_for_initrd(unsigned long node)
+{
+}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 static int __init early_init_dt_scan_chosen(unsigned long node,
                                            const char *uname, int depth, void *data)
 {
        unsigned long *lprop;
-       u32 *prop;
        unsigned long l;
        char *p;
 
@@ -762,21 +791,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
                crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
 
-#ifdef CONFIG_BLK_DEV_INITRD
-       DBG("Looking for initrd properties... ");
-       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
-       if (prop) {
-               initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
-               prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
-               if (prop) {
-                       initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
-                       initrd_below_start_ok = 1;
-               } else {
-                       initrd_start = 0;
-               }
-       }
-       DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
-#endif /* CONFIG_BLK_DEV_INITRD */
+       early_init_dt_check_for_initrd(node);
 
        /* Retreive command line */
        p = of_get_flat_dt_prop(node, "bootargs", &l);
index 064a7ba4f02c0a43e87e6ee68f96ab2ebf63f426..77b7b34b5955f0d6453e829b75454f0df145da9c 100644 (file)
@@ -36,8 +36,4 @@ void restore_processor_state(void)
 #ifdef CONFIG_PPC32
        set_context(current->active_mm->context.id, current->active_mm->pgd);
 #endif
-
-#ifdef CONFIG_PPC64
-       hard_irq_enable();
-#endif
 }
index cae39d9dfe48add64f8be93cff924f630003cfd4..68991c2d4a1b3a6fcb101728c2be0e9724dcf37d 100644 (file)
@@ -342,10 +342,12 @@ static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                register_cpu_online(cpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                unregister_cpu_online(cpu);
                break;
 #endif
index 450258de7ca1215cdd9f2d63dea6e91053def2ee..0a486d4b2547e98af054799435d11c2a9de25379 100644 (file)
@@ -23,7 +23,5 @@ obj-$(CONFIG_SMP)     += locks.o
 endif
 
 # Temporary hack until we have migrated to asm-powerpc
-ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_8xx)      += rheap.o
 obj-$(CONFIG_CPM2)     += rheap.o
-endif
index 6c5c5dd183ee3ac79c57bf4f5cf744b91a15ad47..b2f6dcc59600bb5c6d21c753b0eb6058491ca260 100644 (file)
@@ -133,7 +133,7 @@ static rh_block_t *get_slot(rh_info_t * info)
        info->empty_slots--;
 
        /* Initialize */
-       blk->start = NULL;
+       blk->start = 0;
        blk->size = 0;
        blk->owner = NULL;
 
@@ -158,7 +158,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
 
        /* We assume that they are aligned properly */
        size = blkn->size;
-       s = (unsigned long)blkn->start;
+       s = blkn->start;
        e = s + size;
 
        /* Find the blocks immediately before and after the given one
@@ -170,7 +170,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
        list_for_each(l, &info->free_list) {
                blk = list_entry(l, rh_block_t, list);
 
-               bs = (unsigned long)blk->start;
+               bs = blk->start;
                be = bs + blk->size;
 
                if (next == NULL && s >= bs)
@@ -188,10 +188,10 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
        }
 
        /* Now check if they are really adjacent */
-       if (before != NULL && s != (unsigned long)before->start + before->size)
+       if (before && s != (before->start + before->size))
                before = NULL;
 
-       if (after != NULL && e != (unsigned long)after->start)
+       if (after && e != after->start)
                after = NULL;
 
        /* No coalescing; list insert and return */
@@ -216,7 +216,7 @@ static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
 
        /* Grow the after block backwards */
        if (before == NULL && after != NULL) {
-               after->start = (int8_t *)after->start - size;
+               after->start -= size;
                after->size += size;
                return;
        }
@@ -321,14 +321,14 @@ void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
 }
 
 /* Attach a free memory region, coalesces regions if adjuscent */
-int rh_attach_region(rh_info_t * info, void *start, int size)
+int rh_attach_region(rh_info_t * info, unsigned long start, int size)
 {
        rh_block_t *blk;
        unsigned long s, e, m;
        int r;
 
        /* The region must be aligned */
-       s = (unsigned long)start;
+       s = start;
        e = s + size;
        m = info->alignment - 1;
 
@@ -338,9 +338,12 @@ int rh_attach_region(rh_info_t * info, void *start, int size)
        /* Round end down */
        e = e & ~m;
 
+       if (IS_ERR_VALUE(e) || (e < s))
+               return -ERANGE;
+
        /* Take final values */
-       start = (void *)s;
-       size = (int)(e - s);
+       start = s;
+       size = e - s;
 
        /* Grow the blocks, if needed */
        r = assure_empty(info, 1);
@@ -358,7 +361,7 @@ int rh_attach_region(rh_info_t * info, void *start, int size)
 }
 
 /* Detatch given address range, splits free block if needed. */
-void *rh_detach_region(rh_info_t * info, void *start, int size)
+unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
 {
        struct list_head *l;
        rh_block_t *blk, *newblk;
@@ -366,10 +369,10 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
 
        /* Validate size */
        if (size <= 0)
-               return ERR_PTR(-EINVAL);
+               return (unsigned long) -EINVAL;
 
        /* The region must be aligned */
-       s = (unsigned long)start;
+       s = start;
        e = s + size;
        m = info->alignment - 1;
 
@@ -380,34 +383,34 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
        e = e & ~m;
 
        if (assure_empty(info, 1) < 0)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        blk = NULL;
        list_for_each(l, &info->free_list) {
                blk = list_entry(l, rh_block_t, list);
                /* The range must lie entirely inside one free block */
-               bs = (unsigned long)blk->start;
-               be = (unsigned long)blk->start + blk->size;
+               bs = blk->start;
+               be = blk->start + blk->size;
                if (s >= bs && e <= be)
                        break;
                blk = NULL;
        }
 
        if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        /* Perfect fit */
        if (bs == s && be == e) {
                /* Delete from free list, release slot */
                list_del(&blk->list);
                release_slot(info, blk);
-               return (void *)s;
+               return s;
        }
 
        /* blk still in free list, with updated start and/or size */
        if (bs == s || be == e) {
                if (bs == s)
-                       blk->start = (int8_t *)blk->start + size;
+                       blk->start += size;
                blk->size -= size;
 
        } else {
@@ -416,25 +419,29 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
 
                /* the back free fragment */
                newblk = get_slot(info);
-               newblk->start = (void *)e;
+               newblk->start = e;
                newblk->size = be - e;
 
                list_add(&newblk->list, &blk->list);
        }
 
-       return (void *)s;
+       return s;
 }
 
-void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
+/* Allocate a block of memory at the specified alignment.  The value returned
+ * is an offset into the buffer initialized by rh_init(), or a negative number
+ * if there is an error.
+ */
+unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
 {
        struct list_head *l;
        rh_block_t *blk;
        rh_block_t *newblk;
-       void *start;
+       unsigned long start;
 
-       /* Validate size, (must be power of two) */
+       /* Validate size, and alignment must be power of two */
        if (size <= 0 || (alignment & (alignment - 1)) != 0)
-               return ERR_PTR(-EINVAL);
+               return (unsigned long) -EINVAL;
 
        /* given alignment larger that default rheap alignment */
        if (alignment > info->alignment)
@@ -444,7 +451,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
        size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
 
        if (assure_empty(info, 1) < 0)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        blk = NULL;
        list_for_each(l, &info->free_list) {
@@ -455,7 +462,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
        }
 
        if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        /* Just fits */
        if (blk->size == size) {
@@ -475,7 +482,7 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
        newblk->owner = owner;
 
        /* blk still in free list, with updated start, size */
-       blk->start = (int8_t *)blk->start + size;
+       blk->start += size;
        blk->size -= size;
 
        start = newblk->start;
@@ -486,19 +493,25 @@ void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owne
        /* this is no problem with the deallocator since */
        /* we scan for pointers that lie in the blocks   */
        if (alignment > info->alignment)
-               start = (void *)(((unsigned long)start + alignment - 1) &
-                               ~(alignment - 1));
+               start = (start + alignment - 1) & ~(alignment - 1);
 
        return start;
 }
 
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
+/* Allocate a block of memory at the default alignment.  The value returned is
+ * an offset into the buffer initialized by rh_init(), or a negative number if
+ * there is an error.
+ */
+unsigned long rh_alloc(rh_info_t * info, int size, const char *owner)
 {
        return rh_alloc_align(info, size, info->alignment, owner);
 }
 
-/* allocate at precisely the given address */
-void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
+/* Allocate a block of memory at the given offset, rounded up to the default
+ * alignment.  The value returned is an offset into the buffer initialized by
+ * rh_init(), or a negative number if there is an error.
+ */
+unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, const char *owner)
 {
        struct list_head *l;
        rh_block_t *blk, *newblk1, *newblk2;
@@ -506,10 +519,10 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
 
        /* Validate size */
        if (size <= 0)
-               return ERR_PTR(-EINVAL);
+               return (unsigned long) -EINVAL;
 
        /* The region must be aligned */
-       s = (unsigned long)start;
+       s = start;
        e = s + size;
        m = info->alignment - 1;
 
@@ -520,20 +533,20 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
        e = e & ~m;
 
        if (assure_empty(info, 2) < 0)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        blk = NULL;
        list_for_each(l, &info->free_list) {
                blk = list_entry(l, rh_block_t, list);
                /* The range must lie entirely inside one free block */
-               bs = (unsigned long)blk->start;
-               be = (unsigned long)blk->start + blk->size;
+               bs = blk->start;
+               be = blk->start + blk->size;
                if (s >= bs && e <= be)
                        break;
        }
 
        if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
+               return (unsigned long) -ENOMEM;
 
        /* Perfect fit */
        if (bs == s && be == e) {
@@ -551,7 +564,7 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
        /* blk still in free list, with updated start and/or size */
        if (bs == s || be == e) {
                if (bs == s)
-                       blk->start = (int8_t *)blk->start + size;
+                       blk->start += size;
                blk->size -= size;
 
        } else {
@@ -560,14 +573,14 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
 
                /* The back free fragment */
                newblk2 = get_slot(info);
-               newblk2->start = (void *)e;
+               newblk2->start = e;
                newblk2->size = be - e;
 
                list_add(&newblk2->list, &blk->list);
        }
 
        newblk1 = get_slot(info);
-       newblk1->start = (void *)s;
+       newblk1->start = s;
        newblk1->size = e - s;
        newblk1->owner = owner;
 
@@ -577,7 +590,11 @@ void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
        return start;
 }
 
-int rh_free(rh_info_t * info, void *start)
+/* Deallocate the memory previously allocated by one of the rh_alloc functions.
+ * The return value is the size of the deallocated block, or a negative number
+ * if there is an error.
+ */
+int rh_free(rh_info_t * info, unsigned long start)
 {
        rh_block_t *blk, *blk2;
        struct list_head *l;
@@ -642,7 +659,7 @@ int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
        return nr;
 }
 
-int rh_set_owner(rh_info_t * info, void *start, const char *owner)
+int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
 {
        rh_block_t *blk, *blk2;
        struct list_head *l;
@@ -684,8 +701,8 @@ void rh_dump(rh_info_t * info)
                nr = maxnr;
        for (i = 0; i < nr; i++)
                printk(KERN_INFO
-                      "    0x%p-0x%p (%u)\n",
-                      st[i].start, (int8_t *) st[i].start + st[i].size,
+                      "    0x%lx-0x%lx (%u)\n",
+                      st[i].start, st[i].start + st[i].size,
                       st[i].size);
        printk(KERN_INFO "\n");
 
@@ -695,8 +712,8 @@ void rh_dump(rh_info_t * info)
                nr = maxnr;
        for (i = 0; i < nr; i++)
                printk(KERN_INFO
-                      "    0x%p-0x%p (%u) %s\n",
-                      st[i].start, (int8_t *) st[i].start + st[i].size,
+                      "    0x%lx-0x%lx (%u) %s\n",
+                      st[i].start, st[i].start + st[i].size,
                       st[i].size, st[i].owner != NULL ? st[i].owner : "");
        printk(KERN_INFO "\n");
 }
@@ -704,6 +721,6 @@ void rh_dump(rh_info_t * info)
 void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
 {
        printk(KERN_INFO
-              "blk @0x%p: 0x%p-0x%p (%u)\n",
-              blk, blk->start, (int8_t *) blk->start + blk->size, blk->size);
+              "blk @0x%p: 0x%lx-0x%lx (%u)\n",
+              blk, blk->start, blk->start + blk->size, blk->size);
 }
index 38a81967ca0702a1f0f04b4de7aa8712fe79627d..4f839c6a97682165fc9c7d18c91140fea0eddd31 100644 (file)
@@ -18,4 +18,5 @@ obj-$(CONFIG_40x)             += 4xx_mmu.o
 obj-$(CONFIG_44x)              += 44x_mmu.o
 obj-$(CONFIG_FSL_BOOKE)                += fsl_booke_mmu.o
 obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
+obj-$(CONFIG_PPC_MM_SLICES)    += slice.o
 obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
index e64ce3eec36ed3e025324cb68011bac3c6a1028c..4762ff7c14df22fd2c4c5bdcc6a1e234665c917a 100644 (file)
@@ -615,6 +615,9 @@ htab_pte_insert_failure:
        li      r3,-1
        b       htab_bail
 
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
 
 /*****************************************************************************
  *                                                                           *
@@ -870,7 +873,7 @@ ht64_pte_insert_failure:
        b       ht64_bail
 
 
-#endif /* CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC_HAS_HASH_64K */
 
 
 /*****************************************************************************
index 7b7fe2d7b9dc7c1e882984ab2b8ba17461b70617..7d722eea4ea8ba927850c54cc85aff990ed81727 100644 (file)
@@ -376,31 +376,28 @@ static void hpte_decode(hpte_t *hpte, unsigned long slot,
                }
        }
 
-       /*
-        * FIXME, the code below works for 16M, 64K, and 4K pages as these
-        * fall under the p<=23 rules for calculating the virtual address.
-        * In the case of 16M pages, an extra bit is stolen from the AVPN
-        * field to achieve the requisite 24 bits.
-        *
-        * Does not work for 16G pages or 1 TB segments.
-        */
+       /* This works for all page sizes, and for 256M and 1T segments */
        shift = mmu_psize_defs[size].shift;
-       if (mmu_psize_defs[size].avpnm)
-               avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1;
-       else
-               avpnm_bits = 0;
-       if (shift - avpnm_bits <= 23) {
-               avpn = HPTE_V_AVPN_VAL(hpte_v) << 23;
+       avpn = (HPTE_V_AVPN_VAL(hpte_v) & ~mmu_psize_defs[size].avpnm) << 23;
 
-               if (shift < 23) {
-                       unsigned long vpi, pteg;
+       if (shift < 23) {
+               unsigned long vpi, vsid, pteg;
 
-                       pteg = slot / HPTES_PER_GROUP;
-                       if (hpte_v & HPTE_V_SECONDARY)
-                               pteg = ~pteg;
+               pteg = slot / HPTES_PER_GROUP;
+               if (hpte_v & HPTE_V_SECONDARY)
+                       pteg = ~pteg;
+               switch (hpte_v >> HPTE_V_SSIZE_SHIFT) {
+               case MMU_SEGSIZE_256M:
                        vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask;
-                       avpn |= (vpi << mmu_psize_defs[size].shift);
+                       break;
+               case MMU_SEGSIZE_1T:
+                       vsid = avpn >> 40;
+                       vpi = (vsid ^ (vsid << 25) ^ pteg) & htab_hash_mask;
+                       break;
+               default:
+                       avpn = vpi = psize = 0;
                }
+               avpn |= (vpi << mmu_psize_defs[size].shift);
        }
 
        *va = avpn;
index 9b226fa7006fd51e32d497a813abce46a38766dd..028ba4ed03d2c88f5c413b96c83fe60e00161f58 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/cputable.h>
 #include <asm/abs_addr.h>
 #include <asm/sections.h>
+#include <asm/spu.h>
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
@@ -419,7 +420,7 @@ static void __init htab_finish_init(void)
        extern unsigned int *htab_call_hpte_remove;
        extern unsigned int *htab_call_hpte_updatepp;
 
-#ifdef CONFIG_PPC_64K_PAGES
+#ifdef CONFIG_PPC_HAS_HASH_64K
        extern unsigned int *ht64_call_hpte_insert1;
        extern unsigned int *ht64_call_hpte_insert2;
        extern unsigned int *ht64_call_hpte_remove;
@@ -596,22 +597,23 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
  * Demote a segment to using 4k pages.
  * For now this makes the whole process use 4k pages.
  */
-void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
-{
 #ifdef CONFIG_PPC_64K_PAGES
+static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
        if (mm->context.user_psize == MMU_PAGE_4K)
                return;
+#ifdef CONFIG_PPC_MM_SLICES
+       slice_set_user_psize(mm, MMU_PAGE_4K);
+#else /* CONFIG_PPC_MM_SLICES */
        mm->context.user_psize = MMU_PAGE_4K;
        mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
-       get_paca()->context = mm->context;
-       slb_flush_and_rebolt();
+#endif /* CONFIG_PPC_MM_SLICES */
+
 #ifdef CONFIG_SPE_BASE
        spu_flush_all_slbs(mm);
 #endif
-#endif
 }
-
-EXPORT_SYMBOL_GPL(demote_segment_4k);
+#endif /* CONFIG_PPC_64K_PAGES */
 
 /* Result code is:
  *  0 - handled
@@ -646,7 +648,11 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
                        return 1;
                }
                vsid = get_vsid(mm->context.id, ea);
+#ifdef CONFIG_PPC_MM_SLICES
+               psize = get_slice_psize(mm, ea);
+#else
                psize = mm->context.user_psize;
+#endif
                break;
        case VMALLOC_REGION_ID:
                mm = &init_mm;
@@ -674,11 +680,22 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        if (user_region && cpus_equal(mm->cpu_vm_mask, tmp))
                local = 1;
 
+#ifdef CONFIG_HUGETLB_PAGE
        /* Handle hugepage regions */
-       if (unlikely(in_hugepage_area(mm->context, ea))) {
+       if (HPAGE_SHIFT && psize == mmu_huge_psize) {
                DBG_LOW(" -> huge page !\n");
                return hash_huge_page(mm, access, ea, vsid, local, trap);
        }
+#endif /* CONFIG_HUGETLB_PAGE */
+
+#ifndef CONFIG_PPC_64K_PAGES
+       /* If we use 4K pages and our psize is not 4K, then we are hitting
+        * a special driver mapping, we need to align the address before
+        * we fetch the PTE
+        */
+       if (psize != MMU_PAGE_4K)
+               ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
+#endif /* CONFIG_PPC_64K_PAGES */
 
        /* Get PTE and page size from page tables */
        ptep = find_linux_pte(pgdir, ea);
@@ -702,54 +719,56 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        }
 
        /* Do actual hashing */
-#ifndef CONFIG_PPC_64K_PAGES
-       rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
+#ifdef CONFIG_PPC_64K_PAGES
        /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
        if (pte_val(*ptep) & _PAGE_4K_PFN) {
                demote_segment_4k(mm, ea);
                psize = MMU_PAGE_4K;
        }
 
-       if (mmu_ci_restrictions) {
-               /* If this PTE is non-cacheable, switch to 4k */
-               if (psize == MMU_PAGE_64K &&
-                   (pte_val(*ptep) & _PAGE_NO_CACHE)) {
-                       if (user_region) {
-                               demote_segment_4k(mm, ea);
-                               psize = MMU_PAGE_4K;
-                       } else if (ea < VMALLOC_END) {
-                               /*
-                                * some driver did a non-cacheable mapping
-                                * in vmalloc space, so switch vmalloc
-                                * to 4k pages
-                                */
-                               printk(KERN_ALERT "Reducing vmalloc segment "
-                                      "to 4kB pages because of "
-                                      "non-cacheable mapping\n");
-                               psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-                       }
+       /* If this PTE is non-cacheable and we have restrictions on
+        * using non cacheable large pages, then we switch to 4k
+        */
+       if (mmu_ci_restrictions && psize == MMU_PAGE_64K &&
+           (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+               if (user_region) {
+                       demote_segment_4k(mm, ea);
+                       psize = MMU_PAGE_4K;
+               } else if (ea < VMALLOC_END) {
+                       /*
+                        * some driver did a non-cacheable mapping
+                        * in vmalloc space, so switch vmalloc
+                        * to 4k pages
+                        */
+                       printk(KERN_ALERT "Reducing vmalloc segment "
+                              "to 4kB pages because of "
+                              "non-cacheable mapping\n");
+                       psize = mmu_vmalloc_psize = MMU_PAGE_4K;
 #ifdef CONFIG_SPE_BASE
                        spu_flush_all_slbs(mm);
 #endif
                }
-               if (user_region) {
-                       if (psize != get_paca()->context.user_psize) {
-                               get_paca()->context = mm->context;
-                               slb_flush_and_rebolt();
-                       }
-               } else if (get_paca()->vmalloc_sllp !=
-                          mmu_psize_defs[mmu_vmalloc_psize].sllp) {
-                       get_paca()->vmalloc_sllp =
-                               mmu_psize_defs[mmu_vmalloc_psize].sllp;
+       }
+       if (user_region) {
+               if (psize != get_paca()->context.user_psize) {
+                       get_paca()->context.user_psize =
+                               mm->context.user_psize;
                        slb_flush_and_rebolt();
                }
+       } else if (get_paca()->vmalloc_sllp !=
+                  mmu_psize_defs[mmu_vmalloc_psize].sllp) {
+               get_paca()->vmalloc_sllp =
+                       mmu_psize_defs[mmu_vmalloc_psize].sllp;
+               slb_flush_and_rebolt();
        }
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
        if (psize == MMU_PAGE_64K)
                rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
        else
+#endif /* CONFIG_PPC_HAS_HASH_64K */
                rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#endif /* CONFIG_PPC_64K_PAGES */
 
 #ifndef CONFIG_PPC_64K_PAGES
        DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -772,42 +791,55 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
        unsigned long flags;
        int local = 0;
 
-       /* We don't want huge pages prefaulted for now
-        */
-       if (unlikely(in_hugepage_area(mm->context, ea)))
+       BUG_ON(REGION_ID(ea) != USER_REGION_ID);
+
+#ifdef CONFIG_PPC_MM_SLICES
+       /* We only prefault standard pages for now */
+       if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize));
                return;
+#endif
 
        DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
                " trap=%lx\n", mm, mm->pgd, ea, access, trap);
 
-       /* Get PTE, VSID, access mask */
+       /* Get Linux PTE if available */
        pgdir = mm->pgd;
        if (pgdir == NULL)
                return;
        ptep = find_linux_pte(pgdir, ea);
        if (!ptep)
                return;
+
+#ifdef CONFIG_PPC_64K_PAGES
+       /* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
+        * a 64K kernel), then we don't preload, hash_page() will take
+        * care of it once we actually try to access the page.
+        * That way we don't have to duplicate all of the logic for segment
+        * page size demotion here
+        */
+       if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
+               return;
+#endif /* CONFIG_PPC_64K_PAGES */
+
+       /* Get VSID */
        vsid = get_vsid(mm->context.id, ea);
 
-       /* Hash it in */
+       /* Hash doesn't like irqs */
        local_irq_save(flags);
+
+       /* Is that local to this CPU ? */
        mask = cpumask_of_cpu(smp_processor_id());
        if (cpus_equal(mm->cpu_vm_mask, mask))
                local = 1;
-#ifndef CONFIG_PPC_64K_PAGES
-       __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
-       if (mmu_ci_restrictions) {
-               /* If this PTE is non-cacheable, switch to 4k */
-               if (mm->context.user_psize == MMU_PAGE_64K &&
-                   (pte_val(*ptep) & _PAGE_NO_CACHE))
-                       demote_segment_4k(mm, ea);
-       }
+
+       /* Hash it in */
+#ifdef CONFIG_PPC_HAS_HASH_64K
        if (mm->context.user_psize == MMU_PAGE_64K)
                __hash_page_64K(ea, access, vsid, ptep, trap, local);
        else
-               __hash_page_4K(ea, access, vsid, ptep, trap, local);
 #endif /* CONFIG_PPC_64K_PAGES */
+               __hash_page_4K(ea, access, vsid, ptep, trap, local);
+
        local_irq_restore(flags);
 }
 
index fb959264c104387b5c51c647e6f64743c0e4d6bb..92a1b16fb7e3bab4fe1716d228d32961b77ee302 100644 (file)
@@ -91,7 +91,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
        pgd_t *pg;
        pud_t *pu;
 
-       BUG_ON(! in_hugepage_area(mm->context, addr));
+       BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
        addr &= HPAGE_MASK;
 
@@ -119,7 +119,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
        pud_t *pu;
        hugepd_t *hpdp = NULL;
 
-       BUG_ON(! in_hugepage_area(mm->context, addr));
+       BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
 
        addr &= HPAGE_MASK;
 
@@ -302,7 +302,7 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb,
        start = addr;
        pgd = pgd_offset((*tlb)->mm, addr);
        do {
-               BUG_ON(! in_hugepage_area((*tlb)->mm->context, addr));
+               BUG_ON(get_slice_psize((*tlb)->mm, addr) != mmu_huge_psize);
                next = pgd_addr_end(addr, end);
                if (pgd_none_or_clear_bad(pgd))
                        continue;
@@ -331,203 +331,13 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
        return __pte(old);
 }
 
-struct slb_flush_info {
-       struct mm_struct *mm;
-       u16 newareas;
-};
-
-static void flush_low_segments(void *parm)
-{
-       struct slb_flush_info *fi = parm;
-       unsigned long i;
-
-       BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_LOW_AREAS);
-
-       if (current->active_mm != fi->mm)
-               return;
-
-       /* Only need to do anything if this CPU is working in the same
-        * mm as the one which has changed */
-
-       /* update the paca copy of the context struct */
-       get_paca()->context = current->active_mm->context;
-
-       asm volatile("isync" : : : "memory");
-       for (i = 0; i < NUM_LOW_AREAS; i++) {
-               if (! (fi->newareas & (1U << i)))
-                       continue;
-               asm volatile("slbie %0"
-                            : : "r" ((i << SID_SHIFT) | SLBIE_C));
-       }
-       asm volatile("isync" : : : "memory");
-}
-
-static void flush_high_segments(void *parm)
-{
-       struct slb_flush_info *fi = parm;
-       unsigned long i, j;
-
-
-       BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_HIGH_AREAS);
-
-       if (current->active_mm != fi->mm)
-               return;
-
-       /* Only need to do anything if this CPU is working in the same
-        * mm as the one which has changed */
-
-       /* update the paca copy of the context struct */
-       get_paca()->context = current->active_mm->context;
-
-       asm volatile("isync" : : : "memory");
-       for (i = 0; i < NUM_HIGH_AREAS; i++) {
-               if (! (fi->newareas & (1U << i)))
-                       continue;
-               for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
-                       asm volatile("slbie %0"
-                                    :: "r" (((i << HTLB_AREA_SHIFT)
-                                             + (j << SID_SHIFT)) | SLBIE_C));
-       }
-       asm volatile("isync" : : : "memory");
-}
-
-static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-       unsigned long start = area << SID_SHIFT;
-       unsigned long end = (area+1) << SID_SHIFT;
-       struct vm_area_struct *vma;
-
-       BUG_ON(area >= NUM_LOW_AREAS);
-
-       /* Check no VMAs are in the region */
-       vma = find_vma(mm, start);
-       if (vma && (vma->vm_start < end))
-               return -EBUSY;
-
-       return 0;
-}
-
-static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
-       unsigned long start = area << HTLB_AREA_SHIFT;
-       unsigned long end = (area+1) << HTLB_AREA_SHIFT;
-       struct vm_area_struct *vma;
-
-       BUG_ON(area >= NUM_HIGH_AREAS);
-
-       /* Hack, so that each addresses is controlled by exactly one
-        * of the high or low area bitmaps, the first high area starts
-        * at 4GB, not 0 */
-       if (start == 0)
-               start = 0x100000000UL;
-
-       /* Check no VMAs are in the region */
-       vma = find_vma(mm, start);
-       if (vma && (vma->vm_start < end))
-               return -EBUSY;
-
-       return 0;
-}
-
-static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-       unsigned long i;
-       struct slb_flush_info fi;
-
-       BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
-       BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
-
-       newareas &= ~(mm->context.low_htlb_areas);
-       if (! newareas)
-               return 0; /* The segments we want are already open */
-
-       for (i = 0; i < NUM_LOW_AREAS; i++)
-               if ((1 << i) & newareas)
-                       if (prepare_low_area_for_htlb(mm, i) != 0)
-                               return -EBUSY;
-
-       mm->context.low_htlb_areas |= newareas;
-
-       /* the context change must make it to memory before the flush,
-        * so that further SLB misses do the right thing. */
-       mb();
-
-       fi.mm = mm;
-       fi.newareas = newareas;
-       on_each_cpu(flush_low_segments, &fi, 0, 1);
-
-       return 0;
-}
-
-static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
-       struct slb_flush_info fi;
-       unsigned long i;
-
-       BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
-       BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
-                    != NUM_HIGH_AREAS);
-
-       newareas &= ~(mm->context.high_htlb_areas);
-       if (! newareas)
-               return 0; /* The areas we want are already open */
-
-       for (i = 0; i < NUM_HIGH_AREAS; i++)
-               if ((1 << i) & newareas)
-                       if (prepare_high_area_for_htlb(mm, i) != 0)
-                               return -EBUSY;
-
-       mm->context.high_htlb_areas |= newareas;
-
-       /* the context change must make it to memory before the flush,
-        * so that further SLB misses do the right thing. */
-       mb();
-
-       fi.mm = mm;
-       fi.newareas = newareas;
-       on_each_cpu(flush_high_segments, &fi, 0, 1);
-
-       return 0;
-}
-
-int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff)
-{
-       int err = 0;
-
-       if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT))
-               return -EINVAL;
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (addr & ~HPAGE_MASK)
-               return -EINVAL;
-
-       if (addr < 0x100000000UL)
-               err = open_low_hpage_areas(current->mm,
-                                         LOW_ESID_MASK(addr, len));
-       if ((addr + len) > 0x100000000UL)
-               err = open_high_hpage_areas(current->mm,
-                                           HTLB_AREA_MASK(addr, len));
-#ifdef CONFIG_SPE_BASE
-       spu_flush_all_slbs(current->mm);
-#endif
-       if (err) {
-               printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
-                      " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
-                      addr, len,
-                      LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
-               return err;
-       }
-
-       return 0;
-}
-
 struct page *
 follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
 {
        pte_t *ptep;
        struct page *page;
 
-       if (! in_hugepage_area(mm->context, address))
+       if (get_slice_psize(mm, address) != mmu_huge_psize)
                return ERR_PTR(-EINVAL);
 
        ptep = huge_pte_offset(mm, address);
@@ -551,359 +361,13 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
        return NULL;
 }
 
-/* Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions. */
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
-                                    unsigned long len, unsigned long pgoff,
-                                    unsigned long flags)
-{
-       struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma;
-       unsigned long start_addr;
-
-       if (len > TASK_SIZE)
-               return -ENOMEM;
-
-       /* handle fixed mapping: prevent overlap with huge pages */
-       if (flags & MAP_FIXED) {
-               if (is_hugepage_only_range(mm, addr, len))
-                       return -EINVAL;
-               return addr;
-       }
-
-       if (addr) {
-               addr = PAGE_ALIGN(addr);
-               vma = find_vma(mm, addr);
-               if (((TASK_SIZE - len) >= addr)
-                   && (!vma || (addr+len) <= vma->vm_start)
-                   && !is_hugepage_only_range(mm, addr,len))
-                       return addr;
-       }
-       if (len > mm->cached_hole_size) {
-               start_addr = addr = mm->free_area_cache;
-       } else {
-               start_addr = addr = TASK_UNMAPPED_BASE;
-               mm->cached_hole_size = 0;
-       }
-
-full_search:
-       vma = find_vma(mm, addr);
-       while (TASK_SIZE - len >= addr) {
-               BUG_ON(vma && (addr >= vma->vm_end));
-
-               if (touches_hugepage_low_range(mm, addr, len)) {
-                       addr = ALIGN(addr+1, 1<<SID_SHIFT);
-                       vma = find_vma(mm, addr);
-                       continue;
-               }
-               if (touches_hugepage_high_range(mm, addr, len)) {
-                       addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-                       vma = find_vma(mm, addr);
-                       continue;
-               }
-               if (!vma || addr + len <= vma->vm_start) {
-                       /*
-                        * Remember the place where we stopped the search:
-                        */
-                       mm->free_area_cache = addr + len;
-                       return addr;
-               }
-               if (addr + mm->cached_hole_size < vma->vm_start)
-                       mm->cached_hole_size = vma->vm_start - addr;
-               addr = vma->vm_end;
-               vma = vma->vm_next;
-       }
-
-       /* Make sure we didn't miss any holes */
-       if (start_addr != TASK_UNMAPPED_BASE) {
-               start_addr = addr = TASK_UNMAPPED_BASE;
-               mm->cached_hole_size = 0;
-               goto full_search;
-       }
-       return -ENOMEM;
-}
-
-/*
- * This mmap-allocator allocates new areas top-down from below the
- * stack's low limit (the base):
- *
- * Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions.
- */
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
-                         const unsigned long len, const unsigned long pgoff,
-                         const unsigned long flags)
-{
-       struct vm_area_struct *vma, *prev_vma;
-       struct mm_struct *mm = current->mm;
-       unsigned long base = mm->mmap_base, addr = addr0;
-       unsigned long largest_hole = mm->cached_hole_size;
-       int first_time = 1;
-
-       /* requested length too big for entire address space */
-       if (len > TASK_SIZE)
-               return -ENOMEM;
-
-       /* handle fixed mapping: prevent overlap with huge pages */
-       if (flags & MAP_FIXED) {
-               if (is_hugepage_only_range(mm, addr, len))
-                       return -EINVAL;
-               return addr;
-       }
-
-       /* dont allow allocations above current base */
-       if (mm->free_area_cache > base)
-               mm->free_area_cache = base;
-
-       /* requesting a specific address */
-       if (addr) {
-               addr = PAGE_ALIGN(addr);
-               vma = find_vma(mm, addr);
-               if (TASK_SIZE - len >= addr &&
-                               (!vma || addr + len <= vma->vm_start)
-                               && !is_hugepage_only_range(mm, addr,len))
-                       return addr;
-       }
-
-       if (len <= largest_hole) {
-               largest_hole = 0;
-               mm->free_area_cache = base;
-       }
-try_again:
-       /* make sure it can fit in the remaining address space */
-       if (mm->free_area_cache < len)
-               goto fail;
-
-       /* either no address requested or cant fit in requested address hole */
-       addr = (mm->free_area_cache - len) & PAGE_MASK;
-       do {
-hugepage_recheck:
-               if (touches_hugepage_low_range(mm, addr, len)) {
-                       addr = (addr & ((~0) << SID_SHIFT)) - len;
-                       goto hugepage_recheck;
-               } else if (touches_hugepage_high_range(mm, addr, len)) {
-                       addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
-                       goto hugepage_recheck;
-               }
-
-               /*
-                * Lookup failure means no vma is above this address,
-                * i.e. return with success:
-                */
-               if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
-                       return addr;
-
-               /*
-                * new region fits between prev_vma->vm_end and
-                * vma->vm_start, use it:
-                */
-               if (addr+len <= vma->vm_start &&
-                         (!prev_vma || (addr >= prev_vma->vm_end))) {
-                       /* remember the address as a hint for next time */
-                       mm->cached_hole_size = largest_hole;
-                       return (mm->free_area_cache = addr);
-               } else {
-                       /* pull free_area_cache down to the first hole */
-                       if (mm->free_area_cache == vma->vm_end) {
-                               mm->free_area_cache = vma->vm_start;
-                               mm->cached_hole_size = largest_hole;
-                       }
-               }
-
-               /* remember the largest hole we saw so far */
-               if (addr + largest_hole < vma->vm_start)
-                       largest_hole = vma->vm_start - addr;
-
-               /* try just below the current vma->vm_start */
-               addr = vma->vm_start-len;
-       } while (len <= vma->vm_start);
-
-fail:
-       /*
-        * if hint left us with no space for the requested
-        * mapping then try again:
-        */
-       if (first_time) {
-               mm->free_area_cache = base;
-               largest_hole = 0;
-               first_time = 0;
-               goto try_again;
-       }
-       /*
-        * A failed mmap() very likely causes application failure,
-        * so fall back to the bottom-up function here. This scenario
-        * can happen with large stack limits and large mmap()
-        * allocations.
-        */
-       mm->free_area_cache = TASK_UNMAPPED_BASE;
-       mm->cached_hole_size = ~0UL;
-       addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
-       /*
-        * Restore the topdown base:
-        */
-       mm->free_area_cache = base;
-       mm->cached_hole_size = ~0UL;
-
-       return addr;
-}
-
-static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
-{
-       struct vm_area_struct *vma;
-
-       vma = find_vma(current->mm, addr);
-       if (TASK_SIZE - len >= addr &&
-           (!vma || ((addr + len) <= vma->vm_start)))
-               return 0;
-
-       return -ENOMEM;
-}
-
-static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
-{
-       unsigned long addr = 0;
-       struct vm_area_struct *vma;
-
-       vma = find_vma(current->mm, addr);
-       while (addr + len <= 0x100000000UL) {
-               BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-               if (! __within_hugepage_low_range(addr, len, segmask)) {
-                       addr = ALIGN(addr+1, 1<<SID_SHIFT);
-                       vma = find_vma(current->mm, addr);
-                       continue;
-               }
-
-               if (!vma || (addr + len) <= vma->vm_start)
-                       return addr;
-               addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-               /* Depending on segmask this might not be a confirmed
-                * hugepage region, so the ALIGN could have skipped
-                * some VMAs */
-               vma = find_vma(current->mm, addr);
-       }
-
-       return -ENOMEM;
-}
-
-static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
-{
-       unsigned long addr = 0x100000000UL;
-       struct vm_area_struct *vma;
-
-       vma = find_vma(current->mm, addr);
-       while (addr + len <= TASK_SIZE_USER64) {
-               BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
-               if (! __within_hugepage_high_range(addr, len, areamask)) {
-                       addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
-                       vma = find_vma(current->mm, addr);
-                       continue;
-               }
-
-               if (!vma || (addr + len) <= vma->vm_start)
-                       return addr;
-               addr = ALIGN(vma->vm_end, HPAGE_SIZE);
-               /* Depending on segmask this might not be a confirmed
-                * hugepage region, so the ALIGN could have skipped
-                * some VMAs */
-               vma = find_vma(current->mm, addr);
-       }
-
-       return -ENOMEM;
-}
 
 unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
                                        unsigned long len, unsigned long pgoff,
                                        unsigned long flags)
 {
-       int lastshift;
-       u16 areamask, curareas;
-
-       if (HPAGE_SHIFT == 0)
-               return -EINVAL;
-       if (len & ~HPAGE_MASK)
-               return -EINVAL;
-       if (len > TASK_SIZE)
-               return -ENOMEM;
-
-       if (!cpu_has_feature(CPU_FTR_16M_PAGE))
-               return -EINVAL;
-
-       /* Paranoia, caller should have dealt with this */
-       BUG_ON((addr + len)  < addr);
-
-       /* Handle MAP_FIXED */
-       if (flags & MAP_FIXED) {
-               if (prepare_hugepage_range(addr, len, pgoff))
-                       return -EINVAL;
-               return addr;
-       }
-
-       if (test_thread_flag(TIF_32BIT)) {
-               curareas = current->mm->context.low_htlb_areas;
-
-               /* First see if we can use the hint address */
-               if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
-                       areamask = LOW_ESID_MASK(addr, len);
-                       if (open_low_hpage_areas(current->mm, areamask) == 0)
-                               return addr;
-               }
-
-               /* Next see if we can map in the existing low areas */
-               addr = htlb_get_low_area(len, curareas);
-               if (addr != -ENOMEM)
-                       return addr;
-
-               /* Finally go looking for areas to open */
-               lastshift = 0;
-               for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
-                    ! lastshift; areamask >>=1) {
-                       if (areamask & 1)
-                               lastshift = 1;
-
-                       addr = htlb_get_low_area(len, curareas | areamask);
-                       if ((addr != -ENOMEM)
-                           && open_low_hpage_areas(current->mm, areamask) == 0)
-                               return addr;
-               }
-       } else {
-               curareas = current->mm->context.high_htlb_areas;
-
-               /* First see if we can use the hint address */
-               /* We discourage 64-bit processes from doing hugepage
-                * mappings below 4GB (must use MAP_FIXED) */
-               if ((addr >= 0x100000000UL)
-                   && (htlb_check_hinted_area(addr, len) == 0)) {
-                       areamask = HTLB_AREA_MASK(addr, len);
-                       if (open_high_hpage_areas(current->mm, areamask) == 0)
-                               return addr;
-               }
-
-               /* Next see if we can map in the existing high areas */
-               addr = htlb_get_high_area(len, curareas);
-               if (addr != -ENOMEM)
-                       return addr;
-
-               /* Finally go looking for areas to open */
-               lastshift = 0;
-               for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
-                    ! lastshift; areamask >>=1) {
-                       if (areamask & 1)
-                               lastshift = 1;
-
-                       addr = htlb_get_high_area(len, curareas | areamask);
-                       if ((addr != -ENOMEM)
-                           && open_high_hpage_areas(current->mm, areamask) == 0)
-                               return addr;
-               }
-       }
-       printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
-              " enough areas\n");
-       return -ENOMEM;
+       return slice_get_unmapped_area(addr, len, flags,
+                                      mmu_huge_psize, 1, 0);
 }
 
 /*
index fe1fe852181ae7558c5de961a672d4b3f3226c50..7312a265545f3e2f3b675595c17e6c46c44d5bbc 100644 (file)
@@ -146,21 +146,16 @@ static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
        memset(addr, 0, kmem_cache_size(cache));
 }
 
-#ifdef CONFIG_PPC_64K_PAGES
-static const unsigned int pgtable_cache_size[3] = {
-       PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-       "pte_pmd_cache", "pmd_cache", "pgd_cache",
-};
-#else
 static const unsigned int pgtable_cache_size[2] = {
-       PTE_TABLE_SIZE, PMD_TABLE_SIZE
+       PGD_TABLE_SIZE, PMD_TABLE_SIZE
 };
 static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
-       "pgd_pte_cache", "pud_pmd_cache",
-};
+#ifdef CONFIG_PPC_64K_PAGES
+       "pgd_cache", "pmd_cache",
+#else
+       "pgd_cache", "pud_pmd_cache",
 #endif /* CONFIG_PPC_64K_PAGES */
+};
 
 #ifdef CONFIG_HUGETLB_PAGE
 /* Hugepages need one extra cache, initialized in hugetlbpage.c.  We
index 1a6e08f3298f8fa9ccc00910ab97a551136f9577..246eeea40ecec4ba0e5884fe114508bcab70dad9 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/highmem.h>
 #include <linux/initrd.h>
 #include <linux/pagemap.h>
+#include <linux/suspend.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -276,6 +277,28 @@ void __init do_init_bootmem(void)
        init_bootmem_done = 1;
 }
 
+/* mark pages that don't exist as nosave */
+static int __init mark_nonram_nosave(void)
+{
+       unsigned long lmb_next_region_start_pfn,
+                     lmb_region_max_pfn;
+       int i;
+
+       for (i = 0; i < lmb.memory.cnt - 1; i++) {
+               lmb_region_max_pfn =
+                       (lmb.memory.region[i].base >> PAGE_SHIFT) +
+                       (lmb.memory.region[i].size >> PAGE_SHIFT);
+               lmb_next_region_start_pfn =
+                       lmb.memory.region[i+1].base >> PAGE_SHIFT;
+
+               if (lmb_region_max_pfn < lmb_next_region_start_pfn)
+                       register_nosave_region(lmb_region_max_pfn,
+                                              lmb_next_region_start_pfn);
+       }
+
+       return 0;
+}
+
 /*
  * paging_init() sets up the page tables - in fact we've already done this.
  */
@@ -307,6 +330,8 @@ void __init paging_init(void)
        max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
 #endif
        free_area_init_nodes(max_zone_pfns);
+
+       mark_nonram_nosave();
 }
 #endif /* ! CONFIG_NEED_MULTIPLE_NODES */
 
index 90a06ac02d5e5f35f44adf4366cc016b473463ee..7a78cdc0515a283cd13a6487b558adea435caf8b 100644 (file)
@@ -28,6 +28,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
        int index;
        int err;
+       int new_context = (mm->context.id == 0);
 
 again:
        if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
@@ -50,9 +51,18 @@ again:
        }
 
        mm->context.id = index;
+#ifdef CONFIG_PPC_MM_SLICES
+       /* The old code would re-promote on fork, we don't do that
+        * when using slices as it could cause problem promoting slices
+        * that have been forced down to 4K
+        */
+       if (new_context)
+               slice_set_user_psize(mm, mmu_virtual_psize);
+#else
        mm->context.user_psize = mmu_virtual_psize;
        mm->context.sllp = SLB_VSID_USER |
                mmu_psize_defs[mmu_virtual_psize].sllp;
+#endif
 
        return 0;
 }
index b3a592b25ab3a7a18e31955af180ab6857763444..de45aa82d97b11c133fb14ccab6fbdf2e2bce450 100644 (file)
@@ -252,12 +252,15 @@ static int __cpuinit cpu_numa_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                numa_setup_cpu(lcpu);
                ret = NOTIFY_OK;
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                unmap_cpu_from_node(lcpu);
                break;
                ret = NOTIFY_OK;
index 05066674a7a02fa2b07835d3068c15e951013173..ec1421a20aaab96d94f6ea162066a95df81fd602 100644 (file)
@@ -185,7 +185,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
 
        if (Hash == 0)
                return;
-       pmd = pmd_offset(pgd_offset(mm, ea), ea);
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea);
        if (!pmd_none(*pmd))
                add_hash_page(mm->context.id, ea, pmd_val(*pmd));
 }
index 224e960650a09ce3e1face7057fd8643d58a9e0d..304375a735747cfc868f67cfba4fc6715809b6c2 100644 (file)
@@ -198,12 +198,6 @@ void slb_initialize(void)
        static int slb_encoding_inited;
        extern unsigned int *slb_miss_kernel_load_linear;
        extern unsigned int *slb_miss_kernel_load_io;
-#ifdef CONFIG_HUGETLB_PAGE
-       extern unsigned int *slb_miss_user_load_huge;
-       unsigned long huge_llp;
-
-       huge_llp = mmu_psize_defs[mmu_huge_psize].sllp;
-#endif
 
        /* Prepare our SLB miss handler based on our page size */
        linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
@@ -220,11 +214,6 @@ void slb_initialize(void)
 
                DBG("SLB: linear  LLP = %04x\n", linear_llp);
                DBG("SLB: io      LLP = %04x\n", io_llp);
-#ifdef CONFIG_HUGETLB_PAGE
-               patch_slb_encoding(slb_miss_user_load_huge,
-                                  SLB_VSID_USER | huge_llp);
-               DBG("SLB: huge    LLP = %04x\n", huge_llp);
-#endif
        }
 
        get_paca()->stab_rr = SLB_NUM_BOLTED;
index b10e4707d7c1396f858f43ba4f9f30eb6d233072..cd1a93d4948ca85868dd943a60667f541229a26e 100644 (file)
@@ -82,31 +82,45 @@ _GLOBAL(slb_miss_kernel_load_io)
        srdi.   r9,r10,USER_ESID_BITS
        bne-    8f                      /* invalid ea bits set */
 
-       /* Figure out if the segment contains huge pages */
-#ifdef CONFIG_HUGETLB_PAGE
-BEGIN_FTR_SECTION
-       b       1f
-END_FTR_SECTION_IFCLR(CPU_FTR_16M_PAGE)
+
+       /* when using slices, we extract the psize off the slice bitmaps
+        * and then we need to get the sllp encoding off the mmu_psize_defs
+        * array.
+        *
+        * XXX This is a bit inefficient especially for the normal case,
+        * so we should try to implement a fast path for the standard page
+        * size using the old sllp value so we avoid the array. We cannot
+        * really do dynamic patching unfortunately as processes might flip
+        * between 4k and 64k standard page size
+        */
+#ifdef CONFIG_PPC_MM_SLICES
        cmpldi  r10,16
 
-       lhz     r9,PACALOWHTLBAREAS(r13)
-       mr      r11,r10
+       /* Get the slice index * 4 in r11 and matching slice size mask in r9 */
+       ld      r9,PACALOWSLICESPSIZE(r13)
+       sldi    r11,r10,2
        blt     5f
+       ld      r9,PACAHIGHSLICEPSIZE(r13)
+       srdi    r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2)
+       andi.   r11,r11,0x3c
 
-       lhz     r9,PACAHIGHHTLBAREAS(r13)
-       srdi    r11,r10,(HTLB_AREA_SHIFT-SID_SHIFT)
-
-5:     srd     r9,r9,r11
-       andi.   r9,r9,1
-       beq     1f
-_GLOBAL(slb_miss_user_load_huge)
-       li      r11,0
-       b       2f
-1:
-#endif /* CONFIG_HUGETLB_PAGE */
+5:     /* Extract the psize and multiply to get an array offset */
+       srd     r9,r9,r11
+       andi.   r9,r9,0xf
+       mulli   r9,r9,MMUPSIZEDEFSIZE
 
+       /* Now get to the array and obtain the sllp
+        */
+       ld      r11,PACATOC(r13)
+       ld      r11,mmu_psize_defs@got(r11)
+       add     r11,r11,r9
+       ld      r11,MMUPSIZESLLP(r11)
+       ori     r11,r11,SLB_VSID_USER
+#else
+       /* paca context sllp already contains the SLB_VSID_USER bits */
        lhz     r11,PACACONTEXTSLLP(r13)
-2:
+#endif /* CONFIG_PPC_MM_SLICES */
+
        ld      r9,PACACONTEXTID(r13)
        rldimi  r10,r9,USER_ESID_BITS,0
        b       slb_finish_load
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
new file mode 100644 (file)
index 0000000..f833dba
--- /dev/null
@@ -0,0 +1,633 @@
+/*
+ * address space "slices" (meta-segments) support
+ *
+ * Copyright (C) 2007 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * Based on hugetlb implementation
+ *
+ * Copyright (C) 2003 David Gibson, IBM Corporation.
+ *
+ * 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
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/mman.h>
+#include <asm/mmu.h>
+#include <asm/spu.h>
+
+static spinlock_t slice_convert_lock = SPIN_LOCK_UNLOCKED;
+
+
+#ifdef DEBUG
+int _slice_debug = 1;
+
+static void slice_print_mask(const char *label, struct slice_mask mask)
+{
+       char    *p, buf[16 + 3 + 16 + 1];
+       int     i;
+
+       if (!_slice_debug)
+               return;
+       p = buf;
+       for (i = 0; i < SLICE_NUM_LOW; i++)
+               *(p++) = (mask.low_slices & (1 << i)) ? '1' : '0';
+       *(p++) = ' ';
+       *(p++) = '-';
+       *(p++) = ' ';
+       for (i = 0; i < SLICE_NUM_HIGH; i++)
+               *(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';
+       *(p++) = 0;
+
+       printk(KERN_DEBUG "%s:%s\n", label, buf);
+}
+
+#define slice_dbg(fmt...) do { if (_slice_debug) pr_debug(fmt); } while(0)
+
+#else
+
+static void slice_print_mask(const char *label, struct slice_mask mask) {}
+#define slice_dbg(fmt...)
+
+#endif
+
+static struct slice_mask slice_range_to_mask(unsigned long start,
+                                            unsigned long len)
+{
+       unsigned long end = start + len - 1;
+       struct slice_mask ret = { 0, 0 };
+
+       if (start < SLICE_LOW_TOP) {
+               unsigned long mend = min(end, SLICE_LOW_TOP);
+               unsigned long mstart = min(start, SLICE_LOW_TOP);
+
+               ret.low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
+                       - (1u << GET_LOW_SLICE_INDEX(mstart));
+       }
+
+       if ((start + len) > SLICE_LOW_TOP)
+               ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))
+                       - (1u << GET_HIGH_SLICE_INDEX(start));
+
+       return ret;
+}
+
+static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
+                             unsigned long len)
+{
+       struct vm_area_struct *vma;
+
+       if ((mm->task_size - len) < addr)
+               return 0;
+       vma = find_vma(mm, addr);
+       return (!vma || (addr + len) <= vma->vm_start);
+}
+
+static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+       return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,
+                                  1ul << SLICE_LOW_SHIFT);
+}
+
+static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+       unsigned long start = slice << SLICE_HIGH_SHIFT;
+       unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);
+
+       /* Hack, so that each addresses is controlled by exactly one
+        * of the high or low area bitmaps, the first high area starts
+        * at 4GB, not 0 */
+       if (start == 0)
+               start = SLICE_LOW_TOP;
+
+       return !slice_area_is_free(mm, start, end - start);
+}
+
+static struct slice_mask slice_mask_for_free(struct mm_struct *mm)
+{
+       struct slice_mask ret = { 0, 0 };
+       unsigned long i;
+
+       for (i = 0; i < SLICE_NUM_LOW; i++)
+               if (!slice_low_has_vma(mm, i))
+                       ret.low_slices |= 1u << i;
+
+       if (mm->task_size <= SLICE_LOW_TOP)
+               return ret;
+
+       for (i = 0; i < SLICE_NUM_HIGH; i++)
+               if (!slice_high_has_vma(mm, i))
+                       ret.high_slices |= 1u << i;
+
+       return ret;
+}
+
+static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize)
+{
+       struct slice_mask ret = { 0, 0 };
+       unsigned long i;
+       u64 psizes;
+
+       psizes = mm->context.low_slices_psize;
+       for (i = 0; i < SLICE_NUM_LOW; i++)
+               if (((psizes >> (i * 4)) & 0xf) == psize)
+                       ret.low_slices |= 1u << i;
+
+       psizes = mm->context.high_slices_psize;
+       for (i = 0; i < SLICE_NUM_HIGH; i++)
+               if (((psizes >> (i * 4)) & 0xf) == psize)
+                       ret.high_slices |= 1u << i;
+
+       return ret;
+}
+
+static int slice_check_fit(struct slice_mask mask, struct slice_mask available)
+{
+       return (mask.low_slices & available.low_slices) == mask.low_slices &&
+               (mask.high_slices & available.high_slices) == mask.high_slices;
+}
+
+static void slice_flush_segments(void *parm)
+{
+       struct mm_struct *mm = parm;
+       unsigned long flags;
+
+       if (mm != current->active_mm)
+               return;
+
+       /* update the paca copy of the context struct */
+       get_paca()->context = current->active_mm->context;
+
+       local_irq_save(flags);
+       slb_flush_and_rebolt();
+       local_irq_restore(flags);
+}
+
+static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize)
+{
+       /* Write the new slice psize bits */
+       u64 lpsizes, hpsizes;
+       unsigned long i, flags;
+
+       slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);
+       slice_print_mask(" mask", mask);
+
+       /* We need to use a spinlock here to protect against
+        * concurrent 64k -> 4k demotion ...
+        */
+       spin_lock_irqsave(&slice_convert_lock, flags);
+
+       lpsizes = mm->context.low_slices_psize;
+       for (i = 0; i < SLICE_NUM_LOW; i++)
+               if (mask.low_slices & (1u << i))
+                       lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+                               (((unsigned long)psize) << (i * 4));
+
+       hpsizes = mm->context.high_slices_psize;
+       for (i = 0; i < SLICE_NUM_HIGH; i++)
+               if (mask.high_slices & (1u << i))
+                       hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+                               (((unsigned long)psize) << (i * 4));
+
+       mm->context.low_slices_psize = lpsizes;
+       mm->context.high_slices_psize = hpsizes;
+
+       slice_dbg(" lsps=%lx, hsps=%lx\n",
+                 mm->context.low_slices_psize,
+                 mm->context.high_slices_psize);
+
+       spin_unlock_irqrestore(&slice_convert_lock, flags);
+       mb();
+
+       /* XXX this is sub-optimal but will do for now */
+       on_each_cpu(slice_flush_segments, mm, 0, 1);
+#ifdef CONFIG_SPU_BASE
+       spu_flush_all_slbs(mm);
+#endif
+}
+
+static unsigned long slice_find_area_bottomup(struct mm_struct *mm,
+                                             unsigned long len,
+                                             struct slice_mask available,
+                                             int psize, int use_cache)
+{
+       struct vm_area_struct *vma;
+       unsigned long start_addr, addr;
+       struct slice_mask mask;
+       int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+       if (use_cache) {
+               if (len <= mm->cached_hole_size) {
+                       start_addr = addr = TASK_UNMAPPED_BASE;
+                       mm->cached_hole_size = 0;
+               } else
+                       start_addr = addr = mm->free_area_cache;
+       } else
+               start_addr = addr = TASK_UNMAPPED_BASE;
+
+full_search:
+       for (;;) {
+               addr = _ALIGN_UP(addr, 1ul << pshift);
+               if ((TASK_SIZE - len) < addr)
+                       break;
+               vma = find_vma(mm, addr);
+               BUG_ON(vma && (addr >= vma->vm_end));
+
+               mask = slice_range_to_mask(addr, len);
+               if (!slice_check_fit(mask, available)) {
+                       if (addr < SLICE_LOW_TOP)
+                               addr = _ALIGN_UP(addr + 1,  1ul << SLICE_LOW_SHIFT);
+                       else
+                               addr = _ALIGN_UP(addr + 1,  1ul << SLICE_HIGH_SHIFT);
+                       continue;
+               }
+               if (!vma || addr + len <= vma->vm_start) {
+                       /*
+                        * Remember the place where we stopped the search:
+                        */
+                       if (use_cache)
+                               mm->free_area_cache = addr + len;
+                       return addr;
+               }
+               if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+                       mm->cached_hole_size = vma->vm_start - addr;
+               addr = vma->vm_end;
+       }
+
+       /* Make sure we didn't miss any holes */
+       if (use_cache && start_addr != TASK_UNMAPPED_BASE) {
+               start_addr = addr = TASK_UNMAPPED_BASE;
+               mm->cached_hole_size = 0;
+               goto full_search;
+       }
+       return -ENOMEM;
+}
+
+static unsigned long slice_find_area_topdown(struct mm_struct *mm,
+                                            unsigned long len,
+                                            struct slice_mask available,
+                                            int psize, int use_cache)
+{
+       struct vm_area_struct *vma;
+       unsigned long addr;
+       struct slice_mask mask;
+       int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+       /* check if free_area_cache is useful for us */
+       if (use_cache) {
+               if (len <= mm->cached_hole_size) {
+                       mm->cached_hole_size = 0;
+                       mm->free_area_cache = mm->mmap_base;
+               }
+
+               /* either no address requested or can't fit in requested
+                * address hole
+                */
+               addr = mm->free_area_cache;
+
+               /* make sure it can fit in the remaining address space */
+               if (addr > len) {
+                       addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+                       mask = slice_range_to_mask(addr, len);
+                       if (slice_check_fit(mask, available) &&
+                           slice_area_is_free(mm, addr, len))
+                                       /* remember the address as a hint for
+                                        * next time
+                                        */
+                                       return (mm->free_area_cache = addr);
+               }
+       }
+
+       addr = mm->mmap_base;
+       while (addr > len) {
+               /* Go down by chunk size */
+               addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+
+               /* Check for hit with different page size */
+               mask = slice_range_to_mask(addr, len);
+               if (!slice_check_fit(mask, available)) {
+                       if (addr < SLICE_LOW_TOP)
+                               addr = _ALIGN_DOWN(addr, 1ul << SLICE_LOW_SHIFT);
+                       else if (addr < (1ul << SLICE_HIGH_SHIFT))
+                               addr = SLICE_LOW_TOP;
+                       else
+                               addr = _ALIGN_DOWN(addr, 1ul << SLICE_HIGH_SHIFT);
+                       continue;
+               }
+
+               /*
+                * Lookup failure means no vma is above this address,
+                * else if new region fits below vma->vm_start,
+                * return with success:
+                */
+               vma = find_vma(mm, addr);
+               if (!vma || (addr + len) <= vma->vm_start) {
+                       /* remember the address as a hint for next time */
+                       if (use_cache)
+                               mm->free_area_cache = addr;
+                       return addr;
+               }
+
+               /* remember the largest hole we saw so far */
+               if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+                       mm->cached_hole_size = vma->vm_start - addr;
+
+               /* try just below the current vma->vm_start */
+               addr = vma->vm_start;
+       }
+
+       /*
+        * A failed mmap() very likely causes application failure,
+        * so fall back to the bottom-up function here. This scenario
+        * can happen with large stack limits and large mmap()
+        * allocations.
+        */
+       addr = slice_find_area_bottomup(mm, len, available, psize, 0);
+
+       /*
+        * Restore the topdown base:
+        */
+       if (use_cache) {
+               mm->free_area_cache = mm->mmap_base;
+               mm->cached_hole_size = ~0UL;
+       }
+
+       return addr;
+}
+
+
+static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len,
+                                    struct slice_mask mask, int psize,
+                                    int topdown, int use_cache)
+{
+       if (topdown)
+               return slice_find_area_topdown(mm, len, mask, psize, use_cache);
+       else
+               return slice_find_area_bottomup(mm, len, mask, psize, use_cache);
+}
+
+unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
+                                     unsigned long flags, unsigned int psize,
+                                     int topdown, int use_cache)
+{
+       struct slice_mask mask;
+       struct slice_mask good_mask;
+       struct slice_mask potential_mask = {0,0} /* silence stupid warning */;
+       int pmask_set = 0;
+       int fixed = (flags & MAP_FIXED);
+       int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+       struct mm_struct *mm = current->mm;
+
+       /* Sanity checks */
+       BUG_ON(mm->task_size == 0);
+
+       slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
+       slice_dbg(" addr=%lx, len=%lx, flags=%lx, topdown=%d, use_cache=%d\n",
+                 addr, len, flags, topdown, use_cache);
+
+       if (len > mm->task_size)
+               return -ENOMEM;
+       if (fixed && (addr & ((1ul << pshift) - 1)))
+               return -EINVAL;
+       if (fixed && addr > (mm->task_size - len))
+               return -EINVAL;
+
+       /* If hint, make sure it matches our alignment restrictions */
+       if (!fixed && addr) {
+               addr = _ALIGN_UP(addr, 1ul << pshift);
+               slice_dbg(" aligned addr=%lx\n", addr);
+       }
+
+       /* First makeup a "good" mask of slices that have the right size
+        * already
+        */
+       good_mask = slice_mask_for_size(mm, psize);
+       slice_print_mask(" good_mask", good_mask);
+
+       /* First check hint if it's valid or if we have MAP_FIXED */
+       if ((addr != 0 || fixed) && (mm->task_size - len) >= addr) {
+
+               /* Don't bother with hint if it overlaps a VMA */
+               if (!fixed && !slice_area_is_free(mm, addr, len))
+                       goto search;
+
+               /* Build a mask for the requested range */
+               mask = slice_range_to_mask(addr, len);
+               slice_print_mask(" mask", mask);
+
+               /* Check if we fit in the good mask. If we do, we just return,
+                * nothing else to do
+                */
+               if (slice_check_fit(mask, good_mask)) {
+                       slice_dbg(" fits good !\n");
+                       return addr;
+               }
+
+               /* We don't fit in the good mask, check what other slices are
+                * empty and thus can be converted
+                */
+               potential_mask = slice_mask_for_free(mm);
+               potential_mask.low_slices |= good_mask.low_slices;
+               potential_mask.high_slices |= good_mask.high_slices;
+               pmask_set = 1;
+               slice_print_mask(" potential", potential_mask);
+               if (slice_check_fit(mask, potential_mask)) {
+                       slice_dbg(" fits potential !\n");
+                       goto convert;
+               }
+       }
+
+       /* If we have MAP_FIXED and failed the above step, then error out */
+       if (fixed)
+               return -EBUSY;
+
+ search:
+       slice_dbg(" search...\n");
+
+       /* Now let's see if we can find something in the existing slices
+        * for that size
+        */
+       addr = slice_find_area(mm, len, good_mask, psize, topdown, use_cache);
+       if (addr != -ENOMEM) {
+               /* Found within the good mask, we don't have to setup,
+                * we thus return directly
+                */
+               slice_dbg(" found area at 0x%lx\n", addr);
+               return addr;
+       }
+
+       /* Won't fit, check what can be converted */
+       if (!pmask_set) {
+               potential_mask = slice_mask_for_free(mm);
+               potential_mask.low_slices |= good_mask.low_slices;
+               potential_mask.high_slices |= good_mask.high_slices;
+               pmask_set = 1;
+               slice_print_mask(" potential", potential_mask);
+       }
+
+       /* Now let's see if we can find something in the existing slices
+        * for that size
+        */
+       addr = slice_find_area(mm, len, potential_mask, psize, topdown,
+                              use_cache);
+       if (addr == -ENOMEM)
+               return -ENOMEM;
+
+       mask = slice_range_to_mask(addr, len);
+       slice_dbg(" found potential area at 0x%lx\n", addr);
+       slice_print_mask(" mask", mask);
+
+ convert:
+       slice_convert(mm, mask, psize);
+       return addr;
+
+}
+EXPORT_SYMBOL_GPL(slice_get_unmapped_area);
+
+unsigned long arch_get_unmapped_area(struct file *filp,
+                                    unsigned long addr,
+                                    unsigned long len,
+                                    unsigned long pgoff,
+                                    unsigned long flags)
+{
+       return slice_get_unmapped_area(addr, len, flags,
+                                      current->mm->context.user_psize,
+                                      0, 1);
+}
+
+unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+                                            const unsigned long addr0,
+                                            const unsigned long len,
+                                            const unsigned long pgoff,
+                                            const unsigned long flags)
+{
+       return slice_get_unmapped_area(addr0, len, flags,
+                                      current->mm->context.user_psize,
+                                      1, 1);
+}
+
+unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+{
+       u64 psizes;
+       int index;
+
+       if (addr < SLICE_LOW_TOP) {
+               psizes = mm->context.low_slices_psize;
+               index = GET_LOW_SLICE_INDEX(addr);
+       } else {
+               psizes = mm->context.high_slices_psize;
+               index = GET_HIGH_SLICE_INDEX(addr);
+       }
+
+       return (psizes >> (index * 4)) & 0xf;
+}
+EXPORT_SYMBOL_GPL(get_slice_psize);
+
+/*
+ * This is called by hash_page when it needs to do a lazy conversion of
+ * an address space from real 64K pages to combo 4K pages (typically
+ * when hitting a non cacheable mapping on a processor or hypervisor
+ * that won't allow them for 64K pages).
+ *
+ * This is also called in init_new_context() to change back the user
+ * psize from whatever the parent context had it set to
+ *
+ * This function will only change the content of the {low,high)_slice_psize
+ * masks, it will not flush SLBs as this shall be handled lazily by the
+ * caller.
+ */
+void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
+{
+       unsigned long flags, lpsizes, hpsizes;
+       unsigned int old_psize;
+       int i;
+
+       slice_dbg("slice_set_user_psize(mm=%p, psize=%d)\n", mm, psize);
+
+       spin_lock_irqsave(&slice_convert_lock, flags);
+
+       old_psize = mm->context.user_psize;
+       slice_dbg(" old_psize=%d\n", old_psize);
+       if (old_psize == psize)
+               goto bail;
+
+       mm->context.user_psize = psize;
+       wmb();
+
+       lpsizes = mm->context.low_slices_psize;
+       for (i = 0; i < SLICE_NUM_LOW; i++)
+               if (((lpsizes >> (i * 4)) & 0xf) == old_psize)
+                       lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+                               (((unsigned long)psize) << (i * 4));
+
+       hpsizes = mm->context.high_slices_psize;
+       for (i = 0; i < SLICE_NUM_HIGH; i++)
+               if (((hpsizes >> (i * 4)) & 0xf) == old_psize)
+                       hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+                               (((unsigned long)psize) << (i * 4));
+
+       mm->context.low_slices_psize = lpsizes;
+       mm->context.high_slices_psize = hpsizes;
+
+       slice_dbg(" lsps=%lx, hsps=%lx\n",
+                 mm->context.low_slices_psize,
+                 mm->context.high_slices_psize);
+
+ bail:
+       spin_unlock_irqrestore(&slice_convert_lock, flags);
+}
+
+/*
+ * is_hugepage_only_range() is used by generic code to verify wether
+ * a normal mmap mapping (non hugetlbfs) is valid on a given area.
+ *
+ * until the generic code provides a more generic hook and/or starts
+ * calling arch get_unmapped_area for MAP_FIXED (which our implementation
+ * here knows how to deal with), we hijack it to keep standard mappings
+ * away from us.
+ *
+ * because of that generic code limitation, MAP_FIXED mapping cannot
+ * "convert" back a slice with no VMAs to the standard page size, only
+ * get_unmapped_area() can. It would be possible to fix it here but I
+ * prefer working on fixing the generic code instead.
+ *
+ * WARNING: This will not work if hugetlbfs isn't enabled since the
+ * generic code will redefine that function as 0 in that. This is ok
+ * for now as we only use slices with hugetlbfs enabled. This should
+ * be fixed as the generic code gets fixed.
+ */
+int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
+                          unsigned long len)
+{
+       struct slice_mask mask, available;
+
+       mask = slice_range_to_mask(addr, len);
+       available = slice_mask_for_size(mm, mm->context.user_psize);
+
+#if 0 /* too verbose */
+       slice_dbg("is_hugepage_only_range(mm=%p, addr=%lx, len=%lx)\n",
+                mm, addr, len);
+       slice_print_mask(" mask", mask);
+       slice_print_mask(" available", available);
+#endif
+       return !slice_check_fit(mask, available);
+}
+
index 925ff70be8ba93ed9133a1f123067ff8527e9c9f..6a69417cbc0ef3cf0eaba041081b2f3a53ae5f96 100644 (file)
@@ -111,7 +111,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
        if (start >= end)
                return;
        end = (end - 1) | ~PAGE_MASK;
-       pmd = pmd_offset(pgd_offset(mm, start), start);
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
        for (;;) {
                pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
                if (pmd_end > end)
@@ -169,7 +169,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
                return;
        }
        mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
-       pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
+       pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
        if (!pmd_none(*pmd))
                flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
        FINISH_FLUSH;
index fd8d08c325ebecca3083759360cbf6e6c30b1e8e..2bfc4d7e1aa259b37462735c97e299c67d5d9a3e 100644 (file)
@@ -143,16 +143,22 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
         */
        addr &= PAGE_MASK;
 
-       /* Get page size (maybe move back to caller) */
+       /* Get page size (maybe move back to caller).
+        *
+        * NOTE: when using special 64K mappings in 4K environment like
+        * for SPEs, we obtain the page size from the slice, which thus
+        * must still exist (and thus the VMA not reused) at the time
+        * of this call
+        */
        if (huge) {
 #ifdef CONFIG_HUGETLB_PAGE
                psize = mmu_huge_psize;
 #else
                BUG();
-               psize = pte_pagesize_index(pte); /* shutup gcc */
+               psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
 #endif
        } else
-               psize = pte_pagesize_index(pte);
+               psize = pte_pagesize_index(mm, addr, pte);
 
        /* Build full vaddr */
        if (!is_kernel_addr(addr)) {
index 626b29f38304e3c8339e61b52ddb619a5c5dd0f5..c29293befba9b69c0e0f673c82869e4343802230 100644 (file)
@@ -747,7 +747,7 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
                 * counter value etc.) are not copied to the actual registers
                 * until the performance monitor is enabled.  In order to get
                 * this to work as desired, the permormance monitor needs to
-                * be disabled while writting to the latches.  This is a
+                * be disabled while writing to the latches.  This is a
                 * HW design issue.
                 */
                cbe_enable_pm(cpu);
index 32e9e9492841ac600f68fb4bf07dfb35218837e3..96970ac887ee267dc2826f607298df6cf930e36c 100644 (file)
@@ -40,7 +40,9 @@ unsigned long isa_mem_base = 0;
  */
 static void __init mpc8313_rdb_setup_arch(void)
 {
+#ifdef CONFIG_PCI
        struct device_node *np;
+#endif
 
        if (ppc_md.progress)
                ppc_md.progress("mpc8313_rdb_setup_arch()", 0);
index b0b22bb29de79045f34d81e7b1f6366973fd6bcb..3db68b73fc3297a8eab6c1bff2d73cf0de3532cf 100644 (file)
@@ -44,7 +44,9 @@ unsigned long isa_mem_base = 0;
  */
 static void __init mpc832x_rdb_setup_arch(void)
 {
+#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
        struct device_node *np;
+#endif
 
        if (ppc_md.progress)
                ppc_md.progress("mpc832x_rdb_setup_arch()", 0);
index 3c009f6d4a4f12baec689d577cba7070cb76f097..40a01947d6840428733df06f316d8f0be3152904 100644 (file)
@@ -50,7 +50,9 @@ unsigned long isa_mem_base = 0;
  */
 static void __init mpc834x_itx_setup_arch(void)
 {
+#ifdef CONFIG_PCI
        struct device_node *np;
+#endif
 
        if (ppc_md.progress)
                ppc_md.progress("mpc834x_itx_setup_arch()", 0);
index 8aa9a93e2aa2c78a30c8920bd58c78e93799a7db..10394b2d7e7a0bd44cb4cc9871d7ddc30f876897 100644 (file)
@@ -120,7 +120,9 @@ static int mpc834x_usb_cfg(void)
  */
 static void __init mpc834x_mds_setup_arch(void)
 {
+#ifdef CONFIG_PCI
        struct device_node *np;
+#endif
 
        if (ppc_md.progress)
                ppc_md.progress("mpc834x_mds_setup_arch()", 0);
index 90877565caa33238f2b83514df58a7dd0d0ac1c1..1051702c8d4f48c5e2dc9bc0c01be7e913e8eb0b 100644 (file)
@@ -168,7 +168,7 @@ static void __devinit quirk_uli1575(struct pci_dev *dev)
 {
        unsigned short temp;
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
-       unsigned char irq2pin[16];
+       unsigned char irq2pin[16], c;
        unsigned long pirq_map_word = 0;
        u32 irq;
        int i;
@@ -288,6 +288,11 @@ static void __devinit quirk_uli1575(struct pci_dev *dev)
        outb(0x1e, 0x4d1);
 
 #undef ULI1575_SET_DEV_IRQ
+
+       /* Disable the HD interface and enable the AC97 interface. */
+       pci_read_config_byte(dev, 0xb8, &c);
+       c &= 0x7f;
+       pci_write_config_byte(dev, 0xb8, c);
 }
 
 static void __devinit quirk_uli5288(struct pci_dev *dev)
index 7ef0c6854799b68bc2164bce879fd86f832a52d1..ba55b0ff0f746a4c60dd848c06bfb41faa97d026 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
-#include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/pci-bridge.h>
 #include <asm-powerpc/mpic.h>
 #include <asm/mpc86xx.h>
index a35315af5c532fa84ed3a6be3580f31c2e2676a8..cf0e7bc8c2e77350749bc85e75480c83e743b5a5 100644 (file)
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc86xads-setup.c
+/*arch/powerpc/platforms/8xx/mpc86xads_setup.c
  *
  * Platform setup for the Freescale mpc86xads board
  *
index a57b57785acd854c2598251ecf1206a9646d0a6d..c36e475d93dc86d3e5dea78731d06fa728810549 100644 (file)
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc885ads-setup.c
+/*arch/powerpc/platforms/8xx/mpc885ads_setup.c
  *
  * Platform setup for the Freescale mpc885ads board
  *
index 82551770917c5e7fb66eec807550b18d4b5e029b..9b2b386ccf48aa2f6ed0650aeca471a2dad29ea3 100644 (file)
@@ -35,6 +35,21 @@ config SPU_FS
          Units on machines implementing the Broadband Processor
          Architecture.
 
+config SPU_FS_64K_LS
+       bool "Use 64K pages to map SPE local  store"
+       # we depend on PPC_MM_SLICES for now rather than selecting
+       # it because we depend on hugetlbfs hooks being present. We
+       # will fix that when the generic code has been improved to
+       # not require hijacking hugetlbfs hooks.
+       depends on SPU_FS && PPC_MM_SLICES && !PPC_64K_PAGES
+       default y
+       select PPC_HAS_HASH_64K
+       help
+         This option causes SPE local stores to be mapped in process
+         address spaces using 64K pages while the rest of the kernel
+         uses 4K pages. This can improve performances of applications
+         using multiple SPEs by lowering the TLB pressure on them.
+
 config SPU_BASE
        bool
        default n
index d68d920eb2c4e6bbe8894c3c3dc99caefb8a8fe5..7fb92f23f380a60c66a01eb7a5314ac6bbe79a93 100644 (file)
@@ -74,7 +74,7 @@ static void spider_io_flush(const volatile void __iomem *addr)
        /* Fast path if we have a non-0 token, it indicates which bus we
         * are on.
         *
-        * If the token is 0, that means either the the ioremap was done
+        * If the token is 0, that means either that the ioremap was done
         * before we initialized this layer, or it's a PIO operation. We
         * fallback to a low path in this case. Hopefully, internal devices
         * which are ioremap'ed early should use in_XX/out_XX functions
index 8c20f0fb8651f23b204f455bbf75a23581bef746..812bf563ed6509aebeb51606fe8fa068c411bc5c 100644 (file)
@@ -43,12 +43,10 @@ static void cbe_power_save(void)
        unsigned long ctrl, thread_switch_control;
 
        /*
-        * We need to hard disable interrupts, but we also need to mark them
-        * hard disabled in the PACA so that the local_irq_enable() done by
-        * our caller upon return propertly hard enables.
+        * We need to hard disable interrupts, the local_irq_enable() done by
+        * our caller upon return will hard re-enable.
         */
        hard_irq_disable();
-       get_paca()->hard_enabled = 0;
 
        ctrl = mfspr(SPRN_CTRLF);
 
index fec51525252e2dfba33d8bb0c860bbbc0630d974..a7f5a7653c62e19149fd9d8865d6e0bc2c3aa890 100644 (file)
@@ -144,12 +144,11 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
 
        switch(REGION_ID(ea)) {
        case USER_REGION_ID:
-#ifdef CONFIG_HUGETLB_PAGE
-               if (in_hugepage_area(mm->context, ea))
-                       psize = mmu_huge_psize;
-               else
+#ifdef CONFIG_PPC_MM_SLICES
+               psize = get_slice_psize(mm, ea);
+#else
+               psize = mm->context.user_psize;
 #endif
-                       psize = mm->context.user_psize;
                vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
                                SLB_VSID_USER;
                break;
index 2cd89c11af5ac328209cdbcf7a0b76dcdd7c196c..328afcf895032e50a7f36b0a7f00a38d3ca7aade 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += switch.o fault.o
+obj-y += switch.o fault.o lscsa_alloc.o
 
 obj-$(CONFIG_SPU_FS) += spufs.o
 spufs-y += inode.o file.o context.o syscalls.o coredump.o
index a87d9ca3dba26c926822f068e7e8ea0055cb60ba..8654749e317bae0aa67795dda4ba2eebdae50c3f 100644 (file)
@@ -36,10 +36,8 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        /* Binding to physical processor deferred
         * until spu_activate().
         */
-       spu_init_csa(&ctx->csa);
-       if (!ctx->csa.lscsa) {
+       if (spu_init_csa(&ctx->csa))
                goto out_free;
-       }
        spin_lock_init(&ctx->mmio_lock);
        spin_lock_init(&ctx->mapping_lock);
        kref_init(&ctx->kref);
index d010b2464a98cf3df710a4e5a9dc150c827506e8..45614c73c7841824d1a1f47834ebc2838bfbbe0a 100644 (file)
@@ -118,14 +118,32 @@ spufs_mem_write(struct file *file, const char __user *buffer,
 static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
                                          unsigned long address)
 {
-       struct spu_context *ctx = vma->vm_file->private_data;
-       unsigned long pfn, offset = address - vma->vm_start;
-
-       offset += vma->vm_pgoff << PAGE_SHIFT;
+       struct spu_context *ctx = vma->vm_file->private_data;
+       unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+       struct spu_state *csa = &ctx->csa;
+       int psize;
+
+       /* Check what page size we are using */
+       psize = get_slice_psize(vma->vm_mm, address);
+
+       /* Some sanity checking */
+       BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+       /* Wow, 64K, cool, we need to align the address though */
+       if (csa->use_big_pages) {
+               BUG_ON(vma->vm_start & 0xffff);
+               address &= ~0xfffful;
+       }
+#endif /* CONFIG_SPU_FS_64K_LS */
 
+       offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
        if (offset >= LS_SIZE)
                return NOPFN_SIGBUS;
 
+       pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+                addr0, address, offset);
+
        spu_acquire(ctx);
 
        if (ctx->state == SPU_STATE_SAVED) {
@@ -149,9 +167,24 @@ static struct vm_operations_struct spufs_mem_mmap_vmops = {
        .nopfn = spufs_mem_mmap_nopfn,
 };
 
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
-{
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_SPU_FS_64K_LS
+       struct spu_context      *ctx = file->private_data;
+       struct spu_state        *csa = &ctx->csa;
+
+       /* Sanity check VMA alignment */
+       if (csa->use_big_pages) {
+               pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+                        " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+                        vma->vm_pgoff);
+               if (vma->vm_start & 0xffff)
+                       return -EINVAL;
+               if (vma->vm_pgoff & 0xf)
+                       return -EINVAL;
+       }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
        if (!(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
@@ -163,13 +196,34 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+                                     unsigned long len, unsigned long pgoff,
+                                     unsigned long flags)
+{
+       struct spu_context      *ctx = file->private_data;
+       struct spu_state        *csa = &ctx->csa;
+
+       /* If not using big pages, fallback to normal MM g_u_a */
+       if (!csa->use_big_pages)
+               return current->mm->get_unmapped_area(file, addr, len,
+                                                     pgoff, flags);
+
+       /* Else, try to obtain a 64K pages slice */
+       return slice_get_unmapped_area(addr, len, flags,
+                                      MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 static const struct file_operations spufs_mem_fops = {
-       .open    = spufs_mem_open,
-       .release = spufs_mem_release,
-       .read    = spufs_mem_read,
-       .write   = spufs_mem_write,
-       .llseek  = generic_file_llseek,
-       .mmap    = spufs_mem_mmap,
+       .open                   = spufs_mem_open,
+       .read                   = spufs_mem_read,
+       .write                  = spufs_mem_write,
+       .llseek                 = generic_file_llseek,
+       .mmap                   = spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+       .get_unmapped_area      = spufs_get_unmapped_area,
+#endif
 };
 
 static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
diff --git a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
new file mode 100644 (file)
index 0000000..f4b3c05
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * SPU local store allocation routines
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu.h>
+
+static int spu_alloc_lscsa_std(struct spu_state *csa)
+{
+       struct spu_lscsa *lscsa;
+       unsigned char *p;
+
+       lscsa = vmalloc(sizeof(struct spu_lscsa));
+       if (!lscsa)
+               return -ENOMEM;
+       memset(lscsa, 0, sizeof(struct spu_lscsa));
+       csa->lscsa = lscsa;
+
+       /* Set LS pages reserved to allow for user-space mapping. */
+       for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               SetPageReserved(vmalloc_to_page(p));
+
+       return 0;
+}
+
+static void spu_free_lscsa_std(struct spu_state *csa)
+{
+       /* Clear reserved bit before vfree. */
+       unsigned char *p;
+
+       if (csa->lscsa == NULL)
+               return;
+
+       for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               ClearPageReserved(vmalloc_to_page(p));
+
+       vfree(csa->lscsa);
+}
+
+#ifdef CONFIG_SPU_FS_64K_LS
+
+#define SPU_64K_PAGE_SHIFT     16
+#define SPU_64K_PAGE_ORDER     (SPU_64K_PAGE_SHIFT - PAGE_SHIFT)
+#define SPU_64K_PAGE_COUNT     (1ul << SPU_64K_PAGE_ORDER)
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+       struct page     **pgarray;
+       unsigned char   *p;
+       int             i, j, n_4k;
+
+       /* Check availability of 64K pages */
+       if (mmu_psize_defs[MMU_PAGE_64K].shift == 0)
+               goto fail;
+
+       csa->use_big_pages = 1;
+
+       pr_debug("spu_alloc_lscsa(csa=0x%p), trying to allocate 64K pages\n",
+                csa);
+
+       /* First try to allocate our 64K pages. We need 5 of them
+        * with the current implementation. In the future, we should try
+        * to separate the lscsa with the actual local store image, thus
+        * allowing us to require only 4 64K pages per context
+        */
+       for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) {
+               /* XXX This is likely to fail, we should use a special pool
+                *     similiar to what hugetlbfs does.
+                */
+               csa->lscsa_pages[i] = alloc_pages(GFP_KERNEL,
+                                                 SPU_64K_PAGE_ORDER);
+               if (csa->lscsa_pages[i] == NULL)
+                       goto fail;
+       }
+
+       pr_debug(" success ! creating vmap...\n");
+
+       /* Now we need to create a vmalloc mapping of these for the kernel
+        * and SPU context switch code to use. Currently, we stick to a
+        * normal kernel vmalloc mapping, which in our case will be 4K
+        */
+       n_4k = SPU_64K_PAGE_COUNT * SPU_LSCSA_NUM_BIG_PAGES;
+       pgarray = kmalloc(sizeof(struct page *) * n_4k, GFP_KERNEL);
+       if (pgarray == NULL)
+               goto fail;
+       for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+               for (j = 0; j < SPU_64K_PAGE_COUNT; j++)
+                       /* We assume all the struct page's are contiguous
+                        * which should be hopefully the case for an order 4
+                        * allocation..
+                        */
+                       pgarray[i * SPU_64K_PAGE_COUNT + j] =
+                               csa->lscsa_pages[i] + j;
+       csa->lscsa = vmap(pgarray, n_4k, VM_USERMAP, PAGE_KERNEL);
+       kfree(pgarray);
+       if (csa->lscsa == NULL)
+               goto fail;
+
+       memset(csa->lscsa, 0, sizeof(struct spu_lscsa));
+
+       /* Set LS pages reserved to allow for user-space mapping.
+        *
+        * XXX isn't that a bit obsolete ? I think we should just
+        * make sure the page count is high enough. Anyway, won't harm
+        * for now
+        */
+       for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               SetPageReserved(vmalloc_to_page(p));
+
+       pr_debug(" all good !\n");
+
+       return 0;
+fail:
+       pr_debug("spufs: failed to allocate lscsa 64K pages, falling back\n");
+       spu_free_lscsa(csa);
+       return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+       unsigned char *p;
+       int i;
+
+       if (!csa->use_big_pages) {
+               spu_free_lscsa_std(csa);
+               return;
+       }
+       csa->use_big_pages = 0;
+
+       if (csa->lscsa == NULL)
+               goto free_pages;
+
+       for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+               ClearPageReserved(vmalloc_to_page(p));
+
+       vunmap(csa->lscsa);
+       csa->lscsa = NULL;
+
+ free_pages:
+
+       for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+               if (csa->lscsa_pages[i])
+                       __free_pages(csa->lscsa_pages[i], SPU_64K_PAGE_ORDER);
+}
+
+#else /* CONFIG_SPU_FS_64K_LS */
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+       return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+       spu_free_lscsa_std(csa);
+}
+
+#endif /* !defined(CONFIG_SPU_FS_64K_LS) */
index 29dc59cefc38b52aa4d4b7ca7d67668bb6a525be..71a0b41adb8c8ed320ba2325716f491ec99b34e0 100644 (file)
@@ -2188,40 +2188,30 @@ static void init_priv2(struct spu_state *csa)
  * as it is by far the largest of the context save regions,
  * and may need to be pinned or otherwise specially aligned.
  */
-void spu_init_csa(struct spu_state *csa)
+int spu_init_csa(struct spu_state *csa)
 {
-       struct spu_lscsa *lscsa;
-       unsigned char *p;
+       int rc;
 
        if (!csa)
-               return;
+               return -EINVAL;
        memset(csa, 0, sizeof(struct spu_state));
 
-       lscsa = vmalloc(sizeof(struct spu_lscsa));
-       if (!lscsa)
-               return;
+       rc = spu_alloc_lscsa(csa);
+       if (rc)
+               return rc;
 
-       memset(lscsa, 0, sizeof(struct spu_lscsa));
-       csa->lscsa = lscsa;
        spin_lock_init(&csa->register_lock);
 
-       /* Set LS pages reserved to allow for user-space mapping. */
-       for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-               SetPageReserved(vmalloc_to_page(p));
-
        init_prob(csa);
        init_priv1(csa);
        init_priv2(csa);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(spu_init_csa);
 
 void spu_fini_csa(struct spu_state *csa)
 {
-       /* Clear reserved bit before vfree. */
-       unsigned char *p;
-       for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
-               ClearPageReserved(vmalloc_to_page(p));
-
-       vfree(csa->lscsa);
+       spu_free_lscsa(csa);
 }
 EXPORT_SYMBOL_GPL(spu_fini_csa);
index d1adf34cd5e8dedc2b9a43625704d765da37734e..e9ac19c4bba411d19f34d58aeb7ffa35c959defb 100644 (file)
@@ -457,6 +457,7 @@ int __devinit celleb_setup_phb(struct pci_controller *phb)
 
        pr_debug("PCI: celleb_setup_phb() %s\n", name);
        phb_set_bus_ranges(dev, phb);
+       phb->buid = 1;
 
        if (strcmp(name, "epci") == 0) {
                phb->ops = &celleb_epci_ops;
index fb23d53eb09c53cce17482905f95169c266de9b0..c4b011094bd678a64b92a00ff70cc277e5cda5cb 100644 (file)
@@ -133,13 +133,13 @@ static int celleb_epci_check_abort(struct pci_controller *hose,
 }
 
 static volatile void __iomem *celleb_epci_make_config_addr(
+                                       struct pci_bus *bus,
                                        struct pci_controller *hose,
                                        unsigned int devfn, int where)
 {
        volatile void __iomem *addr;
-       struct pci_bus *bus = hose->bus;
 
-       if (bus->self)
+       if (bus != hose->bus)
                addr = celleb_epci_get_epci_cfg(hose) +
                       (((bus->number & 0xff) << 16)
                        | ((devfn & 0xff) << 8)
@@ -193,7 +193,7 @@ static int celleb_epci_read_config(struct pci_bus *bus,
        } else {
 
                clear_and_disable_master_abort_interrupt(hose);
-               addr = celleb_epci_make_config_addr(hose, devfn, where);
+               addr = celleb_epci_make_config_addr(bus, hose, devfn, where);
 
                switch (size) {
                case 1:
@@ -257,7 +257,7 @@ static int celleb_epci_write_config(struct pci_bus *bus,
        } else {
 
                clear_and_disable_master_abort_interrupt(hose);
-               addr = celleb_epci_make_config_addr(hose, devfn, where);
+               addr = celleb_epci_make_config_addr(bus, hose, devfn, where);
 
                switch (size) {
                case 1:
index 596ab2a788d4571cd3f51f85a7b15352bbf25794..5e9f7f163571a36b08344e18e8e931c8035c47b1 100644 (file)
@@ -80,7 +80,7 @@ static int celleb_machine_type_hack(char *ptr)
        return 0;
 }
 
-__setup("celleb_machine_type_hack", celleb_machine_type_hack);
+__setup("celleb_machine_type_hack=", celleb_machine_type_hack);
 
 static void celleb_progress(char *s, unsigned short hex)
 {
index 46c3a8e7c3a8a0a5b035991c9a34921423af8eca..761d9e971fc4bacb5413efc9dd4b02cb3da4bd8c 100644 (file)
@@ -7,7 +7,9 @@ menu "iSeries device drivers"
        depends on PPC_ISERIES
 
 config VIOCONS
-       tristate "iSeries Virtual Console Support (Obsolete)"
+       bool "iSeries Virtual Console Support (Obsolete)"
+       depends on !HVC_ISERIES
+       default n
        help
          This is the old virtual console driver for legacy iSeries.
          You should use the iSeries Hypervisor Virtual Console
index 63e23062e98299d4c8f619769e1bff2d5b146013..5f3e6d8659fec09d2909e801737bf39f1a9b4717 100644 (file)
@@ -76,7 +76,7 @@
  */
 #define EEH_MAX_FAILS  2100000
 
-/* Time to wait for a PCI slot to retport status, in milliseconds */
+/* Time to wait for a PCI slot to report status, in milliseconds */
 #define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
 /* RTAS tokens */
@@ -95,11 +95,21 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
 /* Lock to avoid races due to multiple reports of an error */
 static DEFINE_SPINLOCK(confirm_error_lock);
 
-/* Buffer for reporting slot-error-detail rtas calls */
+/* Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
 static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(slot_errbuf_lock);
 static int eeh_error_buf_size;
 
+/* Buffer for reporting pci register dumps. Its here in BSS, and
+ * not dynamically alloced, so that it ends up in RMO where RTAS
+ * can access it.
+ */
+#define EEH_PCI_REGS_LOG_LEN 4096
+static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
+
 /* System monitoring statistics */
 static unsigned long no_device;
 static unsigned long no_dn;
@@ -115,7 +125,8 @@ static unsigned long slot_resets;
 /* --------------------------------------------------------------- */
 /* Below lies the EEH event infrastructure */
 
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
+static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
+                                   char *driver_log, size_t loglen)
 {
        int config_addr;
        unsigned long flags;
@@ -133,7 +144,8 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
        rc = rtas_call(ibm_slot_error_detail,
                       8, 1, NULL, config_addr,
                       BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid), NULL, 0,
+                      BUID_LO(pdn->phb->buid),
+                      virt_to_phys(driver_log), loglen,
                       virt_to_phys(slot_errbuf),
                       eeh_error_buf_size,
                       severity);
@@ -143,6 +155,84 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
        spin_unlock_irqrestore(&slot_errbuf_lock, flags);
 }
 
+/**
+ * gather_pci_data - copy assorted PCI config space registers to buff
+ * @pdn: device to report data for
+ * @buf: point to buffer in which to log
+ * @len: amount of room in buffer
+ *
+ * This routine captures assorted PCI configuration space data,
+ * and puts them into a buffer for RTAS error logging.
+ */
+static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+{
+       u32 cfg;
+       int cap, i;
+       int n = 0;
+
+       n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
+       printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+
+       rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+       n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
+       printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
+
+       rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+       n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
+       printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
+
+       /* Dump out the PCI-X command and status regs */
+       cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX);
+       if (cap) {
+               rtas_read_config(pdn, cap, 4, &cfg);
+               n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
+               printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
+
+               rtas_read_config(pdn, cap+4, 4, &cfg);
+               n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
+               printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
+       }
+
+       /* If PCI-E capable, dump PCI-E cap 10, and the AER */
+       cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_EXP);
+       if (cap) {
+               n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
+               printk(KERN_WARNING
+                      "EEH: PCI-E capabilities and status follow:\n");
+
+               for (i=0; i<=8; i++) {
+                       rtas_read_config(pdn, cap+4*i, 4, &cfg);
+                       n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+                       printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
+               }
+
+               cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR);
+               if (cap) {
+                       n += scnprintf(buf+n, len-n, "pci-e AER:\n");
+                       printk(KERN_WARNING
+                              "EEH: PCI-E AER capability register set follows:\n");
+
+                       for (i=0; i<14; i++) {
+                               rtas_read_config(pdn, cap+4*i, 4, &cfg);
+                               n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+                               printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
+                       }
+               }
+       }
+       return n;
+}
+
+void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
+{
+       size_t loglen = 0;
+       pci_regs_buf[0] = 0;
+
+       rtas_pci_enable(pdn, EEH_THAW_MMIO);
+       loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
+
+       rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+}
+
 /**
  * read_slot_reset_state - Read the reset state of a device node's slot
  * @dn: device node to read
index 3170e003f76ada0a313888fe30d51e06c3917c4c..161a5844ab6c243da27df37ba188fc5e98e72eba 100644 (file)
@@ -361,11 +361,12 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
                goto hard_fail;
        }
 
-       eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
        printk(KERN_WARNING
-          "EEH: This PCI device has failed %d times since last reboot: "
-               "location=%s driver=%s pci addr=%s\n",
-               frozen_pdn->eeh_freeze_count, location, drv_str, pci_str);
+          "EEH: This PCI device has failed %d times in the last hour:\n",
+               frozen_pdn->eeh_freeze_count);
+       printk(KERN_WARNING
+               "EEH: location=%s driver=%s pci addr=%s\n",
+               location, drv_str, pci_str);
 
        /* Walk the various device drivers attached to this slot through
         * a reset sequence, giving each an opportunity to do what it needs
@@ -375,6 +376,12 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
         */
        pci_walk_bus(frozen_bus, eeh_report_error, &result);
 
+       /* Since rtas may enable MMIO when posting the error log,
+        * don't post the error log until after all dev drivers
+        * have been informed.
+        */
+       eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
+
        /* If all device drivers were EEH-unaware, then shut
         * down all of the device drivers, and hope they
         * go down willingly, without panicing the system.
@@ -464,7 +471,7 @@ hard_fail:
                location, drv_str, pci_str);
 
 perm_error:
-       eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
+       eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
 
        /* Notify all devices that they're about to go down. */
        pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
index eec684a8e44e1bc7176df1f29120631d1b8f5474..be17d2395072c02a67abd37565c956a1221f2699 100644 (file)
@@ -520,7 +520,6 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
                dev->dev.archdata.dma_data = PCI_DN(pdn)->iommu_table;
                return;
        }
-       DBG("  found DMA window, table: %p\n", pci->iommu_table);
 
        pci = PCI_DN(pdn);
        if (!pci->iommu_table) {
@@ -534,6 +533,8 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
 
                pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
                DBG("  created table: %p\n", pci->iommu_table);
+       } else {
+               DBG("  found DMA window, table: %p\n", pci->iommu_table);
        }
 
        dev->dev.archdata.dma_data = pci->iommu_table;
index af2685607458e1e877bbb5bb71d9036a1829b892..412a5e7aff2d33829f8d0f1483fba69d6d635003 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/firmware.h>
 #include <asm/kexec.h>
 #include <asm/mpic.h>
+#include <asm/smp.h>
 
 #include "pseries.h"
 #include "xics.h"
index 9b4fafd9a840aceb236816276ac4ef8a419b998d..4f67b89ba1d0a0bcf532229b8027962ccce93a95 100644 (file)
@@ -330,7 +330,7 @@ void m8xx_cpm_dpinit(void)
         * with the processor and the microcode patches applied / activated.
         * But the following should be at least safe.
         */
-       rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+       rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
 }
 
 /*
@@ -338,9 +338,9 @@ void m8xx_cpm_dpinit(void)
  * This function returns an offset into the DPRAM area.
  * Use cpm_dpram_addr() to get the virtual address of the area.
  */
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -352,30 +352,30 @@ uint cpm_dpalloc(uint size, uint align)
 }
 EXPORT_SYMBOL(cpm_dpalloc);
 
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
-       ret = rh_free(&cpm_dpmem_info, (void *)offset);
+       ret = rh_free(&cpm_dpmem_info, offset);
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
        return ret;
 }
 EXPORT_SYMBOL(cpm_dpfree);
 
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
        cpm_dpmem_info.alignment = align;
-       start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+       start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc_fixed);
 
@@ -385,7 +385,7 @@ void cpm_dpdump(void)
 }
 EXPORT_SYMBOL(cpm_dpdump);
 
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
 {
        return (void *)(dpram_vbase + offset);
 }
index ec265995d5d8bc020837c766f35ac3ed6de25ad3..9244129747955d062b7a255c3797b97a23b88ab4 100644 (file)
@@ -248,15 +248,14 @@ static void cpm2_dpinit(void)
         * varies with the processor and the microcode patches activated.
         * But the following should be at least safe.
         */
-       rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
-                       CPM_DATAONLY_SIZE);
+       rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
 }
 
 /* This function returns an index into the DPRAM area.
  */
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -268,13 +267,13 @@ uint cpm_dpalloc(uint size, uint align)
 }
 EXPORT_SYMBOL(cpm_dpalloc);
 
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
-       ret = rh_free(&cpm_dpmem_info, (void *)offset);
+       ret = rh_free(&cpm_dpmem_info, offset);
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
        return ret;
@@ -282,17 +281,17 @@ int cpm_dpfree(uint offset)
 EXPORT_SYMBOL(cpm_dpfree);
 
 /* not sure if this is ever needed */
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
        cpm_dpmem_info.alignment = align;
-       start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+       start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc_fixed);
 
@@ -302,7 +301,7 @@ void cpm_dpdump(void)
 }
 EXPORT_SYMBOL(cpm_dpdump);
 
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
 {
        return (void *)(im_dprambase + offset);
 }
index 8a123c71449fffd9315b085158f0e1a8d6f5795a..cad175724359df4099a84b00c4af154cbd2362a5 100644 (file)
@@ -907,7 +907,7 @@ static int __init fs_enet_of_init(void)
                struct fs_platform_info fs_enet_data;
                const unsigned int *id;
                const unsigned int *phy_addr;
-               void *mac_addr;
+               const void *mac_addr;
                const phandle *ph;
                const char *model;
 
index 7f4c0754396197bdc5bf571c698b7813ffd3b979..90f87408b5d591de37347a2006432b4ba8a6d012 100644 (file)
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(qe_put_snum);
 static int qe_sdma_init(void)
 {
        struct sdma *sdma = &qe_immr->sdma;
-       u32 sdma_buf_offset;
+       unsigned long sdma_buf_offset;
 
        if (!sdma)
                return -ENODEV;
@@ -252,10 +252,10 @@ static int qe_sdma_init(void)
        /* allocate 2 internal temporary buffers (512 bytes size each) for
         * the SDMA */
        sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
-       if (IS_MURAM_ERR(sdma_buf_offset))
+       if (IS_ERR_VALUE(sdma_buf_offset))
                return -ENOMEM;
 
-       out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
+       out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
        out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
                                        (0x1 << QE_SDMR_CEN_SHIFT)));
 
@@ -291,33 +291,32 @@ static void qe_muram_init(void)
        if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
                address = *of_get_address(np, 0, &size, &flags);
                of_node_put(np);
-               rh_attach_region(&qe_muram_info,
-                       (void *)address, (int)size);
+               rh_attach_region(&qe_muram_info, address, (int) size);
        }
 }
 
 /* This function returns an index into the MURAM area.
  */
-u32 qe_muram_alloc(u32 size, u32 align)
+unsigned long qe_muram_alloc(int size, int align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&qe_muram_lock, flags);
        start = rh_alloc_align(&qe_muram_info, size, align, "QE");
        spin_unlock_irqrestore(&qe_muram_lock, flags);
 
-       return (u32) start;
+       return start;
 }
 EXPORT_SYMBOL(qe_muram_alloc);
 
-int qe_muram_free(u32 offset)
+int qe_muram_free(unsigned long offset)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&qe_muram_lock, flags);
-       ret = rh_free(&qe_muram_info, (void *)offset);
+       ret = rh_free(&qe_muram_info, offset);
        spin_unlock_irqrestore(&qe_muram_lock, flags);
 
        return ret;
@@ -325,16 +324,16 @@ int qe_muram_free(u32 offset)
 EXPORT_SYMBOL(qe_muram_free);
 
 /* not sure if this is ever needed */
-u32 qe_muram_alloc_fixed(u32 offset, u32 size)
+unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&qe_muram_lock, flags);
-       start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
+       start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
        spin_unlock_irqrestore(&qe_muram_lock, flags);
 
-       return (u32) start;
+       return start;
 }
 EXPORT_SYMBOL(qe_muram_alloc_fixed);
 
@@ -344,7 +343,7 @@ void qe_muram_dump(void)
 }
 EXPORT_SYMBOL(qe_muram_dump);
 
-void *qe_muram_addr(u32 offset)
+void *qe_muram_addr(unsigned long offset)
 {
        return (void *)&qe_immr->muram[offset];
 }
index 66137bf2dfb0ffb2c78a1613cd62079d6f447b38..9143236853fc029029f0a178f5319cb383650506 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/stddef.h>
 #include <linux/interrupt.h>
+#include <linux/err.h>
 
 #include <asm/io.h>
 #include <asm/immap_qe.h>
@@ -268,7 +269,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
        /* Allocate memory for Tx Virtual Fifo */
        uccf->ucc_fast_tx_virtual_fifo_base_offset =
            qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
-       if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
+       if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
                printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO", __FUNCTION__);
                uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
                ucc_fast_free(uccf);
@@ -280,7 +281,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
                qe_muram_alloc(uf_info->urfs +
                           UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
                           UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
-       if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
+       if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
                printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO", __FUNCTION__);
                uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
                ucc_fast_free(uccf);
index b930d686a4d18d1b06c5fe0915674f67492df900..1f65c26ce63f8fff07ecd4ff040f0d8eadb8c0e9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/stddef.h>
 #include <linux/interrupt.h>
+#include <linux/err.h>
 
 #include <asm/io.h>
 #include <asm/immap_qe.h>
@@ -175,7 +176,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
        /* Get PRAM base */
        uccs->us_pram_offset =
                qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM);
-       if (IS_MURAM_ERR(uccs->us_pram_offset)) {
+       if (IS_ERR_VALUE(uccs->us_pram_offset)) {
                printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __FUNCTION__);
                ucc_slow_free(uccs);
                return -ENOMEM;
@@ -210,7 +211,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
        uccs->rx_base_offset =
                qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),
                                QE_ALIGNMENT_OF_BD);
-       if (IS_MURAM_ERR(uccs->rx_base_offset)) {
+       if (IS_ERR_VALUE(uccs->rx_base_offset)) {
                printk(KERN_ERR "%s: cannot allocate RX BDs", __FUNCTION__);
                uccs->rx_base_offset = 0;
                ucc_slow_free(uccs);
@@ -220,7 +221,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
        uccs->tx_base_offset =
                qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),
                        QE_ALIGNMENT_OF_BD);
-       if (IS_MURAM_ERR(uccs->tx_base_offset)) {
+       if (IS_ERR_VALUE(uccs->tx_base_offset)) {
                printk(KERN_ERR "%s: cannot allocate TX BDs", __FUNCTION__);
                uccs->tx_base_offset = 0;
                ucc_slow_free(uccs);
index 7a8722beac1262bafeb4fe49545dcd5d66370f6b..e2c6210f234baf322ad2dd40d2f8af0d0184433c 100644 (file)
@@ -402,7 +402,7 @@ void m8xx_cpm_dpinit(void)
         * with the processor and the microcode patches applied / activated.
         * But the following should be at least safe.
         */
-       rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+       rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
 }
 
 /*
@@ -410,9 +410,9 @@ void m8xx_cpm_dpinit(void)
  * This function returns an offset into the DPRAM area.
  * Use cpm_dpram_addr() to get the virtual address of the area.
  */
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -420,34 +420,34 @@ uint cpm_dpalloc(uint size, uint align)
        start = rh_alloc(&cpm_dpmem_info, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc);
 
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
-       ret = rh_free(&cpm_dpmem_info, (void *)offset);
+       ret = rh_free(&cpm_dpmem_info, offset);
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
        return ret;
 }
 EXPORT_SYMBOL(cpm_dpfree);
 
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
        cpm_dpmem_info.alignment = align;
-       start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+       start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc_fixed);
 
@@ -457,7 +457,7 @@ void cpm_dpdump(void)
 }
 EXPORT_SYMBOL(cpm_dpdump);
 
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
 {
        return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
 }
index c5850a272650b688e462a9b1415e9c3514df5f1c..e8e94321b59e6fd653188c40078a6239cb8146a2 100644 (file)
@@ -35,7 +35,7 @@ int
 main(void)
 {
        DEFINE(THREAD, offsetof(struct task_struct, thread));
-       DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+       DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
        DEFINE(MM, offsetof(struct task_struct, mm));
        DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
        DEFINE(KSP, offsetof(struct thread_struct, ksp));
index 422bef9bae7b6dff9f360272be891db61d449217..095e661e79ddc3335d95f6db6bb71d0d09960541 100644 (file)
@@ -3,6 +3,3 @@
 #
 
 obj-y                  := checksum.o string.o div64.o
-
-obj-$(CONFIG_8xx)      += rheap.o
-obj-$(CONFIG_CPM2)     += rheap.o
diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c
deleted file mode 100644 (file)
index d407007..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * A Remote Heap.  Remote means that we don't touch the memory that the
- * heap points to. Normal heap implementations use the memory they manage
- * to place their list. We cannot do that because the memory we manage may
- * have special properties, for example it is uncachable or of different
- * endianess.
- *
- * Author: Pantelis Antoniou <panto@intracom.gr>
- *
- * 2004 (c) INTRACOM S.A. Greece. 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 <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include <asm/rheap.h>
-
-/*
- * Fixup a list_head, needed when copying lists.  If the pointers fall
- * between s and e, apply the delta.  This assumes that
- * sizeof(struct list_head *) == sizeof(unsigned long *).
- */
-static inline void fixup(unsigned long s, unsigned long e, int d,
-                        struct list_head *l)
-{
-       unsigned long *pp;
-
-       pp = (unsigned long *)&l->next;
-       if (*pp >= s && *pp < e)
-               *pp += d;
-
-       pp = (unsigned long *)&l->prev;
-       if (*pp >= s && *pp < e)
-               *pp += d;
-}
-
-/* Grow the allocated blocks */
-static int grow(rh_info_t * info, int max_blocks)
-{
-       rh_block_t *block, *blk;
-       int i, new_blocks;
-       int delta;
-       unsigned long blks, blke;
-
-       if (max_blocks <= info->max_blocks)
-               return -EINVAL;
-
-       new_blocks = max_blocks - info->max_blocks;
-
-       block = kmalloc(sizeof(rh_block_t) * max_blocks, GFP_KERNEL);
-       if (block == NULL)
-               return -ENOMEM;
-
-       if (info->max_blocks > 0) {
-
-               /* copy old block area */
-               memcpy(block, info->block,
-                      sizeof(rh_block_t) * info->max_blocks);
-
-               delta = (char *)block - (char *)info->block;
-
-               /* and fixup list pointers */
-               blks = (unsigned long)info->block;
-               blke = (unsigned long)(info->block + info->max_blocks);
-
-               for (i = 0, blk = block; i < info->max_blocks; i++, blk++)
-                       fixup(blks, blke, delta, &blk->list);
-
-               fixup(blks, blke, delta, &info->empty_list);
-               fixup(blks, blke, delta, &info->free_list);
-               fixup(blks, blke, delta, &info->taken_list);
-
-               /* free the old allocated memory */
-               if ((info->flags & RHIF_STATIC_BLOCK) == 0)
-                       kfree(info->block);
-       }
-
-       info->block = block;
-       info->empty_slots += new_blocks;
-       info->max_blocks = max_blocks;
-       info->flags &= ~RHIF_STATIC_BLOCK;
-
-       /* add all new blocks to the free list */
-       for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++)
-               list_add(&blk->list, &info->empty_list);
-
-       return 0;
-}
-
-/*
- * Assure at least the required amount of empty slots.  If this function
- * causes a grow in the block area then all pointers kept to the block
- * area are invalid!
- */
-static int assure_empty(rh_info_t * info, int slots)
-{
-       int max_blocks;
-
-       /* This function is not meant to be used to grow uncontrollably */
-       if (slots >= 4)
-               return -EINVAL;
-
-       /* Enough space */
-       if (info->empty_slots >= slots)
-               return 0;
-
-       /* Next 16 sized block */
-       max_blocks = ((info->max_blocks + slots) + 15) & ~15;
-
-       return grow(info, max_blocks);
-}
-
-static rh_block_t *get_slot(rh_info_t * info)
-{
-       rh_block_t *blk;
-
-       /* If no more free slots, and failure to extend. */
-       /* XXX: You should have called assure_empty before */
-       if (info->empty_slots == 0) {
-               printk(KERN_ERR "rh: out of slots; crash is imminent.\n");
-               return NULL;
-       }
-
-       /* Get empty slot to use */
-       blk = list_entry(info->empty_list.next, rh_block_t, list);
-       list_del_init(&blk->list);
-       info->empty_slots--;
-
-       /* Initialize */
-       blk->start = NULL;
-       blk->size = 0;
-       blk->owner = NULL;
-
-       return blk;
-}
-
-static inline void release_slot(rh_info_t * info, rh_block_t * blk)
-{
-       list_add(&blk->list, &info->empty_list);
-       info->empty_slots++;
-}
-
-static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
-{
-       rh_block_t *blk;
-       rh_block_t *before;
-       rh_block_t *after;
-       rh_block_t *next;
-       int size;
-       unsigned long s, e, bs, be;
-       struct list_head *l;
-
-       /* We assume that they are aligned properly */
-       size = blkn->size;
-       s = (unsigned long)blkn->start;
-       e = s + size;
-
-       /* Find the blocks immediately before and after the given one
-        * (if any) */
-       before = NULL;
-       after = NULL;
-       next = NULL;
-
-       list_for_each(l, &info->free_list) {
-               blk = list_entry(l, rh_block_t, list);
-
-               bs = (unsigned long)blk->start;
-               be = bs + blk->size;
-
-               if (next == NULL && s >= bs)
-                       next = blk;
-
-               if (be == s)
-                       before = blk;
-
-               if (e == bs)
-                       after = blk;
-
-               /* If both are not null, break now */
-               if (before != NULL && after != NULL)
-                       break;
-       }
-
-       /* Now check if they are really adjacent */
-       if (before != NULL && s != (unsigned long)before->start + before->size)
-               before = NULL;
-
-       if (after != NULL && e != (unsigned long)after->start)
-               after = NULL;
-
-       /* No coalescing; list insert and return */
-       if (before == NULL && after == NULL) {
-
-               if (next != NULL)
-                       list_add(&blkn->list, &next->list);
-               else
-                       list_add(&blkn->list, &info->free_list);
-
-               return;
-       }
-
-       /* We don't need it anymore */
-       release_slot(info, blkn);
-
-       /* Grow the before block */
-       if (before != NULL && after == NULL) {
-               before->size += size;
-               return;
-       }
-
-       /* Grow the after block backwards */
-       if (before == NULL && after != NULL) {
-               after->start = (int8_t *)after->start - size;
-               after->size += size;
-               return;
-       }
-
-       /* Grow the before block, and release the after block */
-       before->size += size + after->size;
-       list_del(&after->list);
-       release_slot(info, after);
-}
-
-static void attach_taken_block(rh_info_t * info, rh_block_t * blkn)
-{
-       rh_block_t *blk;
-       struct list_head *l;
-
-       /* Find the block immediately before the given one (if any) */
-       list_for_each(l, &info->taken_list) {
-               blk = list_entry(l, rh_block_t, list);
-               if (blk->start > blkn->start) {
-                       list_add_tail(&blkn->list, &blk->list);
-                       return;
-               }
-       }
-
-       list_add_tail(&blkn->list, &info->taken_list);
-}
-
-/*
- * Create a remote heap dynamically.  Note that no memory for the blocks
- * are allocated.  It will upon the first allocation
- */
-rh_info_t *rh_create(unsigned int alignment)
-{
-       rh_info_t *info;
-
-       /* Alignment must be a power of two */
-       if ((alignment & (alignment - 1)) != 0)
-               return ERR_PTR(-EINVAL);
-
-       info = kmalloc(sizeof(*info), GFP_KERNEL);
-       if (info == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       info->alignment = alignment;
-
-       /* Initially everything as empty */
-       info->block = NULL;
-       info->max_blocks = 0;
-       info->empty_slots = 0;
-       info->flags = 0;
-
-       INIT_LIST_HEAD(&info->empty_list);
-       INIT_LIST_HEAD(&info->free_list);
-       INIT_LIST_HEAD(&info->taken_list);
-
-       return info;
-}
-
-/*
- * Destroy a dynamically created remote heap.  Deallocate only if the areas
- * are not static
- */
-void rh_destroy(rh_info_t * info)
-{
-       if ((info->flags & RHIF_STATIC_BLOCK) == 0 && info->block != NULL)
-               kfree(info->block);
-
-       if ((info->flags & RHIF_STATIC_INFO) == 0)
-               kfree(info);
-}
-
-/*
- * Initialize in place a remote heap info block.  This is needed to support
- * operation very early in the startup of the kernel, when it is not yet safe
- * to call kmalloc.
- */
-void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
-            rh_block_t * block)
-{
-       int i;
-       rh_block_t *blk;
-
-       /* Alignment must be a power of two */
-       if ((alignment & (alignment - 1)) != 0)
-               return;
-
-       info->alignment = alignment;
-
-       /* Initially everything as empty */
-       info->block = block;
-       info->max_blocks = max_blocks;
-       info->empty_slots = max_blocks;
-       info->flags = RHIF_STATIC_INFO | RHIF_STATIC_BLOCK;
-
-       INIT_LIST_HEAD(&info->empty_list);
-       INIT_LIST_HEAD(&info->free_list);
-       INIT_LIST_HEAD(&info->taken_list);
-
-       /* Add all new blocks to the free list */
-       for (i = 0, blk = block; i < max_blocks; i++, blk++)
-               list_add(&blk->list, &info->empty_list);
-}
-
-/* Attach a free memory region, coalesces regions if adjuscent */
-int rh_attach_region(rh_info_t * info, void *start, int size)
-{
-       rh_block_t *blk;
-       unsigned long s, e, m;
-       int r;
-
-       /* The region must be aligned */
-       s = (unsigned long)start;
-       e = s + size;
-       m = info->alignment - 1;
-
-       /* Round start up */
-       s = (s + m) & ~m;
-
-       /* Round end down */
-       e = e & ~m;
-
-       /* Take final values */
-       start = (void *)s;
-       size = (int)(e - s);
-
-       /* Grow the blocks, if needed */
-       r = assure_empty(info, 1);
-       if (r < 0)
-               return r;
-
-       blk = get_slot(info);
-       blk->start = start;
-       blk->size = size;
-       blk->owner = NULL;
-
-       attach_free_block(info, blk);
-
-       return 0;
-}
-
-/* Detatch given address range, splits free block if needed. */
-void *rh_detach_region(rh_info_t * info, void *start, int size)
-{
-       struct list_head *l;
-       rh_block_t *blk, *newblk;
-       unsigned long s, e, m, bs, be;
-
-       /* Validate size */
-       if (size <= 0)
-               return ERR_PTR(-EINVAL);
-
-       /* The region must be aligned */
-       s = (unsigned long)start;
-       e = s + size;
-       m = info->alignment - 1;
-
-       /* Round start up */
-       s = (s + m) & ~m;
-
-       /* Round end down */
-       e = e & ~m;
-
-       if (assure_empty(info, 1) < 0)
-               return ERR_PTR(-ENOMEM);
-
-       blk = NULL;
-       list_for_each(l, &info->free_list) {
-               blk = list_entry(l, rh_block_t, list);
-               /* The range must lie entirely inside one free block */
-               bs = (unsigned long)blk->start;
-               be = (unsigned long)blk->start + blk->size;
-               if (s >= bs && e <= be)
-                       break;
-               blk = NULL;
-       }
-
-       if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       /* Perfect fit */
-       if (bs == s && be == e) {
-               /* Delete from free list, release slot */
-               list_del(&blk->list);
-               release_slot(info, blk);
-               return (void *)s;
-       }
-
-       /* blk still in free list, with updated start and/or size */
-       if (bs == s || be == e) {
-               if (bs == s)
-                       blk->start = (int8_t *)blk->start + size;
-               blk->size -= size;
-
-       } else {
-               /* The front free fragment */
-               blk->size = s - bs;
-
-               /* the back free fragment */
-               newblk = get_slot(info);
-               newblk->start = (void *)e;
-               newblk->size = be - e;
-
-               list_add(&newblk->list, &blk->list);
-       }
-
-       return (void *)s;
-}
-
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
-{
-       struct list_head *l;
-       rh_block_t *blk;
-       rh_block_t *newblk;
-       void *start;
-
-       /* Validate size */
-       if (size <= 0)
-               return ERR_PTR(-EINVAL);
-
-       /* Align to configured alignment */
-       size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
-
-       if (assure_empty(info, 1) < 0)
-               return ERR_PTR(-ENOMEM);
-
-       blk = NULL;
-       list_for_each(l, &info->free_list) {
-               blk = list_entry(l, rh_block_t, list);
-               if (size <= blk->size)
-                       break;
-               blk = NULL;
-       }
-
-       if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       /* Just fits */
-       if (blk->size == size) {
-               /* Move from free list to taken list */
-               list_del(&blk->list);
-               blk->owner = owner;
-               start = blk->start;
-
-               attach_taken_block(info, blk);
-
-               return start;
-       }
-
-       newblk = get_slot(info);
-       newblk->start = blk->start;
-       newblk->size = size;
-       newblk->owner = owner;
-
-       /* blk still in free list, with updated start, size */
-       blk->start = (int8_t *)blk->start + size;
-       blk->size -= size;
-
-       start = newblk->start;
-
-       attach_taken_block(info, newblk);
-
-       return start;
-}
-
-/* allocate at precisely the given address */
-void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
-{
-       struct list_head *l;
-       rh_block_t *blk, *newblk1, *newblk2;
-       unsigned long s, e, m, bs, be;
-
-       /* Validate size */
-       if (size <= 0)
-               return ERR_PTR(-EINVAL);
-
-       /* The region must be aligned */
-       s = (unsigned long)start;
-       e = s + size;
-       m = info->alignment - 1;
-
-       /* Round start up */
-       s = (s + m) & ~m;
-
-       /* Round end down */
-       e = e & ~m;
-
-       if (assure_empty(info, 2) < 0)
-               return ERR_PTR(-ENOMEM);
-
-       blk = NULL;
-       list_for_each(l, &info->free_list) {
-               blk = list_entry(l, rh_block_t, list);
-               /* The range must lie entirely inside one free block */
-               bs = (unsigned long)blk->start;
-               be = (unsigned long)blk->start + blk->size;
-               if (s >= bs && e <= be)
-                       break;
-       }
-
-       if (blk == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       /* Perfect fit */
-       if (bs == s && be == e) {
-               /* Move from free list to taken list */
-               list_del(&blk->list);
-               blk->owner = owner;
-
-               start = blk->start;
-               attach_taken_block(info, blk);
-
-               return start;
-
-       }
-
-       /* blk still in free list, with updated start and/or size */
-       if (bs == s || be == e) {
-               if (bs == s)
-                       blk->start = (int8_t *)blk->start + size;
-               blk->size -= size;
-
-       } else {
-               /* The front free fragment */
-               blk->size = s - bs;
-
-               /* The back free fragment */
-               newblk2 = get_slot(info);
-               newblk2->start = (void *)e;
-               newblk2->size = be - e;
-
-               list_add(&newblk2->list, &blk->list);
-       }
-
-       newblk1 = get_slot(info);
-       newblk1->start = (void *)s;
-       newblk1->size = e - s;
-       newblk1->owner = owner;
-
-       start = newblk1->start;
-       attach_taken_block(info, newblk1);
-
-       return start;
-}
-
-int rh_free(rh_info_t * info, void *start)
-{
-       rh_block_t *blk, *blk2;
-       struct list_head *l;
-       int size;
-
-       /* Linear search for block */
-       blk = NULL;
-       list_for_each(l, &info->taken_list) {
-               blk2 = list_entry(l, rh_block_t, list);
-               if (start < blk2->start)
-                       break;
-               blk = blk2;
-       }
-
-       if (blk == NULL || start > (blk->start + blk->size))
-               return -EINVAL;
-
-       /* Remove from taken list */
-       list_del(&blk->list);
-
-       /* Get size of freed block */
-       size = blk->size;
-       attach_free_block(info, blk);
-
-       return size;
-}
-
-int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
-{
-       rh_block_t *blk;
-       struct list_head *l;
-       struct list_head *h;
-       int nr;
-
-       switch (what) {
-
-       case RHGS_FREE:
-               h = &info->free_list;
-               break;
-
-       case RHGS_TAKEN:
-               h = &info->taken_list;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       /* Linear search for block */
-       nr = 0;
-       list_for_each(l, h) {
-               blk = list_entry(l, rh_block_t, list);
-               if (stats != NULL && nr < max_stats) {
-                       stats->start = blk->start;
-                       stats->size = blk->size;
-                       stats->owner = blk->owner;
-                       stats++;
-               }
-               nr++;
-       }
-
-       return nr;
-}
-
-int rh_set_owner(rh_info_t * info, void *start, const char *owner)
-{
-       rh_block_t *blk, *blk2;
-       struct list_head *l;
-       int size;
-
-       /* Linear search for block */
-       blk = NULL;
-       list_for_each(l, &info->taken_list) {
-               blk2 = list_entry(l, rh_block_t, list);
-               if (start < blk2->start)
-                       break;
-               blk = blk2;
-       }
-
-       if (blk == NULL || start > (blk->start + blk->size))
-               return -EINVAL;
-
-       blk->owner = owner;
-       size = blk->size;
-
-       return size;
-}
-
-void rh_dump(rh_info_t * info)
-{
-       static rh_stats_t st[32];       /* XXX maximum 32 blocks */
-       int maxnr;
-       int i, nr;
-
-       maxnr = ARRAY_SIZE(st);
-
-       printk(KERN_INFO
-              "info @0x%p (%d slots empty / %d max)\n",
-              info, info->empty_slots, info->max_blocks);
-
-       printk(KERN_INFO "  Free:\n");
-       nr = rh_get_stats(info, RHGS_FREE, maxnr, st);
-       if (nr > maxnr)
-               nr = maxnr;
-       for (i = 0; i < nr; i++)
-               printk(KERN_INFO
-                      "    0x%p-0x%p (%u)\n",
-                      st[i].start, (int8_t *) st[i].start + st[i].size,
-                      st[i].size);
-       printk(KERN_INFO "\n");
-
-       printk(KERN_INFO "  Taken:\n");
-       nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st);
-       if (nr > maxnr)
-               nr = maxnr;
-       for (i = 0; i < nr; i++)
-               printk(KERN_INFO
-                      "    0x%p-0x%p (%u) %s\n",
-                      st[i].start, (int8_t *) st[i].start + st[i].size,
-                      st[i].size, st[i].owner != NULL ? st[i].owner : "");
-       printk(KERN_INFO "\n");
-}
-
-void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
-{
-       printk(KERN_INFO
-              "blk @0x%p: 0x%p-0x%p (%u)\n",
-              blk, blk->start, (int8_t *) blk->start + blk->size, blk->size);
-}
index 7ce5364fdb3b0d2243c072c1b21bdbe6c46dcc3c..bf72204125c57ec77553368a7d67b7cef3f655a6 100644 (file)
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc866ads-setup.c
+/*arch/ppc/platforms/mpc866ads_setup.c
  *
  * Platform setup for the Freescale mpc866ads board
  *
index cbac44b1620cc3cc7313b2127e1999e2472a422c..6cd859d7721f7cbca96ee09c3915890ad2b4de92 100644 (file)
@@ -136,15 +136,14 @@ static void cpm2_dpinit(void)
         * varies with the processor and the microcode patches activated.
         * But the following should be at least safe.
         */
-       rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
-                       CPM_DATAONLY_SIZE);
+       rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
 }
 
 /* This function returns an index into the DPRAM area.
  */
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -152,17 +151,17 @@ uint cpm_dpalloc(uint size, uint align)
        start = rh_alloc(&cpm_dpmem_info, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc);
 
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
 {
        int ret;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
-       ret = rh_free(&cpm_dpmem_info, (void *)offset);
+       ret = rh_free(&cpm_dpmem_info, offset);
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
        return ret;
@@ -170,17 +169,17 @@ int cpm_dpfree(uint offset)
 EXPORT_SYMBOL(cpm_dpfree);
 
 /* not sure if this is ever needed */
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
 {
-       void *start;
+       unsigned long start;
        unsigned long flags;
 
        spin_lock_irqsave(&cpm_dpmem_lock, flags);
        cpm_dpmem_info.alignment = align;
-       start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+       start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
        spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
 
-       return (uint)start;
+       return start;
 }
 EXPORT_SYMBOL(cpm_dpalloc_fixed);
 
@@ -190,7 +189,7 @@ void cpm_dpdump(void)
 }
 EXPORT_SYMBOL(cpm_dpdump);
 
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
 {
        return (void *)&cpm2_immr->im_dprambase[offset];
 }
index 10659c24b1beb2c4369afe48868e2b86d719ec0d..9192777d0f78469c9791970327a2b97f4d7d47c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-ppc/ipic.c
+ * arch/ppc/syslib/ipic.c
  *
  * IPIC routines implementations.
  *
index 1a84719be2641f47bedc832ff7a460acbf29cf9b..098c62c29f9c3cda9b4292da5790ae1265be259d 100644 (file)
@@ -4,27 +4,23 @@
 #
 
 config MMU
-       bool
-       default y
+       def_bool y
 
 config ZONE_DMA
        def_bool y
        depends on 64BIT
 
 config LOCKDEP_SUPPORT
-       bool
-       default y
+       def_bool y
 
 config STACKTRACE_SUPPORT
-       bool
-       default y
+       def_bool y
 
 config RWSEM_GENERIC_SPINLOCK
        bool
 
 config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default y
+       def_bool y
 
 config ARCH_HAS_ILOG2_U32
        bool
@@ -35,8 +31,7 @@ config ARCH_HAS_ILOG2_U64
        default n
 
 config GENERIC_HWEIGHT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_TIME
        def_bool y
@@ -55,8 +50,7 @@ config NO_DMA
 mainmenu "Linux Kernel Configuration"
 
 config S390
-       bool
-       default y
+       def_bool y
 
 source "init/Kconfig"
 
@@ -280,6 +274,10 @@ config WARN_STACK_SIZE
 config ARCH_POPULATES_NODE_MAP
        def_bool y
 
+comment "Kernel preemption"
+
+source "kernel/Kconfig.preempt"
+
 source "mm/Kconfig"
 
 config HOLES_IN_ZONE
@@ -320,17 +318,6 @@ config QDIO_DEBUG
 
 comment "Misc"
 
-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 N if you are unsure.
-
 config IPL
        bool "Builtin IPL record support"
        help
@@ -488,6 +475,8 @@ config APPLDATA_NET_SUM
          This can also be compiled as a module, which will be called
          appldata_net_sum.o.
 
+source kernel/Kconfig.hz
+
 config NO_IDLE_HZ
        bool "No HZ timer ticks in idle"
        help
@@ -535,18 +524,12 @@ endmenu
 source "net/Kconfig"
 
 config PCMCIA
-       bool
-       default n
-
-source "drivers/base/Kconfig"
+       def_bool n
 
-source "drivers/connector/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/s390/Kconfig"
+config CCW
+       def_bool y
 
-source "drivers/net/Kconfig"
+source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
index ee89b33145d58584761159391ebea59117db1c51..81a2b92ab0c2b777d2a6dc3b7c594a9ffb547945 100644 (file)
@@ -567,9 +567,11 @@ appldata_cpu_notify(struct notifier_block *self,
 {
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                appldata_online_cpu((long) hcpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                appldata_offline_cpu((long) hcpu);
                break;
        default:
index 99ff9f08e4d737112c655ce539e52e9c78607189..d1defbbfcd8129ac1f3a5926e94a0a5a4f05d2e7 100644 (file)
@@ -54,7 +54,7 @@ config S390_PRNG
        default "m"
        help
          Select this option if you want to use the s390 pseudo random number
-         generator. The PRNG is part of the cryptograhic processor functions
+         generator. The PRNG is part of the cryptographic processor functions
          and uses triple-DES to generate secure random numbers like the
          ANSI X9.17 standard. The PRNG is usable via the char device
          /dev/prandom.
index 0e4da8a7d8266c64897375e03002447d1d3c5455..485b60c1983ce8d2efa2a348c0464bb384d890f3 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc1
-# Wed Feb 21 10:44:30 2007
+# Linux kernel version: 2.6.21
+# Thu May 10 15:18:19 2007
 #
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
@@ -14,6 +14,7 @@ CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_BUG=y
 CONFIG_NO_IOMEM=y
+CONFIG_NO_DMA=y
 CONFIG_S390=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -41,9 +42,11 @@ CONFIG_AUDIT=y
 # CONFIG_AUDITSYSCALL is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
@@ -60,12 +63,14 @@ CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -128,6 +133,14 @@ CONFIG_CHECK_STACK=y
 CONFIG_STACK_GUARD=256
 # CONFIG_WARN_STACK is not set
 CONFIG_ARCH_POPULATES_NODE_MAP=y
+
+#
+# Kernel preemption
+#
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -150,7 +163,6 @@ CONFIG_QDIO=y
 #
 # Misc
 #
-CONFIG_PREEMPT=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -163,6 +175,11 @@ CONFIG_PFAULT=y
 CONFIG_VIRT_TIMER=y
 CONFIG_VIRT_CPU_ACCOUNTING=y
 # CONFIG_APPLDATA_BASE is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
 CONFIG_NO_IDLE_HZ=y
 CONFIG_NO_IDLE_HZ_INIT=y
 CONFIG_S390_HYPFS_FS=y
@@ -177,7 +194,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -216,6 +232,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 CONFIG_IPV6=y
 # CONFIG_IPV6_PRIVACY is not set
 # CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
 # CONFIG_INET6_AH is not set
 # CONFIG_INET6_ESP is not set
 # CONFIG_INET6_IPCOMP is not set
@@ -240,7 +257,12 @@ CONFIG_IPV6_SIT=y
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-# CONFIG_IP_SCTP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
 
 #
 # TIPC Configuration (EXPERIMENTAL)
@@ -263,9 +285,6 @@ CONFIG_IPV6_SIT=y
 #
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_FIFO=y
-CONFIG_NET_SCH_CLK_JIFFIES=y
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
 
 #
 # Queueing/Scheduling
@@ -308,11 +327,14 @@ CONFIG_NET_ESTIMATOR=y
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_NET_TCPPROBE is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_RFKILL is not set
 # CONFIG_PCMCIA is not set
+CONFIG_CCW=y
+
+#
+# Device Drivers
+#
 
 #
 # Generic Driver Options
@@ -329,6 +351,37 @@ CONFIG_SYS_HYPERVISOR=y
 #
 # CONFIG_CONNECTOR is not set
 
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# S/390 block device drivers
+#
+CONFIG_BLK_DEV_XPRAM=m
+# CONFIG_DCSSBLK is not set
+CONFIG_DASD=y
+CONFIG_DASD_PROFILE=y
+CONFIG_DASD_ECKD=y
+CONFIG_DASD_FBA=y
+CONFIG_DASD_DIAG=y
+CONFIG_DASD_EER=y
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
 #
 # SCSI device support
 #
@@ -356,6 +409,7 @@ CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -372,34 +426,6 @@ CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_ZFCP=y
-CONFIG_CCW=y
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# S/390 block device drivers
-#
-CONFIG_BLK_DEV_XPRAM=m
-# CONFIG_DCSSBLK is not set
-CONFIG_DASD=y
-CONFIG_DASD_PROFILE=y
-CONFIG_DASD_ECKD=y
-CONFIG_DASD_FBA=y
-CONFIG_DASD_DIAG=y
-CONFIG_DASD_EER=y
-# CONFIG_ATA_OVER_ETH is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -421,56 +447,7 @@ CONFIG_DM_MIRROR=y
 CONFIG_DM_ZERO=y
 CONFIG_DM_MULTIPATH=y
 # CONFIG_DM_MULTIPATH_EMC is not set
-
-#
-# Character device drivers
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=2048
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-
-#
-# S/390 character device drivers
-#
-CONFIG_TN3270=y
-CONFIG_TN3270_TTY=y
-CONFIG_TN3270_FS=m
-CONFIG_TN3270_CONSOLE=y
-CONFIG_TN3215=y
-CONFIG_TN3215_CONSOLE=y
-CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP_TTY=y
-CONFIG_SCLP_CONSOLE=y
-CONFIG_SCLP_VT220_TTY=y
-CONFIG_SCLP_VT220_CONSOLE=y
-CONFIG_SCLP_CPI=m
-CONFIG_S390_TAPE=m
-
-#
-# S/390 tape interface support
-#
-CONFIG_S390_TAPE_BLOCK=y
-
-#
-# S/390 tape hardware support
-#
-CONFIG_S390_TAPE_34XX=m
-# CONFIG_S390_TAPE_3590 is not set
-# CONFIG_VMLOGRDR is not set
-# CONFIG_VMCP is not set
-# CONFIG_MONREADER is not set
-CONFIG_MONWRITER=m
-
-#
-# Cryptographic devices
-#
-CONFIG_ZCRYPT=m
-# CONFIG_ZCRYPT_MONOLITHIC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Network device support
@@ -481,10 +458,6 @@ CONFIG_BONDING=m
 CONFIG_EQUALIZER=m
 CONFIG_TUN=m
 
-#
-# PHY device support
-#
-
 #
 # Ethernet (10 or 100Mbit)
 #
@@ -498,17 +471,13 @@ CONFIG_NET_ETHERNET=y
 #
 # Ethernet (10000 Mbit)
 #
+CONFIG_MLX4_DEBUG=y
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
 
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
 #
 # Wan interfaces
 #
@@ -536,6 +505,56 @@ CONFIG_CCWGROUP=y
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_R3964 is not set
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# S/390 character device drivers
+#
+CONFIG_TN3270=y
+CONFIG_TN3270_TTY=y
+CONFIG_TN3270_FS=m
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
+CONFIG_CCW_CONSOLE=y
+CONFIG_SCLP=y
+CONFIG_SCLP_TTY=y
+CONFIG_SCLP_CONSOLE=y
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
+CONFIG_SCLP_CPI=m
+CONFIG_S390_TAPE=m
+
+#
+# S/390 tape interface support
+#
+CONFIG_S390_TAPE_BLOCK=y
+
+#
+# S/390 tape hardware support
+#
+CONFIG_S390_TAPE_34XX=m
+# CONFIG_S390_TAPE_3590 is not set
+# CONFIG_VMLOGRDR is not set
+# CONFIG_VMCP is not set
+# CONFIG_MONREADER is not set
+CONFIG_MONWRITER=m
+
 #
 # File systems
 #
@@ -628,6 +647,7 @@ CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -658,6 +678,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -668,8 +689,6 @@ CONFIG_MSDOS_PARTITION=y
 # Distributed Lock Manager
 #
 CONFIG_DLM=m
-CONFIG_DLM_TCP=y
-# CONFIG_DLM_SCTP is not set
 # CONFIG_DLM_DEBUG is not set
 
 #
@@ -693,7 +712,6 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -729,12 +747,13 @@ CONFIG_FORCED_INLINING=y
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=m
 CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
+CONFIG_CRYPTO_HMAC=m
 # CONFIG_CRYPTO_XCBC is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
+CONFIG_CRYPTO_MD5=m
 # CONFIG_CRYPTO_SHA1 is not set
 # CONFIG_CRYPTO_SHA256 is not set
 # CONFIG_CRYPTO_SHA512 is not set
@@ -745,6 +764,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_DES is not set
 CONFIG_CRYPTO_FCRYPT=m
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -771,6 +791,8 @@ CONFIG_CRYPTO_CAMELLIA=m
 # CONFIG_CRYPTO_DES_S390 is not set
 # CONFIG_CRYPTO_AES_S390 is not set
 CONFIG_S390_PRNG=m
+CONFIG_ZCRYPT=m
+# CONFIG_ZCRYPT_MONOLITHIC is not set
 
 #
 # Library routines
index ba5d3167df0db3175fb76525843094ac653582e6..8e1ea1c4012846a8a8d2f31f45f289ceabf39e6f 100644 (file)
@@ -477,7 +477,7 @@ static int __init hypfs_init(void)
                        goto fail_diag;
                }
        }
-       kset_set_kset_s(&s390_subsys, hypervisor_subsys);
+       kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
        rc = subsystem_register(&s390_subsys);
        if (rc)
                goto fail_sysfs;
index ec514fe5ccd02bb3f652ef5c962e4eb5d3ba7ed6..1375f8a4469e8e89d56fadba47e9992fbcee6963 100644 (file)
@@ -15,7 +15,7 @@
 
 int main(void)
 {
-       DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
+       DEFINE(__THREAD_info, offsetof(struct task_struct, stack),);
        DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
        DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
        DEFINE(__THREAD_mm_segment,
index 0ea048d350d8a8a2b51e9347823ae88327fab4cc..367caf92ea78afbc9715c9e7f0534424647d3741 100644 (file)
@@ -816,23 +816,23 @@ static int __init ipl_register_fcp_files(void)
 {
        int rc;
 
-       rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+       rc = sysfs_create_group(&ipl_subsys.kobj,
                                &ipl_fcp_attr_group);
        if (rc)
                goto out;
-       rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+       rc = sysfs_create_bin_file(&ipl_subsys.kobj,
                                   &ipl_parameter_attr);
        if (rc)
                goto out_ipl_parm;
-       rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+       rc = sysfs_create_bin_file(&ipl_subsys.kobj,
                                   &ipl_scp_data_attr);
        if (!rc)
                goto out;
 
-       sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
+       sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr);
 
 out_ipl_parm:
-       sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
+       sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group);
 out:
        return rc;
 }
@@ -846,7 +846,7 @@ static int __init ipl_init(void)
                return rc;
        switch (ipl_info.type) {
        case IPL_TYPE_CCW:
-               rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+               rc = sysfs_create_group(&ipl_subsys.kobj,
                                        &ipl_ccw_attr_group);
                break;
        case IPL_TYPE_FCP:
@@ -854,11 +854,11 @@ static int __init ipl_init(void)
                rc = ipl_register_fcp_files();
                break;
        case IPL_TYPE_NSS:
-               rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+               rc = sysfs_create_group(&ipl_subsys.kobj,
                                        &ipl_nss_attr_group);
                break;
        default:
-               rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+               rc = sysfs_create_group(&ipl_subsys.kobj,
                                        &ipl_unknown_attr_group);
                break;
        }
@@ -885,7 +885,7 @@ static int __init reipl_nss_init(void)
 
        if (!MACHINE_IS_VM)
                return 0;
-       rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group);
        if (rc)
                return rc;
        strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
@@ -900,7 +900,7 @@ static int __init reipl_ccw_init(void)
        reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
        if (!reipl_block_ccw)
                return -ENOMEM;
-       rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
+       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group);
        if (rc) {
                free_page((unsigned long)reipl_block_ccw);
                return rc;
@@ -938,7 +938,7 @@ static int __init reipl_fcp_init(void)
        reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
        if (!reipl_block_fcp)
                return -ENOMEM;
-       rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
+       rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group);
        if (rc) {
                free_page((unsigned long)reipl_block_fcp);
                return rc;
@@ -990,7 +990,7 @@ static int __init dump_ccw_init(void)
        dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
        if (!dump_block_ccw)
                return -ENOMEM;
-       rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
+       rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group);
        if (rc) {
                free_page((unsigned long)dump_block_ccw);
                return rc;
@@ -1014,7 +1014,7 @@ static int __init dump_fcp_init(void)
        dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
        if (!dump_block_fcp)
                return -ENOMEM;
-       rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
+       rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group);
        if (rc) {
                free_page((unsigned long)dump_block_fcp);
                return rc;
index b7977027a28fa93a8f142bab9e1d7c3245431fa0..09f028a3266ba7698061422c3dfd5c0f2998827a 100644 (file)
@@ -789,10 +789,12 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                if (sysdev_create_file(s, &attr_capability))
                        return NOTIFY_BAD;
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                sysdev_remove_file(s, &attr_capability);
                break;
        }
index 8b924b359774a40abb9042c2737b5ac9f6c637a2..d855cdbf8fb86b6b96d6e89b0090c95fc243a06c 100644 (file)
@@ -253,7 +253,10 @@ static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
                         unsigned long address, unsigned long error_code)
 {
        u16 instruction;
-       int rc, compat;
+       int rc;
+#ifdef CONFIG_COMPAT
+       int compat;
+#endif
 
        pagefault_disable();
        rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
index d74eb120a9c6b2255deb2812e8069b635f9b9a32..038179ecf6a904dd03fe65f9ab1d0654d4e2427a 100644 (file)
@@ -52,6 +52,9 @@ config GENERIC_IOMAP
 config GENERIC_TIME
        def_bool n
 
+config GENERIC_CLOCKEVENTS
+       def_bool n
+
 config SYS_SUPPORTS_APM_EMULATION
        bool
 
@@ -436,11 +439,11 @@ endmenu
 
 menu "Timer and clock configuration"
 
-if !GENERIC_TIME
-
 config SH_TMU
        bool "TMU timer support"
        depends on CPU_SH3 || CPU_SH4
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
        default y
        help
          This enables the use of the TMU as the system timer.
@@ -459,8 +462,6 @@ config SH_MTU2
        help
          This enables the use of the MTU2 as the system timer.
 
-endif
-
 config SH_TIMER_IRQ
        int
        default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
@@ -468,24 +469,6 @@ config SH_TIMER_IRQ
        default "140" if CPU_SUBTYPE_SH7206
        default "16"
 
-config NO_IDLE_HZ
-       bool "Dynamic tick timer"
-       help
-         Select this option if you want to disable continuous timer ticks
-         and have them programmed to occur as required. This option saves
-         power as the system can remain in idle state for longer.
-
-         By default dynamic tick is disabled during the boot, and can be
-         manually enabled with:
-
-           echo 1 > /sys/devices/system/timer/timer0/dyn_tick
-
-         Alternatively, if you want dynamic tick automatically enabled
-         during boot, pass "dyntick=enable" via the kernel command string.
-
-         Please note that dynamic tick may affect the accuracy of
-         timekeeping on some platforms depending on the implementation.
-
 config SH_PCLK_FREQ
        int "Peripheral clock frequency (in Hz)"
        default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
@@ -509,6 +492,8 @@ config SH_CLK_MD
        help
          MD2 - MD0 pin setting.
 
+source "kernel/time/Kconfig"
+
 endmenu
 
 menu "CPU Frequency scaling"
index a83a5d9587bb3532abd3c33ba4ee39f11f818e43..4058b4f50d44eda199717a64d09fc2e2169545ba 100644 (file)
@@ -93,6 +93,7 @@ static void __init landisk_setup(char **cmdline_p)
  */
 struct sh_machine_vector mv_landisk __initmv = {
        .mv_name = "LANDISK",
+       .mv_nr_irqs = 72,
        .mv_setup = landisk_setup,
        .mv_init_irq = init_landisk_IRQ,
 };
index 770defed9c4a886124b2ee8199094be8c62d1d07..52c7bfa57c2c64c18ba7d41b378a352d10a01f1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/arch/sh/kernel/setup_7751se.c
+ * linux/arch/sh/boards/se/7751/setup.c
  *
  * Copyright (C) 2000  Kazumoto Kojima
  *
index 6cb92676c5fc4a51178a72524a61ee6d93ac7f11..e13f06bebd9221c9247d27754b0fcd396eb11e57 100644 (file)
@@ -2,8 +2,9 @@
 # Makefile for the Linux SuperH-specific device drivers.
 #
 
+obj-y          += dma/
+
 obj-$(CONFIG_PCI)              += pci/
-obj-$(CONFIG_SH_DMA)           += dma/
 obj-$(CONFIG_SUPERHYWAY)       += superhyway/
 obj-$(CONFIG_PUSH_SWITCH)      += push-switch.o
 obj-$(CONFIG_HEARTBEAT)                += heartbeat.o
index defc13c37d483c3d4b064f1035609546ba3d4633..99935f9daf4b89b53825eefdf7df3ae2546e4d10 100644 (file)
@@ -1,12 +1,12 @@
 menu "DMA support"
 
-config SH_DMA
-       bool "DMA controller (DMAC) support"
-       help
-         Selecting this option will provide same API as PC's Direct Memory
-         Access Controller(8237A) for SuperH DMAC.
+config SH_DMA_API
+       bool
 
-         If unsure, say N.
+config SH_DMA
+       bool "SuperH on-chip DMA controller (DMAC) support"
+       select SH_DMA_API
+       default n
 
 config NR_ONCHIP_DMA_CHANNELS
        depends on SH_DMA
@@ -53,4 +53,12 @@ config DMA_PAGE_OPS_CHANNEL
          in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
          are dual-address capable.
 
+config SH_DMABRG
+       bool "SH7760 DMABRG support"
+       depends on CPU_SUBTYPE_SH7760
+       help
+         The DMABRG does data transfers from main memory to Audio/USB units
+         of the SH7760.
+         Say Y if you want to use Audio/USB DMA on your SH7760 board.
+
 endmenu
index db1295d32268b51fdd393227bac89a0347004696..1ac812d2448837dd02ae30a784ab91d69554f349 100644 (file)
@@ -2,8 +2,8 @@
 # Makefile for the SuperH DMA specific kernel interface routines under Linux.
 #
 
-obj-y                          += dma-api.o
+obj-$(CONFIG_SH_DMA_API)       += dma-api.o dma-sysfs.o
 obj-$(CONFIG_ISA_DMA_API)      += dma-isa.o
-obj-$(CONFIG_SYSFS)            += dma-sysfs.o
 obj-$(CONFIG_SH_DMA)           += dma-sh.o
 obj-$(CONFIG_SH_DREAMCAST)     += dma-pvr2.o dma-g2.o
+obj-$(CONFIG_SH_DMABRG)                += dmabrg.o
diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c
new file mode 100644 (file)
index 0000000..9d0a293
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * SH7760 DMABRG IRQ handling
+ *
+ * (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *  licensed under the GPLv2.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/dmabrg.h>
+#include <asm/io.h>
+
+/*
+ * The DMABRG is a special DMA unit within the SH7760. It does transfers
+ * from USB-SRAM/Audio units to main memory (and also the LCDC; but that
+ * part is sensibly placed  in the LCDC  registers and requires no irqs)
+ * It has 3 IRQ lines which trigger 10 events, and works independently
+ * from the traditional SH DMAC (although it blocks usage of DMAC 0)
+ *
+ * BRGIRQID   | component | dir | meaning      | source
+ * -----------------------------------------------------
+ *     0      | USB-DMA   | ... | xfer done    | DMABRGI1
+ *     1      | USB-UAE   | ... | USB addr err.| DMABRGI0
+ *     2      | HAC0/SSI0 | play| all done     | DMABRGI1
+ *     3      | HAC0/SSI0 | play| half done    | DMABRGI2
+ *     4      | HAC0/SSI0 | rec | all done     | DMABRGI1
+ *     5      | HAC0/SSI0 | rec | half done    | DMABRGI2
+ *     6      | HAC1/SSI1 | play| all done     | DMABRGI1
+ *     7      | HAC1/SSI1 | play| half done    | DMABRGI2
+ *     8      | HAC1/SSI1 | rec | all done     | DMABRGI1
+ *     9      | HAC1/SSI1 | rec | half done    | DMABRGI2
+ *
+ * all can be enabled/disabled in the DMABRGCR register,
+ * as well as checked if they occured.
+ *
+ * DMABRGI0 services  USB  DMA  Address  errors,  but it still must be
+ * enabled/acked in the DMABRGCR register.  USB-DMA complete indicator
+ * is grouped together with the audio buffer end indicators, too bad...
+ *
+ * DMABRGCR:   Bits 31-24: audio-dma ENABLE flags,
+ *             Bits 23-16: audio-dma STATUS flags,
+ *             Bits  9-8:  USB error/xfer ENABLE,
+ *             Bits  1-0:  USB error/xfer STATUS.
+ *     Ack an IRQ by writing 0 to the STATUS flag.
+ *     Mask IRQ by writing 0 to ENABLE flag.
+ *
+ * Usage is almost like with any other IRQ:
+ *  dmabrg_request_irq(BRGIRQID, handler, data)
+ *  dmabrg_free_irq(BRGIRQID)
+ *
+ * handler prototype:  void brgirqhandler(void *data)
+ */
+
+#define DMARSRA                0xfe090000
+#define DMAOR          0xffa00040
+#define DMACHCR0       0xffa0000c
+#define DMABRGCR       0xfe3c0000
+
+#define DMAOR_BRG      0x0000c000
+#define DMAOR_DMEN     0x00000001
+
+#define DMABRGI0       68
+#define DMABRGI1       69
+#define DMABRGI2       70
+
+struct dmabrg_handler {
+       void (*handler)(void *);
+       void *data;
+} *dmabrg_handlers;
+
+static inline void dmabrg_call_handler(int i)
+{
+       dmabrg_handlers[i].handler(dmabrg_handlers[i].data);
+}
+
+/*
+ * main DMABRG irq handler. It acks irqs and then
+ * handles every set and unmasked bit sequentially.
+ * No locking and no validity checks; it should be
+ * as fast as possible (audio!)
+ */
+static irqreturn_t dmabrg_irq(int irq, void *data)
+{
+       unsigned long dcr;
+       unsigned int i;
+
+       dcr = ctrl_inl(DMABRGCR);
+       ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */
+       dcr &= dcr >> 8;        /* ignore masked */
+
+       /* USB stuff, get it out of the way first */
+       if (dcr & 1)
+               dmabrg_call_handler(DMABRGIRQ_USBDMA);
+       if (dcr & 2)
+               dmabrg_call_handler(DMABRGIRQ_USBDMAERR);
+
+       /* Audio */
+       dcr >>= 16;
+       while (dcr) {
+               i = __ffs(dcr);
+               dcr &= dcr - 1;
+               dmabrg_call_handler(i + DMABRGIRQ_A0TXF);
+       }
+       return IRQ_HANDLED;
+}
+
+static void dmabrg_disable_irq(unsigned int dmairq)
+{
+       unsigned long dcr;
+       dcr = ctrl_inl(DMABRGCR);
+       dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+       ctrl_outl(dcr, DMABRGCR);
+}
+
+static void dmabrg_enable_irq(unsigned int dmairq)
+{
+       unsigned long dcr;
+       dcr = ctrl_inl(DMABRGCR);
+       dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+       ctrl_outl(dcr, DMABRGCR);
+}
+
+int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*),
+                      void *data)
+{
+       if ((dmairq > 9) || !handler)
+               return -ENOENT;
+       if (dmabrg_handlers[dmairq].handler)
+               return -EBUSY;
+
+       dmabrg_handlers[dmairq].handler = handler;
+       dmabrg_handlers[dmairq].data = data;
+       
+       dmabrg_enable_irq(dmairq);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dmabrg_request_irq);
+
+void dmabrg_free_irq(unsigned int dmairq)
+{
+       if (likely(dmairq < 10)) {
+               dmabrg_disable_irq(dmairq);
+               dmabrg_handlers[dmairq].handler = NULL;
+               dmabrg_handlers[dmairq].data = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(dmabrg_free_irq);
+
+static int __init dmabrg_init(void)
+{
+       unsigned long or;
+       int ret;
+
+       dmabrg_handlers = kzalloc(10 * sizeof(struct dmabrg_handler),
+                                 GFP_KERNEL);
+       if (!dmabrg_handlers)
+               return -ENOMEM;
+
+#ifdef CONFIG_SH_DMA
+       /* request DMAC channel 0 before anyone else can get it */
+       ret = request_dma(0, "DMAC 0 (DMABRG)");
+       if (ret < 0)
+               printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
+#endif
+
+       ctrl_outl(0, DMABRGCR);
+       ctrl_outl(0, DMACHCR0);
+       ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */
+
+       /* enable DMABRG mode, enable the DMAC */
+       or = ctrl_inl(DMAOR);
+       ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR);
+
+       ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED,
+                       "DMABRG USB address error", NULL);
+       if (ret)
+               goto out0;
+
+       ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED,
+                       "DMABRG Transfer End", NULL);
+       if (ret)
+               goto out1;
+
+       ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED,
+                       "DMABRG Transfer Half", NULL);
+       if (ret == 0)
+               return ret;
+
+       free_irq(DMABRGI1, 0);
+out1:  free_irq(DMABRGI0, 0);
+out0:  kfree(dmabrg_handlers);
+       return ret;
+}
+subsys_initcall(dmabrg_init);
index 350972ae9410df1e11b37658e6ce993817b6cc33..965fa2572b2368230bffb56ee00be7d8714eebdf 100644 (file)
@@ -2,9 +2,8 @@
 # Makefile for the Linux/SuperH SH-2A backends.
 #
 
-obj-y  := common.o probe.o
+obj-y  := common.o probe.o opcode_helper.o
 
-common-y       += $(addprefix ../sh2/, ex.o)
-common-y       += $(addprefix ../sh2/, entry.o)
+common-y       += $(addprefix ../sh2/, ex.o entry.o)
 
 obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
new file mode 100644 (file)
index 0000000..9704b79
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/opcode_helper.c
+ *
+ * Helper for the SH-2A 32-bit opcodes.
+ *
+ *  Copyright (C) 2007  Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+/*
+ * Instructions on SH are generally fixed at 16-bits, however, SH-2A
+ * introduces some 32-bit instructions. Since there are no real
+ * constraints on their use (and they can be mixed and matched), we need
+ * to check the instruction encoding to work out if it's a true 32-bit
+ * instruction or not.
+ *
+ * Presently, 32-bit opcodes have only slight variations in what the
+ * actual encoding looks like in the first-half of the instruction, which
+ * makes it fairly straightforward to differentiate from the 16-bit ones.
+ *
+ * First 16-bits of encoding           Used by
+ *
+ *     0011nnnnmmmm0001        mov.b, mov.w, mov.l, fmov.d,
+ *                             fmov.s, movu.b, movu.w
+ *
+ *     0011nnnn0iii1001        bclr.b, bld.b, bset.b, bst.b, band.b,
+ *                             bandnot.b, bldnot.b, bor.b, bornot.b,
+ *                             bxor.b
+ *
+ *     0000nnnniiii0000        movi20
+ *     0000nnnniiii0001        movi20s
+ */
+unsigned int instruction_size(unsigned int insn)
+{
+       /* Look for the common cases */
+       switch ((insn & 0xf00f)) {
+       case 0x0000:    /* movi20 */
+       case 0x0001:    /* movi20s */
+       case 0x3001:    /* 32-bit mov/fmov/movu variants */
+               return 4;
+       }
+
+       /* And the special cases.. */
+       switch ((insn & 0xf08f)) {
+       case 0x3009:    /* 32-bit b*.b bit operations */
+               return 4;
+       }
+
+       return 2;
+}
index 426f6db01fc69d117621398e5be60f29a09f261a..f455c3509789b8ba5b4943e758b31b27d9626695 100644 (file)
@@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void)
 {
        /* Just SH7206 for now .. */
        current_cpu_data.type                   = CPU_SH7206;
+       current_cpu_data.flags                  |= CPU_HAS_OP32;
 
        current_cpu_data.dcache.ways            = 4;
        current_cpu_data.dcache.way_incr        = (1 << 11);
index f3e827f29a46b298eb6a31561fe80dfe09340460..832c0b4a1e6ca2fe78583e57af93ebd44f78d7bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/entry.S
+ * arch/sh/kernel/cpu/sh3/entry.S
  *
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
  *  Copyright (C) 2003 - 2006  Paul Mundt
index ba3082d640b5f1d06191a7cc9671ee62a4bb111e..2b2a9e02fb752d1e358f41787369cb8731412501 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/sh/kernel/cpu/sh3/ex.S
  *
- *  The SH-3 exception vector table.
+ *  The SH-3 and SH-4 exception vector table.
 
  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
  *  Copyright (C) 2003 - 2006  Paul Mundt
@@ -9,7 +9,6 @@
  * 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.
- *
  */
 #include <linux/linkage.h>
 
@@ -36,8 +35,12 @@ ENTRY(exception_handling_table)
        .long   exception_error ! address error load
        .long   exception_error ! address error store   /* 100 */
 #endif
-       .long   exception_error ! fpu_exception /* 120 */
-       .long   exception_error                 /* 140 */
+#if defined(CONFIG_SH_FPU)
+       .long   do_fpu_error            /* 120 */
+#else
+       .long   exception_error         /* 120 */
+#endif
+       .long   exception_error         /* 140 */
        .long   system_call     ! Unconditional Trap     /* 160 */
        .long   exception_error ! reserved_instruction (filled by trap_init) /* 180 */
        .long   exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
@@ -55,4 +58,4 @@ ENTRY(user_break_point_trap)
         * away offsets can be manually inserted in to their appropriate
         * location via set_exception_table_{evt,vec}().
         */
-       .balign 4096,0,4096
+       .balign 4096,0,4096
index 19ca68c71884176ed9f7f2230ab4618660842a47..8add10bd82683d5efd5064faee11b0746e146c61 100644 (file)
@@ -2,10 +2,10 @@
 # Makefile for the Linux/SuperH SH-4 backends.
 #
 
-obj-y  := ex.o probe.o common.o
-common-y       += $(addprefix ../sh3/, entry.o)
+obj-y  := probe.o common.o
+common-y       += $(addprefix ../sh3/, entry.o ex.o)
 
-obj-$(CONFIG_SH_FPU)                    += fpu.o
+obj-$(CONFIG_SH_FPU)                   += fpu.o
 obj-$(CONFIG_SH_STORE_QUEUES)          += sq.o
 
 # CPU subtype setup
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
deleted file mode 100644 (file)
index ac8ab57..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  arch/sh/kernel/cpu/sh4/ex.S
- *
- *  The SH-4 exception vector table.
-
- *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- *  Copyright (C) 2003 - 2006  Paul Mundt
- *
- * 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.
- *
- */
-#include <linux/linkage.h>
-
-       .align 2
-       .data
-
-ENTRY(exception_handling_table)
-       .long   exception_error         /* 000 */
-       .long   exception_error
-#if defined(CONFIG_MMU)
-       .long   tlb_miss_load           /* 040 */
-       .long   tlb_miss_store
-       .long   initial_page_write
-       .long   tlb_protection_violation_load
-       .long   tlb_protection_violation_store
-       .long   address_error_load
-       .long   address_error_store     /* 100 */
-#else
-       .long   exception_error ! tlb miss load         /* 040 */
-       .long   exception_error ! tlb miss store
-       .long   exception_error ! initial page write
-       .long   exception_error ! tlb prot violation load
-       .long   exception_error ! tlb prot violation store
-       .long   exception_error ! address error load
-       .long   exception_error ! address error store   /* 100 */
-#endif
-#if defined(CONFIG_SH_FPU)
-       .long   do_fpu_error            /* 120 */
-#else
-       .long   exception_error         /* 120 */
-#endif
-       .long   exception_error         /* 140 */
-       .long   system_call     ! Unconditional Trap     /* 160 */
-       .long   exception_error ! reserved_instruction (filled by trap_init) /* 180 */
-       .long   exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
-ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
-       .long   debug_enter     /* 1C0 */       ! Allow trap to debugger
-#else
-       .long   exception_none  /* 1C0 */       ! Not implemented yet
-#endif
-ENTRY(user_break_point_trap)
-       .long   break_point_trap        /* 1E0 */
-
-       /*
-        * Pad the remainder of the table out, exceptions residing in far
-        * away offsets can be manually inserted in to their appropriate
-        * location via set_exception_table_{evt,vec}().
-        */
-       .balign 4096,0,4096
index 7624677f66281e7ef31b99d9b48caf1bc7534b5d..d61dd599169f97b0acb1f42fc9b19acc2dd26835 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/processor.h>
+#include <asm/system.h>
 #include <asm/io.h>
 
 /* The PR (precision) bit in the FP Status Register must be clear when
@@ -265,7 +266,7 @@ ieee_fpe_handler (struct pt_regs *regs)
                nextpc = regs->pr;
                finsn = *(unsigned short *) (regs->pc + 2);
        } else {
-               nextpc = regs->pc + 2;
+               nextpc = regs->pc + instruction_size(insn);
                finsn = insn;
        }
 
index 2fa5cb2ae68d58cfe98ef3b4dd77500e69c2e8a8..6d5ba373a75e461db8ded6d7d669c5104043aac9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh73180.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh73180.c
  *
  * SH73180 support for the clock framework
  *
index 1707a213f0cf7b00b6276f112aa837032b5951b6..7adc4f16e95ae4f3fd66a8ea384e6244ad16c095 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7343.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7343.c
  *
  * SH7343/SH7722 support for the clock framework
  *
index c8694bac64775ebbc9ef45c9d6a46483ecbe1d0d..8e236062c721860fb5f39768c09f4eb2859bb6cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7770.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7770.c
  *
  * SH7770 support for the clock framework
  *
index 9e6a216750c800529788b340aa12fdb7f5956f17..01f3da619d3d95f259b19153e556fe1ea721718f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/cpu/sh4/clock-sh7780.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
  *
  * SH7780 support for the clock framework
  *
index 329b3f3051de9d53bb5b58b7418e595d11d74e09..6b4f5748d0be682a2b6334ca7d6f5ccc406be271 100644 (file)
 #include <linux/pm.h>
 #include <linux/kallsyms.h>
 #include <linux/kexec.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
+#include <linux/tick.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
 #include <asm/ubc.h>
 
 static int hlt_counter;
@@ -58,12 +61,15 @@ void cpu_idle(void)
                if (!idle)
                        idle = default_idle;
 
+               tick_nohz_stop_sched_tick();
                while (!need_resched())
                        idle();
+               tick_nohz_restart_sched_tick();
 
                preempt_enable_no_resched();
                schedule();
                preempt_disable();
+               check_pgt_cache();
        }
 }
 
@@ -495,9 +501,9 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
        struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 
        /* Rewind */
-       regs->pc -= 2;
+       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 
-       if (notify_die(DIE_TRAP, regs, regs->tra & 0xff,
+       if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
                       SIGTRAP) == NOTIFY_STOP)
                return;
 
@@ -514,9 +520,9 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
        struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 
        /* Rewind */
-       regs->pc -= 2;
+       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
 
-       if (notify_die(DIE_TRAP, regs, TRAPA_BUG_OPCODE & 0xff,
+       if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
                       SIGTRAP) == NOTIFY_STOP)
                return;
 
index 477d2a854fc4e4a59d0f83cec2341b8648b10fd1..c27729135935d77a8a4387fdb562e3bb86158357 100644 (file)
@@ -431,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c)
 /* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
 static const char *cpu_flags[] = {
        "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
-       "ptea", "llsc", "l2", NULL
+       "ptea", "llsc", "l2", "op32", NULL
 };
 
 static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
index fa91641c1f62c34a4eb0e478bc9654fec48ae585..c1cfcb9f047c1803f3e5564079bdba127f6509e4 100644 (file)
@@ -58,8 +58,6 @@ EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__const_udelay);
 
-EXPORT_SYMBOL(__div64_32);
-
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
 
 /* These symbols are generated by the compiler itself */
index eb0191c374b6839caffd65099899e7166c0d30e2..b32c35a7c0a3e42512765962e8b71c0c1096a5c8 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/personality.h>
 #include <linux/binfmts.h>
 #include <linux/freezer.h>
-
+#include <asm/system.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -500,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                                }
                        /* fallthrough */
                        case -ERESTARTNOINTR:
-                               regs->pc -= 2;
+                               regs->pc -= instruction_size(
+                                               ctrl_inw(regs->pc - 4));
+                               break;
                }
        } else {
                /* gUSA handling */
@@ -516,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                        regs->regs[15] = regs->regs[1];
                        if (regs->pc < regs->regs[0])
                                /* Go to rewind point #1 */
-                               regs->pc = regs->regs[0] + offset - 2;
+                               regs->pc = regs->regs[0] + offset -
+                                       instruction_size(ctrl_inw(regs->pc-4));
                }
 #ifdef CONFIG_PREEMPT
                local_irq_restore(flags);
@@ -600,9 +603,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
                    regs->regs[0] == -ERESTARTSYS ||
                    regs->regs[0] == -ERESTARTNOINTR) {
                        regs->regs[0] = save_r0;
-                       regs->pc -= 2;
+                       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
                } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
-                       regs->pc -= 2;
+                       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
                        regs->regs[3] = __NR_restart_syscall;
                }
        }
index 4bdd2f83535da137635e7507b19f608592f0fd7a..d41e561be20eafacbacf9c99fd08a84d1f1e2321 100644 (file)
@@ -17,7 +17,7 @@
 /*
  * Save stack-backtrace addresses into a stack_trace buffer.
  */
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
 {
        unsigned long *sp = (unsigned long *)current_stack_pointer;
 
index 38fc8cd3ea3a12fbe35dc6a014d12b651eab6795..4357d1a6358f61ba39a2ab7094fdfd968daec8aa 100644 (file)
@@ -354,3 +354,4 @@ ENTRY(sys_call_table)
        .long sys_move_pages
        .long sys_getcpu
        .long sys_epoll_pwait
+       .long sys_utimensat             /* 320 */
index d47e775962e955054f8e0296f4f3a5fdd65377e5..a3a67d151e520285b08c7fd58cc93d618e079fe6 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
  *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
- *  Copyright (C) 2002 - 2006  Paul Mundt
+ *  Copyright (C) 2002 - 2007  Paul Mundt
  *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
  *
  *  Some code taken from i386 version.
@@ -15,6 +15,7 @@
 #include <linux/profile.h>
 #include <linux/timex.h>
 #include <linux/sched.h>
+#include <linux/clockchips.h>
 #include <asm/clock.h>
 #include <asm/rtc.h>
 #include <asm/timer.h>
@@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs)
        return 0;
 }
 
+/*
+ * Null high precision timer functions for systems lacking one.
+ */
+static cycle_t null_hpt_read(void)
+{
+       return 0;
+}
+
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
@@ -101,6 +110,7 @@ int do_settimeofday(struct timespec *tv)
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /* last time the RTC clock got updated */
 static long last_rtc_update;
 
@@ -138,6 +148,7 @@ void handle_timer_tick(void)
                        last_rtc_update = xtime.tv_sec - 600;
        }
 }
+#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 #ifdef CONFIG_PM
 int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -168,136 +179,58 @@ static struct sysdev_class timer_sysclass = {
        .resume  = timer_resume,
 };
 
-#ifdef CONFIG_NO_IDLE_HZ
-static int timer_dyn_tick_enable(void)
+static int __init timer_init_sysfs(void)
 {
-       struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-       unsigned long flags;
-       int ret = -ENODEV;
-
-       if (dyn_tick) {
-               spin_lock_irqsave(&dyn_tick->lock, flags);
-               ret = 0;
-               if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
-                       ret = dyn_tick->enable();
-
-                       if (ret == 0)
-                               dyn_tick->state |= DYN_TICK_ENABLED;
-               }
-               spin_unlock_irqrestore(&dyn_tick->lock, flags);
-       }
+       int ret = sysdev_class_register(&timer_sysclass);
+       if (ret != 0)
+               return ret;
 
-       return ret;
+       sys_timer->dev.cls = &timer_sysclass;
+       return sysdev_register(&sys_timer->dev);
 }
+device_initcall(timer_init_sysfs);
 
-static int timer_dyn_tick_disable(void)
-{
-       struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-       unsigned long flags;
-       int ret = -ENODEV;
-
-       if (dyn_tick) {
-               spin_lock_irqsave(&dyn_tick->lock, flags);
-               ret = 0;
-               if (dyn_tick->state & DYN_TICK_ENABLED) {
-                       ret = dyn_tick->disable();
-
-                       if (ret == 0)
-                               dyn_tick->state &= ~DYN_TICK_ENABLED;
-               }
-               spin_unlock_irqrestore(&dyn_tick->lock, flags);
-       }
-
-       return ret;
-}
+void (*board_time_init)(void);
 
 /*
- * Reprogram the system timer for at least the calculated time interval.
- * This function should be called from the idle thread with IRQs disabled,
- * immediately before sleeping.
+ * Shamelessly based on the MIPS and Sparc64 work.
  */
-void timer_dyn_reprogram(void)
-{
-       struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
-       unsigned long next, seq, flags;
-
-       if (!dyn_tick)
-               return;
-
-       spin_lock_irqsave(&dyn_tick->lock, flags);
-       if (dyn_tick->state & DYN_TICK_ENABLED) {
-               next = next_timer_interrupt();
-               do {
-                       seq = read_seqbegin(&xtime_lock);
-                       dyn_tick->reprogram(next - jiffies);
-               } while (read_seqretry(&xtime_lock, seq));
-       }
-       spin_unlock_irqrestore(&dyn_tick->lock, flags);
-}
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
+unsigned long sh_hpt_frequency = 0;
+
+#define NSEC_PER_CYC_SHIFT     10
+
+struct clocksource clocksource_sh = {
+       .name           = "SuperH",
+       .rating         = 200,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .read           = null_hpt_read,
+       .shift          = 16,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
 
-static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+static void __init init_sh_clocksource(void)
 {
-       return sprintf(buf, "%i\n",
-                      (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
-}
+       if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
+               return;
 
-static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
-                                 size_t count)
-{
-       unsigned int enable = simple_strtoul(buf, NULL, 2);
+       clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
+                                                 clocksource_sh.shift);
 
-       if (enable)
-               timer_dyn_tick_enable();
-       else
-               timer_dyn_tick_disable();
+       timer_ticks_per_nsec_quotient =
+               clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
 
-       return count;
+       clocksource_register(&clocksource_sh);
 }
-static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
 
-/*
- * dyntick=enable|disable
- */
-static char dyntick_str[4] __initdata = "";
-
-static int __init dyntick_setup(char *str)
+#ifdef CONFIG_GENERIC_TIME
+unsigned long long sched_clock(void)
 {
-       if (str)
-               strlcpy(dyntick_str, str, sizeof(dyntick_str));
-       return 1;
+       unsigned long long ticks = clocksource_sh.read();
+       return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
 }
-
-__setup("dyntick=", dyntick_setup);
-#endif
-
-static int __init timer_init_sysfs(void)
-{
-       int ret = sysdev_class_register(&timer_sysclass);
-       if (ret != 0)
-               return ret;
-
-       sys_timer->dev.cls = &timer_sysclass;
-       ret = sysdev_register(&sys_timer->dev);
-
-#ifdef CONFIG_NO_IDLE_HZ
-       if (ret == 0 && sys_timer->dyn_tick) {
-               ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
-
-               /*
-                * Turn on dynamic tick after calibrate delay
-                * for correct bogomips
-                */
-               if (ret == 0 && dyntick_str[0] == 'e')
-                       ret = timer_dyn_tick_enable();
-       }
 #endif
 
-       return ret;
-}
-device_initcall(timer_init_sysfs);
-
-void (*board_time_init)(void);
-
 void __init time_init(void)
 {
        if (board_time_init)
@@ -316,10 +249,15 @@ void __init time_init(void)
        sys_timer = get_sys_timer();
        printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
 
-#ifdef CONFIG_NO_IDLE_HZ
-       if (sys_timer->dyn_tick)
-               spin_lock_init(&sys_timer->dyn_tick->lock);
-#endif
+       if (sys_timer->ops->read)
+               clocksource_sh.read = sys_timer->ops->read;
+
+       init_sh_clocksource();
+
+       if (sh_hpt_frequency)
+               printk("Using %lu.%03lu MHz high precision timer.\n",
+                      ((sh_hpt_frequency + 500) / 1000) / 1000,
+                      ((sh_hpt_frequency + 500) / 1000) % 1000);
 
 #if defined(CONFIG_SH_KGDB)
        /*
index d9e3151c891e9cd197aaa87e4f6efe2d7f81e73c..2d997e2a5b6cc6a0961810c8b02beb49df44efac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
  *
- *  Copyright (C) 2005  Paul Mundt
+ *  Copyright (C) 2005 - 2007  Paul Mundt
  *
  * TMU handling code hacked out of arch/sh/kernel/time.c
  *
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/seqlock.h>
+#include <linux/clockchips.h>
 #include <asm/timer.h>
 #include <asm/rtc.h>
 #include <asm/io.h>
 #include <asm/clock.h>
 
 #define TMU_TOCR_INIT  0x00
-#define TMU0_TCR_INIT  0x0020
-#define TMU_TSTR_INIT  1
+#define TMU_TCR_INIT   0x0020
 
-#define TMU0_TCR_CALIB 0x0000
+static int tmu_timer_start(void)
+{
+       ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
+       return 0;
+}
 
-static unsigned long tmu_timer_get_offset(void)
+static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
 {
-       int count;
-       static int count_p = 0x7fffffff;    /* for the first call after boot */
-       static unsigned long jiffies_p = 0;
+       ctrl_outl(interval, TMU0_TCNT);
 
        /*
-        * cache volatile jiffies temporarily; we have IRQs turned off.
+        * TCNT reloads from TCOR on underflow, clear it if we don't
+        * intend to auto-reload
         */
-       unsigned long jiffies_t;
+       if (reload)
+               ctrl_outl(interval, TMU0_TCOR);
+       else
+               ctrl_outl(0, TMU0_TCOR);
 
-       /* timer count may underflow right here */
-       count = ctrl_inl(TMU0_TCNT);    /* read the latched count */
+       tmu_timer_start();
+}
 
-       jiffies_t = jiffies;
+static int tmu_timer_stop(void)
+{
+       ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
+       return 0;
+}
 
-       /*
-        * avoiding timer inconsistencies (they are rare, but they happen)...
-        * there is one kind of problem that must be avoided here:
-        *  1. the timer counter underflows
-        */
+static cycle_t tmu_timer_read(void)
+{
+       return ~ctrl_inl(TMU1_TCNT);
+}
+
+static int tmu_set_next_event(unsigned long cycles,
+                             struct clock_event_device *evt)
+{
+       tmu0_timer_set_interval(cycles, 1);
+       return 0;
+}
 
-       if (jiffies_t == jiffies_p) {
-               if (count > count_p) {
-                       /* the nutcase */
-                       if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
-                               count -= LATCH;
-                       } else {
-                               printk("%s (): hardware timer problem?\n",
-                                      __FUNCTION__);
-                       }
-               }
-       } else
-               jiffies_p = jiffies_t;
-
-       count_p = count;
-
-       count = ((LATCH-1) - count) * TICK_SIZE;
-       count = (count + LATCH/2) / LATCH;
-
-       return count;
+static void tmu_set_mode(enum clock_event_mode mode,
+                        struct clock_event_device *evt)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               ctrl_outl(0, TMU0_TCOR);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               break;
+       }
 }
 
+static struct clock_event_device tmu0_clockevent = {
+       .name           = "tmu0",
+       .shift          = 32,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = tmu_set_mode,
+       .set_next_event = tmu_set_next_event,
+};
+
 static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
 {
+       struct clock_event_device *evt = &tmu0_clockevent;
        unsigned long timer_status;
 
        /* Clear UNF bit */
@@ -82,72 +102,76 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
        timer_status &= ~0x100;
        ctrl_outw(timer_status, TMU0_TCR);
 
-       /*
-        * Here we are in the timer irq handler. We just have irqs locally
-        * disabled but we don't know if the timer_bh is running on the other
-        * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-        * the irq version of write_lock because as just said we have irq
-        * locally disabled. -arca
-        */
-       write_seqlock(&xtime_lock);
-       handle_timer_tick();
-       write_sequnlock(&xtime_lock);
+       evt->event_handler(evt);
 
        return IRQ_HANDLED;
 }
 
-static struct irqaction tmu_irq = {
-       .name           = "timer",
+static struct irqaction tmu0_irq = {
+       .name           = "periodic timer",
        .handler        = tmu_timer_interrupt,
        .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
        .mask           = CPU_MASK_NONE,
 };
 
-static void tmu_clk_init(struct clk *clk)
+static void tmu0_clk_init(struct clk *clk)
 {
-       u8 divisor = TMU0_TCR_INIT & 0x7;
-       ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+       u8 divisor = TMU_TCR_INIT & 0x7;
+       ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
        clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static void tmu_clk_recalc(struct clk *clk)
+static void tmu0_clk_recalc(struct clk *clk)
 {
        u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
        clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static struct clk_ops tmu_clk_ops = {
-       .init           = tmu_clk_init,
-       .recalc         = tmu_clk_recalc,
+static struct clk_ops tmu0_clk_ops = {
+       .init           = tmu0_clk_init,
+       .recalc         = tmu0_clk_recalc,
 };
 
 static struct clk tmu0_clk = {
        .name           = "tmu0_clk",
-       .ops            = &tmu_clk_ops,
+       .ops            = &tmu0_clk_ops,
 };
 
-static int tmu_timer_start(void)
+static void tmu1_clk_init(struct clk *clk)
 {
-       ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-       return 0;
+       u8 divisor = TMU_TCR_INIT & 0x7;
+       ctrl_outw(divisor, TMU1_TCR);
+       clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
-static int tmu_timer_stop(void)
+static void tmu1_clk_recalc(struct clk *clk)
 {
-       ctrl_outb(0, TMU_TSTR);
-       return 0;
+       u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
+       clk->rate = clk->parent->rate / (4 << (divisor << 1));
 }
 
+static struct clk_ops tmu1_clk_ops = {
+       .init           = tmu1_clk_init,
+       .recalc         = tmu1_clk_recalc,
+};
+
+static struct clk tmu1_clk = {
+       .name           = "tmu1_clk",
+       .ops            = &tmu1_clk_ops,
+};
+
 static int tmu_timer_init(void)
 {
        unsigned long interval;
+       unsigned long frequency;
 
-       setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq);
+       setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
 
        tmu0_clk.parent = clk_get(NULL, "module_clk");
+       tmu1_clk.parent = clk_get(NULL, "module_clk");
 
-       /* Start TMU0 */
        tmu_timer_stop();
+
 #if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
     !defined(CONFIG_CPU_SUBTYPE_SH7785)
@@ -155,15 +179,29 @@ static int tmu_timer_init(void)
 #endif
 
        clk_register(&tmu0_clk);
+       clk_register(&tmu1_clk);
        clk_enable(&tmu0_clk);
+       clk_enable(&tmu1_clk);
 
-       interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ;
-       printk(KERN_INFO "Interval = %ld\n", interval);
+       frequency = clk_get_rate(&tmu0_clk);
+       interval = (frequency + HZ / 2) / HZ;
 
-       ctrl_outl(interval, TMU0_TCOR);
-       ctrl_outl(interval, TMU0_TCNT);
+       sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+       ctrl_outl(~0, TMU1_TCNT);
+       ctrl_outl(~0, TMU1_TCOR);
 
-       tmu_timer_start();
+       tmu0_timer_set_interval(interval, 1);
+
+       tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
+                                     tmu0_clockevent.shift);
+       tmu0_clockevent.max_delta_ns =
+                       clockevent_delta2ns(-1, &tmu0_clockevent);
+       tmu0_clockevent.min_delta_ns =
+                       clockevent_delta2ns(1, &tmu0_clockevent);
+
+       tmu0_clockevent.cpumask = cpumask_of_cpu(0);
+
+       clockevents_register_device(&tmu0_clockevent);
 
        return 0;
 }
@@ -172,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = {
        .init           = tmu_timer_init,
        .start          = tmu_timer_start,
        .stop           = tmu_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
-       .get_offset     = tmu_timer_get_offset,
-#endif
+       .read           = tmu_timer_read,
 };
 
 struct sys_timer tmu_timer = {
index 7b40f0ff3dfc8701a8121dfddaaf3f9044db97c0..3a197649cd83c6c57227156fbcdd6d06e86ef7a2 100644 (file)
 #include <linux/io.h>
 #include <linux/bug.h>
 #include <linux/debug_locks.h>
+#include <linux/kdebug.h>
 #include <linux/limits.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/kdebug.h>
 
 #ifdef CONFIG_SH_KGDB
 #include <asm/kgdb.h>
@@ -76,20 +76,6 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
        }
 }
 
-ATOMIC_NOTIFIER_HEAD(shdie_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&shdie_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
 static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -505,7 +491,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
  simple:
        ret = handle_unaligned_ins(instruction,regs);
        if (ret==0)
-               regs->pc += 2;
+               regs->pc += instruction_size(instruction);
        return ret;
 }
 #endif /* CONFIG_CPU_SH2A */
@@ -682,7 +668,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
 
        err = do_fpu_inst(inst, regs);
        if (!err) {
-               regs->pc += 2;
+               regs->pc += instruction_size(inst);
                return;
        }
        /* not a FPU inst. */
index 7b0f66f033197b83d186231f6a16b5a12580130c..e146bafcd14fb11459e60f1db77549502b22644e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/sh/kernel/vsyscall.c
+ * arch/sh/kernel/vsyscall/vsyscall.c
  *
  *  Copyright (C) 2006 Paul Mundt
  *
index 351714694d6d4b9b6f81d183e774f1fc47e0e215..f3ddd2133e6f4edffb5a7fc7958350d9d1c2f680 100644 (file)
@@ -24,9 +24,10 @@ inline void __const_udelay(unsigned long xloops)
        __asm__("dmulu.l        %0, %2\n\t"
                "sts    mach, %0"
                : "=r" (xloops)
-               : "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy)
+               : "0" (xloops),
+                 "r" (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy)
                : "macl", "mach");
-       __delay(xloops * HZ);
+       __delay(xloops);
 }
 
 void __udelay(unsigned long usecs)
index 12f3d394dc28e97df806d7884cb92b890f681e92..253346d7b316fc1bd3a934f6e37c8b038c18a303 100644 (file)
@@ -218,6 +218,9 @@ endmenu
 
 menu "Memory management options"
 
+config QUICKLIST
+       def_bool y
+
 config MMU
         bool "Support for memory management hardware"
        depends on !CPU_SH2
@@ -300,6 +303,10 @@ config NODES_SHIFT
 config ARCH_FLATMEM_ENABLE
        def_bool y
 
+config MAX_ACTIVE_REGIONS
+       int
+       default "1"
+
 config ARCH_POPULATES_NODE_MAP
        def_bool y
 
index 0ecc117cade4525042e98b8240e1a0ebcda9b882..9207da67ff8a669841170bc73b600f9782d3037d 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/mm.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
 #include <asm/system.h>
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
index 4d030988b3681b3102e859d1f4464afbd23cdef8..8fe223a890ed4aaedf8947493f947041e4bed535 100644 (file)
@@ -67,6 +67,8 @@ void show_mem(void)
        printk("%d slab pages\n", slab);
        printk("%d pages shared\n", shared);
        printk("%d pages swap cached\n", cached);
+       printk(KERN_INFO "Total of %ld pages in page table cache\n",
+              quicklist_total_size());
 }
 
 #ifdef CONFIG_MMU
index 29d7cfd1c970b162adf4a13738c444e7048bd305..6773ed76e414bec7b851d94cebddf2fec48ff1e7 100644 (file)
@@ -28,7 +28,7 @@ int foo(void)
        DEFINE(AOFF_task_gid, offsetof(struct task_struct, gid));
        DEFINE(AOFF_task_euid, offsetof(struct task_struct, euid));
        DEFINE(AOFF_task_egid, offsetof(struct task_struct, egid));
-       /* DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); */
+       /* DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); */
        DEFINE(ASIZ_task_uid,   sizeof(current->uid));
        DEFINE(ASIZ_task_gid,   sizeof(current->gid));
        DEFINE(ASIZ_task_euid,  sizeof(current->euid));
index 3a69778c836627576d9f28d4cd86c9e928fb42ba..e3f5b8ed4c52c2c3a12f857bd3a27ea8bc62a627 100644 (file)
@@ -80,6 +80,7 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/        .long sys_utimensat
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
@@ -196,5 +197,6 @@ sunos_sys_table:
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys
+/*310*/        .long sunos_nosys
 
 #endif
index 0ace17bafba4e33c50168894596e87825ba9569b..ad55a9bb50ddedfe6febf63c54e7836b43c18b16 100644 (file)
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 
 #include <asm/system.h>
 #include <asm/page.h>
-#include <asm/pbm.h>
 #include <asm/ebus.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
+#include <asm/io.h>
 
 /* EBUS dma library. */
 
index a44fe47a3c2b53390edc8e13c26d0359462205da..c93a15b785fa28322b5c254040ceb510904e7113 100644 (file)
@@ -313,7 +313,7 @@ out:
        return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
        struct kprobe *cur = kprobe_running();
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -403,15 +403,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                if (post_kprobe_handler(args->regs))
                        ret = NOTIFY_STOP;
                break;
-       case DIE_GPF:
-       case DIE_PAGE_FAULT:
-               /* kprobe_running() needs smp_processor_id() */
-               preempt_disable();
-               if (kprobe_running() &&
-                   kprobe_fault_handler(args->regs, args->trapnr))
-                       ret = NOTIFY_STOP;
-               preempt_enable();
-               break;
        default:
                break;
        }
index 966861b212be5896d596f8d12d946293a8f8cf6a..cf9a75112d0fa9bdb9e00d09fa9c454ee7e8e17b 100644 (file)
 #include <linux/sched.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <linux/pci.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
-#include <asm/pbm.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/ebus.h>
@@ -48,10 +48,10 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
 #else
 
 /* List of all PCI controllers found in the system. */
-struct pci_controller_info *pci_controller_root = NULL;
+struct pci_pbm_info *pci_pbm_root = NULL;
 
-/* Each PCI controller found gets a unique index. */
-int pci_num_controllers = 0;
+/* Each PBM found gets a unique index. */
+int pci_num_pbms = 0;
 
 volatile int pci_poke_in_progress;
 volatile int pci_poke_cpu = -1;
@@ -291,7 +291,7 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
 
 /* Find each controller in the system, attach and initialize
  * software state structure for each and link into the
- * pci_controller_root.  Setup the controller enough such
+ * pci_pbm_root.  Setup the controller enough such
  * that bus scanning can be done.
  */
 static void __init pci_controller_probe(void)
@@ -377,7 +377,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        const char *type;
        u32 class;
 
-       dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+       dev = alloc_pci_dev();
        if (!dev)
                return NULL;
 
@@ -743,7 +743,6 @@ int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
 
 struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
 {
-       struct pci_controller_info *p = pbm->parent;
        struct device_node *node = pbm->prom_node;
        struct pci_dev *host_pdev;
        struct pci_bus *bus;
@@ -751,7 +750,7 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
        printk("PCI: Scanning PBM %s\n", node->full_name);
 
        /* XXX parent device? XXX */
-       bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
+       bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
        if (!bus) {
                printk(KERN_ERR "Failed to create bus for %s\n",
                       node->full_name);
@@ -776,10 +775,10 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
 
 static void __init pci_scan_each_controller_bus(void)
 {
-       struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
 
-       for (p = pci_controller_root; p; p = p->next)
-               p->scan_bus(p);
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
+               pbm->scan_bus(pbm);
 }
 
 extern void power_init(void);
@@ -787,7 +786,7 @@ extern void power_init(void);
 static int __init pcibios_init(void)
 {
        pci_controller_probe();
-       if (pci_controller_root == NULL)
+       if (pci_pbm_root == NULL)
                return 0;
 
        pci_scan_each_controller_bus();
@@ -922,10 +921,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
                                      enum pci_mmap_state mmap_state)
 {
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       struct pci_controller_info *p;
        unsigned long space_size, user_offset, user_size;
 
-       p = pbm->parent;
        if (mmap_state == pci_mmap_io) {
                space_size = (pbm->io_space.end -
                              pbm->io_space.start) + 1;
@@ -1078,11 +1075,7 @@ int pci_domain_nr(struct pci_bus *pbus)
        if (pbm == NULL || pbm->parent == NULL) {
                ret = -ENXIO;
        } else {
-               struct pci_controller_info *p = pbm->parent;
-
-               ret = p->index;
-               ret = ((ret << 1) +
-                      ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
+               ret = pbm->index;
        }
 
        return ret;
@@ -1093,17 +1086,12 @@ EXPORT_SYMBOL(pci_domain_nr);
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       struct pci_controller_info *p = pbm->parent;
-       int virt_irq, err;
+       int virt_irq;
 
-       if (!pbm->msi_num || !p->setup_msi_irq)
+       if (!pbm->setup_msi_irq)
                return -EINVAL;
 
-       err = p->setup_msi_irq(&virt_irq, pdev, desc);
-       if (err)
-               return err;
-
-       return 0;
+       return pbm->setup_msi_irq(&virt_irq, pdev, desc);
 }
 
 void arch_teardown_msi_irq(unsigned int virt_irq)
@@ -1111,12 +1099,11 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
        struct msi_desc *entry = get_irq_msi(virt_irq);
        struct pci_dev *pdev = entry->dev;
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       struct pci_controller_info *p = pbm->parent;
 
-       if (!pbm->msi_num || !p->setup_msi_irq)
+       if (!pbm->teardown_msi_irq)
                return;
 
-       return p->teardown_msi_irq(virt_irq, pdev);
+       return pbm->teardown_msi_irq(virt_irq, pdev);
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
index 1e6aeedf43c4201672e1f6ea61275f44f3dcd687..f974fefc3ebc273ceea972b6a936d21888326017 100644 (file)
 #include <linux/pci.h>
 #include <linux/device.h>
 
-#include <asm/pbm.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
+#include "pci_sun4v.h"
+
+static int config_out_of_range(struct pci_pbm_info *pbm,
+                              unsigned long bus,
+                              unsigned long devfn,
+                              unsigned long reg)
+{
+       if (bus < pbm->pci_first_busno ||
+           bus > pbm->pci_last_busno)
+               return 1;
+       return 0;
+}
+
+static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
+                                unsigned long bus,
+                                unsigned long devfn,
+                                unsigned long reg)
+{
+       unsigned long rbits = pbm->config_space_reg_bits;
+
+       if (config_out_of_range(pbm, bus, devfn, reg))
+               return NULL;
+
+       reg = (reg & ((1 << rbits) - 1));
+       devfn <<= rbits;
+       bus <<= rbits + 8;
+
+       return (void *) (pbm->config_space | bus | devfn | reg);
+}
+
+static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+                             int where, int size, u32 *value)
+{
+       struct pci_pbm_info *pbm = bus_dev->sysdata;
+       unsigned char bus = bus_dev->number;
+       u32 *addr;
+       u16 tmp16;
+       u8 tmp8;
+
+       if (bus_dev == pbm->pci_bus && devfn == 0x00)
+               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+                                                   size, value);
+
+       switch (size) {
+       case 1:
+               *value = 0xff;
+               break;
+       case 2:
+               *value = 0xffff;
+               break;
+       case 4:
+               *value = 0xffffffff;
+               break;
+       }
+
+       addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+       if (!addr)
+               return PCIBIOS_SUCCESSFUL;
+
+       switch (size) {
+       case 1:
+               pci_config_read8((u8 *)addr, &tmp8);
+               *value = (u32) tmp8;
+               break;
+
+       case 2:
+               if (where & 0x01) {
+                       printk("pci_read_config_word: misaligned reg [%x]\n",
+                              where);
+                       return PCIBIOS_SUCCESSFUL;
+               }
+               pci_config_read16((u16 *)addr, &tmp16);
+               *value = (u32) tmp16;
+               break;
+
+       case 4:
+               if (where & 0x03) {
+                       printk("pci_read_config_dword: misaligned reg [%x]\n",
+                              where);
+                       return PCIBIOS_SUCCESSFUL;
+               }
+               pci_config_read32(addr, value);
+               break;
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+                              int where, int size, u32 value)
+{
+       struct pci_pbm_info *pbm = bus_dev->sysdata;
+       unsigned char bus = bus_dev->number;
+       u32 *addr;
+
+       if (bus_dev == pbm->pci_bus && devfn == 0x00)
+               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+                                                    size, value);
+       addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+       if (!addr)
+               return PCIBIOS_SUCCESSFUL;
+
+       switch (size) {
+       case 1:
+               pci_config_write8((u8 *)addr, value);
+               break;
+
+       case 2:
+               if (where & 0x01) {
+                       printk("pci_write_config_word: misaligned reg [%x]\n",
+                              where);
+                       return PCIBIOS_SUCCESSFUL;
+               }
+               pci_config_write16((u16 *)addr, value);
+               break;
+
+       case 4:
+               if (where & 0x03) {
+                       printk("pci_write_config_dword: misaligned reg [%x]\n",
+                              where);
+                       return PCIBIOS_SUCCESSFUL;
+               }
+               pci_config_write32(addr, value);
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4u_pci_ops = {
+       .read =         sun4u_read_pci_cfg,
+       .write =        sun4u_write_pci_cfg,
+};
+
+static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+                             int where, int size, u32 *value)
+{
+       struct pci_pbm_info *pbm = bus_dev->sysdata;
+       u32 devhandle = pbm->devhandle;
+       unsigned int bus = bus_dev->number;
+       unsigned int device = PCI_SLOT(devfn);
+       unsigned int func = PCI_FUNC(devfn);
+       unsigned long ret;
+
+       if (bus_dev == pbm->pci_bus && devfn == 0x00)
+               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+                                                   size, value);
+       if (config_out_of_range(pbm, bus, devfn, where)) {
+               ret = ~0UL;
+       } else {
+               ret = pci_sun4v_config_get(devhandle,
+                               HV_PCI_DEVICE_BUILD(bus, device, func),
+                               where, size);
+       }
+       switch (size) {
+       case 1:
+               *value = ret & 0xff;
+               break;
+       case 2:
+               *value = ret & 0xffff;
+               break;
+       case 4:
+               *value = ret & 0xffffffff;
+               break;
+       };
+
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+                              int where, int size, u32 value)
+{
+       struct pci_pbm_info *pbm = bus_dev->sysdata;
+       u32 devhandle = pbm->devhandle;
+       unsigned int bus = bus_dev->number;
+       unsigned int device = PCI_SLOT(devfn);
+       unsigned int func = PCI_FUNC(devfn);
+       unsigned long ret;
+
+       if (bus_dev == pbm->pci_bus && devfn == 0x00)
+               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+                                                    size, value);
+       if (config_out_of_range(pbm, bus, devfn, where)) {
+               /* Do nothing. */
+       } else {
+               ret = pci_sun4v_config_put(devhandle,
+                               HV_PCI_DEVICE_BUILD(bus, device, func),
+                               where, size, value);
+       }
+       return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4v_pci_ops = {
+       .read =         sun4v_read_pci_cfg,
+       .write =        sun4v_write_pci_cfg,
+};
+
+void pci_get_pbm_props(struct pci_pbm_info *pbm)
+{
+       const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+
+       pbm->pci_first_busno = val[0];
+       pbm->pci_last_busno = val[1];
+
+       val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+       if (val) {
+               pbm->ino_bitmap = (((u64)val[1] << 32UL) |
+                                  ((u64)val[0] <<  0UL));
+       }
+}
 
 static void pci_register_legacy_regions(struct resource *io_res,
                                        struct resource *mem_res)
@@ -149,8 +357,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
 }
 
 /* Generic helper routines for PCI error reporting. */
-void pci_scan_for_target_abort(struct pci_controller_info *p,
-                              struct pci_pbm_info *pbm,
+void pci_scan_for_target_abort(struct pci_pbm_info *pbm,
                               struct pci_bus *pbus)
 {
        struct pci_dev *pdev;
@@ -165,18 +372,16 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
                                   PCI_STATUS_REC_TARGET_ABORT));
                if (error_bits) {
                        pci_write_config_word(pdev, PCI_STATUS, error_bits);
-                       printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
-                              p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-                              pci_name(pdev), status);
+                       printk("%s: Device %s saw Target Abort [%016x]\n",
+                              pbm->name, pci_name(pdev), status);
                }
        }
 
        list_for_each_entry(bus, &pbus->children, node)
-               pci_scan_for_target_abort(p, pbm, bus);
+               pci_scan_for_target_abort(pbm, bus);
 }
 
-void pci_scan_for_master_abort(struct pci_controller_info *p,
-                              struct pci_pbm_info *pbm,
+void pci_scan_for_master_abort(struct pci_pbm_info *pbm,
                               struct pci_bus *pbus)
 {
        struct pci_dev *pdev;
@@ -190,18 +395,16 @@ void pci_scan_for_master_abort(struct pci_controller_info *p,
                        (status & (PCI_STATUS_REC_MASTER_ABORT));
                if (error_bits) {
                        pci_write_config_word(pdev, PCI_STATUS, error_bits);
-                       printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
-                              p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-                              pci_name(pdev), status);
+                       printk("%s: Device %s received Master Abort [%016x]\n",
+                              pbm->name, pci_name(pdev), status);
                }
        }
 
        list_for_each_entry(bus, &pbus->children, node)
-               pci_scan_for_master_abort(p, pbm, bus);
+               pci_scan_for_master_abort(pbm, bus);
 }
 
-void pci_scan_for_parity_error(struct pci_controller_info *p,
-                              struct pci_pbm_info *pbm,
+void pci_scan_for_parity_error(struct pci_pbm_info *pbm,
                               struct pci_bus *pbus)
 {
        struct pci_dev *pdev;
@@ -216,12 +419,11 @@ void pci_scan_for_parity_error(struct pci_controller_info *p,
                                   PCI_STATUS_DETECTED_PARITY));
                if (error_bits) {
                        pci_write_config_word(pdev, PCI_STATUS, error_bits);
-                       printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
-                              p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
-                              pci_name(pdev), status);
+                       printk("%s: Device %s saw Parity Error [%016x]\n",
+                              pbm->name, pci_name(pdev), status);
                }
        }
 
        list_for_each_entry(bus, &pbus->children, node)
-               pci_scan_for_parity_error(p, pbm, bus);
+               pci_scan_for_parity_error(pbm, bus);
 }
index 0fe626631e12543bae2bd710d63bd885e63e3dc0..9198c1a0f7a5df0f9a2cd4bc12b23947080675ff 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 
-#include <asm/pbm.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
 
                               "i" (ASI_PHYS_BYPASS_EC_E) \
                             : "memory")
 
-/* Fire config space address format is nearly identical to
- * that of SCHIZO and PSYCHO, except that in order to accomodate
- * PCI-E extended config space the encoding can handle 12 bits
- * of register address:
- *
- *  32     28 27 20 19    15 14      12 11  2  1 0
- * -------------------------------------------------
- * |0 0 0 0 0| bus | device | function | reg | 0 0 |
- * -------------------------------------------------
- */
-#define FIRE_CONFIG_BASE(PBM)  ((PBM)->config_space)
-#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG)    \
-       (((unsigned long)(BUS)   << 20) |       \
-        ((unsigned long)(DEVFN) << 12)  |      \
-        ((unsigned long)(REG)))
-
-static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
-                                     unsigned char bus,
-                                     unsigned int devfn,
-                                     int where)
-{
-       if (!pbm)
-               return NULL;
-       return (void *)
-               (FIRE_CONFIG_BASE(pbm) |
-                FIRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-/* FIRE PCI configuration space accessors. */
-
-static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                            int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-       u16 tmp16;
-       u8 tmp8;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-                                                   size, value);
-       switch (size) {
-       case 1:
-               *value = 0xff;
-               break;
-       case 2:
-               *value = 0xffff;
-               break;
-       case 4:
-               *value = 0xffffffff;
-               break;
-       }
-
-       addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_read8((u8 *)addr, &tmp8);
-               *value = tmp8;
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_read_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read16((u16 *)addr, &tmp16);
-               *value = tmp16;
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_read_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-
-               pci_config_read32(addr, value);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                             int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-                                                    size, value);
-       addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_write8((u8 *)addr, value);
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_write_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write16((u16 *)addr, value);
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_write_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-
-               pci_config_write32(addr, value);
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_fire_ops = {
-       .read   =       fire_read_pci_cfg,
-       .write  =       fire_write_pci_cfg,
-};
-
-static void pbm_scan_bus(struct pci_controller_info *p,
-                        struct pci_pbm_info *pbm)
+static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
 {
        pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void pci_fire_scan_bus(struct pci_controller_info *p)
-{
-       struct device_node *dp;
-
-       if ((dp = p->pbm_A.prom_node) != NULL)
-               pbm_scan_bus(p, &p->pbm_A);
-
-       if ((dp = p->pbm_B.prom_node) != NULL)
-               pbm_scan_bus(p, &p->pbm_B);
 
        /* XXX register error interrupt handlers XXX */
 }
@@ -313,18 +168,25 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
 }
 
 static void pci_fire_pbm_init(struct pci_controller_info *p,
-                               struct device_node *dp, u32 portid)
+                             struct device_node *dp, u32 portid)
 {
        const struct linux_prom64_registers *regs;
        struct pci_pbm_info *pbm;
-       const u32 *ino_bitmap;
-       const unsigned int *busrange;
 
        if ((portid & 1) == 0)
                pbm = &p->pbm_A;
        else
                pbm = &p->pbm_B;
 
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       pbm->scan_bus = pci_fire_scan_bus;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 12;
+
+       pbm->index = pci_num_pbms++;
+
        pbm->portid = portid;
        pbm->parent = p;
        pbm->prom_node = dp;
@@ -338,13 +200,7 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
 
        pci_determine_mem_io_space(pbm);
 
-       ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
-       pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
-                          ((u64)ino_bitmap[0] <<  0UL));
-
-       busrange = of_get_property(dp, "bus-range", NULL);
-       pbm->pci_first_busno = busrange[0];
-       pbm->pci_last_busno = busrange[1];
+       pci_get_pbm_props(pbm);
 
        pci_fire_hw_init(pbm);
        pci_fire_pbm_iommu_init(pbm);
@@ -362,19 +218,11 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
        struct pci_controller_info *p;
        u32 portid = of_getintprop_default(dp, "portid", 0xff);
        struct iommu *iommu;
+       struct pci_pbm_info *pbm;
 
-       for (p = pci_controller_root; p; p = p->next) {
-               struct pci_pbm_info *pbm;
-
-               if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-                       continue;
-
-               pbm = (p->pbm_A.prom_node ?
-                      &p->pbm_A :
-                      &p->pbm_B);
-
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
                if (portid_compare(pbm->portid, portid)) {
-                       pci_fire_pbm_init(p, dp, portid);
+                       pci_fire_pbm_init(pbm->parent, dp, portid);
                        return;
                }
        }
@@ -395,14 +243,7 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
 
        p->pbm_B.iommu = iommu;
 
-       p->next = pci_controller_root;
-       pci_controller_root = p;
-
-       p->index = pci_num_controllers++;
-
-       p->scan_bus = pci_fire_scan_bus;
        /* XXX MSI support XXX */
-       p->pci_ops = &pci_fire_ops;
 
        /* Like PSYCHO and SCHIZO we have a 2GB aligned area
         * for memory space.
index 1208583fcb83b433c2abc7b3a3a60a528f0c1fde..f660c2b685ebfe6c8682dff6facfe8f8acaf9e8f 100644 (file)
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/iommu.h>
 
-extern struct pci_controller_info *pci_controller_root;
+/* The abstraction used here is that there are PCI controllers,
+ * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
+ * underneath.  Each PCI bus module uses an IOMMU (shared by both
+ * PBMs of a controller, or per-PBM), and if a streaming buffer
+ * is present, each PCI bus module has it's own. (ie. the IOMMU
+ * might be shared between PBMs, the STC is never shared)
+ * Furthermore, each PCI bus module controls it's own autonomous
+ * PCI bus.
+ */
+
+#define PCI_STC_FLUSHFLAG_INIT(STC) \
+       (*((STC)->strbuf_flushflag) = 0UL)
+#define PCI_STC_FLUSHFLAG_SET(STC) \
+       (*((STC)->strbuf_flushflag) != 0UL)
+
+struct pci_controller_info;
+
+struct pci_pbm_info {
+       struct pci_pbm_info             *next;
+       int                             index;
+
+       /* PCI controller we sit under. */
+       struct pci_controller_info      *parent;
+
+       /* Physical address base of controller registers. */
+       unsigned long                   controller_regs;
+
+       /* Physical address base of PBM registers. */
+       unsigned long                   pbm_regs;
+
+       /* Physical address of DMA sync register, if any.  */
+       unsigned long                   sync_reg;
+
+       /* Opaque 32-bit system bus Port ID. */
+       u32                             portid;
+
+       /* Opaque 32-bit handle used for hypervisor calls.  */
+       u32                             devhandle;
+
+       /* Chipset version information. */
+       int                             chip_type;
+#define PBM_CHIP_TYPE_SABRE            1
+#define PBM_CHIP_TYPE_PSYCHO           2
+#define PBM_CHIP_TYPE_SCHIZO           3
+#define PBM_CHIP_TYPE_SCHIZO_PLUS      4
+#define PBM_CHIP_TYPE_TOMATILLO                5
+       int                             chip_version;
+       int                             chip_revision;
+
+       /* Name used for top-level resources. */
+       char                            *name;
+
+       /* OBP specific information. */
+       struct device_node              *prom_node;
+       u64                             ino_bitmap;
+
+       /* PBM I/O and Memory space resources. */
+       struct resource                 io_space;
+       struct resource                 mem_space;
+
+       /* Base of PCI Config space, can be per-PBM or shared. */
+       unsigned long                   config_space;
+
+       /* This will be 12 on PCI-E controllers, 8 elsewhere.  */
+       unsigned long                   config_space_reg_bits;
+
+       /* State of 66MHz capabilities on this PBM. */
+       int                             is_66mhz_capable;
+       int                             all_devs_66mhz;
+
+#ifdef CONFIG_PCI_MSI
+       /* MSI info.  */
+       u32                             msiq_num;
+       u32                             msiq_ent_count;
+       u32                             msiq_first;
+       u32                             msiq_first_devino;
+       u32                             msi_num;
+       u32                             msi_first;
+       u32                             msi_data_mask;
+       u32                             msix_data_width;
+       u64                             msi32_start;
+       u64                             msi64_start;
+       u32                             msi32_len;
+       u32                             msi64_len;
+       void                            *msi_queues;
+       unsigned long                   *msi_bitmap;
+       int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
+                            struct msi_desc *entry);
+       void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
+#endif /* !(CONFIG_PCI_MSI) */
+
+       /* This PBM's streaming buffer. */
+       struct strbuf                   stc;
+
+       /* IOMMU state, potentially shared by both PBM segments. */
+       struct iommu                    *iommu;
+
+       /* Now things for the actual PCI bus probes. */
+       unsigned int                    pci_first_busno;
+       unsigned int                    pci_last_busno;
+       struct pci_bus                  *pci_bus;
+       void (*scan_bus)(struct pci_pbm_info *);
+       struct pci_ops                  *pci_ops;
+};
+
+struct pci_controller_info {
+       /* The PCI bus modules controlled by us. */
+       struct pci_pbm_info             pbm_A;
+       struct pci_pbm_info             pbm_B;
+};
+
+extern struct pci_pbm_info *pci_pbm_root;
 extern unsigned long pci_memspace_mask;
 
-extern int pci_num_controllers;
+extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
+extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize,
+                                u32 dma_offset, u32 dma_addr_mask);
+extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
 extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
@@ -30,9 +147,9 @@ extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
                                         u32 value);
 
 /* Error reporting support. */
-extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *);
 
 /* Configuration space access. */
 extern void pci_config_read8(u8 *addr, u8 *ret);
@@ -42,4 +159,7 @@ extern void pci_config_write8(u8 *addr, u8 val);
 extern void pci_config_write16(u16 *addr, u16 val);
 extern void pci_config_write32(u32 *addr, u32 val);
 
+extern struct pci_ops sun4u_pci_ops;
+extern struct pci_ops sun4v_pci_ops;
+
 #endif /* !(PCI_IMPL_H) */
index 9e405cbbcb0d244ca7cf81a2c57564b7aedfe0c0..dfd6f9f4790b852035a5143f77559163d7e587ad 100644 (file)
@@ -8,10 +8,12 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
+#include <linux/pci.h>
 
-#include <asm/pbm.h>
+#include <asm/oplib.h>
 
 #include "iommu_common.h"
+#include "pci_impl.h"
 
 #define PCI_STC_CTXMATCH_ADDR(STC, CTX)        \
        ((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
index 253d40ec2245209063ee16a971c0d02a7366a70f..598393a2df168d1e92910cc9bc2a6866bb933013 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/starfire.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -94,127 +94,6 @@ static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
                 PSYCHO_CONFIG_ENCODE(bus, devfn, where));
 }
 
-static int psycho_out_of_range(struct pci_pbm_info *pbm,
-                              unsigned char bus,
-                              unsigned char devfn)
-{
-       return ((pbm->parent == 0) ||
-               ((pbm == &pbm->parent->pbm_B) &&
-                (bus == pbm->pci_first_busno) &&
-                PCI_SLOT(devfn) > 8) ||
-               ((pbm == &pbm->parent->pbm_A) &&
-                (bus == pbm->pci_first_busno) &&
-                PCI_SLOT(devfn) > 8));
-}
-
-/* PSYCHO PCI configuration space accessors. */
-
-static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                              int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-       u16 tmp16;
-       u8 tmp8;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-                                                   size, value);
-
-       switch (size) {
-       case 1:
-               *value = 0xff;
-               break;
-       case 2:
-               *value = 0xffff;
-               break;
-       case 4:
-               *value = 0xffffffff;
-               break;
-       }
-
-       addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (psycho_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-       switch (size) {
-       case 1:
-               pci_config_read8((u8 *)addr, &tmp8);
-               *value = (u32) tmp8;
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_read_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read16((u16 *)addr, &tmp16);
-               *value = (u32) tmp16;
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_read_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read32(addr, value);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                               int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-                                                    size, value);
-       addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (psycho_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_write8((u8 *)addr, value);
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_write_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write16((u16 *)addr, value);
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_write_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write32(addr, value);
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops psycho_ops = {
-       .read =         psycho_read_pci_cfg,
-       .write =        psycho_write_pci_cfg,
-};
-
 /* PSYCHO error handling support. */
 enum psycho_error_type {
        UE_ERR, CE_ERR, PCI_ERR
@@ -265,12 +144,11 @@ static unsigned long stc_error_buf[128];
 static unsigned long stc_tag_buf[16];
 static unsigned long stc_line_buf[16];
 
-static void __psycho_check_one_stc(struct pci_controller_info *p,
-                                  struct pci_pbm_info *pbm,
+static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
                                   int is_pbm_a)
 {
        struct strbuf *strbuf = &pbm->stc;
-       unsigned long regbase = p->pbm_A.controller_regs;
+       unsigned long regbase = pbm->controller_regs;
        unsigned long err_base, tag_base, line_base;
        u64 control;
        int i;
@@ -326,9 +204,8 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
                        unsigned long errval = stc_error_buf[j];
                        if (errval != 0) {
                                saw_error++;
-                               printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n",
-                                      p->index,
-                                      (is_pbm_a ? 'A' : 'B'),
+                               printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
+                                      pbm->name,
                                       j,
                                       (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
                                       (errval & PSYCHO_STCERR_READ) ? 1 : 0);
@@ -337,18 +214,16 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
                if (saw_error != 0) {
                        unsigned long tagval = stc_tag_buf[i];
                        unsigned long lineval = stc_line_buf[i];
-                       printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
-                              p->index,
-                              (is_pbm_a ? 'A' : 'B'),
+                       printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
+                              pbm->name,
                               i,
                               ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
                               (tagval & PSYCHO_STCTAG_VPN),
                               ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
                               ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
-                       printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+                       printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
                               "V(%d)FOFN(%d)]\n",
-                              p->index,
-                              (is_pbm_a ? 'A' : 'B'),
+                              pbm->name,
                               i,
                               ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
                               ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
@@ -362,20 +237,13 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
        spin_unlock(&stc_buf_lock);
 }
 
-static void __psycho_check_stc_error(struct pci_controller_info *p,
+static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
                                     unsigned long afsr,
                                     unsigned long afar,
                                     enum psycho_error_type type)
 {
-       struct pci_pbm_info *pbm;
-
-       pbm = &p->pbm_A;
-       if (pbm->stc.strbuf_enabled)
-               __psycho_check_one_stc(p, pbm, 1);
-
-       pbm = &p->pbm_B;
-       if (pbm->stc.strbuf_enabled)
-               __psycho_check_one_stc(p, pbm, 0);
+       __psycho_check_one_stc(pbm,
+                              (pbm == &pbm->parent->pbm_A));
 }
 
 /* When an Uncorrectable Error or a PCI Error happens, we
@@ -413,12 +281,12 @@ static void __psycho_check_stc_error(struct pci_controller_info *p,
 #define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
 #define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
 #define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_controller_info *p,
+static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
                                     unsigned long afsr,
                                     unsigned long afar,
                                     enum psycho_error_type type)
 {
-       struct iommu *iommu = p->pbm_A.iommu;
+       struct iommu *iommu = pbm->iommu;
        unsigned long iommu_tag[16];
        unsigned long iommu_data[16];
        unsigned long flags;
@@ -449,8 +317,8 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
                        type_string = "ECC Error";
                        break;
                };
-               printk("PSYCHO%d: IOMMU Error, type[%s]\n",
-                      p->index, type_string);
+               printk("%s: IOMMU Error, type[%s]\n",
+                      pbm->name, type_string);
 
                /* Put the IOMMU into diagnostic mode and probe
                 * it's TLB for entries with error status.
@@ -465,7 +333,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
                psycho_write(iommu->iommu_control,
                             control | PSYCHO_IOMMU_CTRL_DENAB);
                for (i = 0; i < 16; i++) {
-                       unsigned long base = p->pbm_A.controller_regs;
+                       unsigned long base = pbm->controller_regs;
 
                        iommu_tag[i] =
                                psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
@@ -503,20 +371,20 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
                                type_string = "ECC Error";
                                break;
                        };
-                       printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
-                              p->index, i, type_string,
+                       printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
+                              pbm->name, i, type_string,
                               ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
                               ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
                               ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
                               (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
-                       printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-                              p->index, i,
+                       printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+                              pbm->name, i,
                               ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
                               ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
                               (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
                }
        }
-       __psycho_check_stc_error(p, afsr, afar, type);
+       __psycho_check_stc_error(pbm, afsr, afar, type);
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -541,9 +409,10 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
 
 static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
-       unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       struct pci_controller_info *p = pbm->parent;
+       unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
@@ -560,22 +429,22 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
        psycho_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: Uncorrectable Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & PSYCHO_UEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & PSYCHO_UEAFSR_PDRD) ?
                  "DMA Read" :
                  ((error_bits & PSYCHO_UEAFSR_PDWR) ?
                   "DMA Write" : "???")))));
-       printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
-              p->index,
+       printk("%s: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
+              pbm->name,
               (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL,
               (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL,
               (afsr & PSYCHO_UEAFSR_MID) >> 24UL,
               ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0));
-       printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar);
-       printk("PSYCHO%d: UE Secondary errors [", p->index);
+       printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: UE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & PSYCHO_UEAFSR_SPIO) {
                reported++;
@@ -593,8 +462,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
                printk("(none)");
        printk("]\n");
 
-       /* Interrogate IOMMU for error status. */
-       psycho_check_iommu_error(p, afsr, afar, UE_ERR);
+       /* Interrogate both IOMMUs for error status. */
+       psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
+       psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -618,9 +488,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 
 static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
-       unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
@@ -637,8 +507,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
        psycho_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: Correctable Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & PSYCHO_CEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & PSYCHO_CEAFSR_PDRD) ?
@@ -649,16 +519,16 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
        /* XXX Use syndrome and afar to print out module string just like
         * XXX UDB CE trap handler does... -DaveM
         */
-       printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+       printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
               "UPA_MID[%02lx] was_block(%d)\n",
-              p->index,
+              pbm->name,
               (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,
               (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,
               (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,
               (afsr & PSYCHO_CEAFSR_MID) >> 24UL,
               ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));
-       printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);
-       printk("PSYCHO%d: CE Secondary errors [", p->index);
+       printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: CE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & PSYCHO_CEAFSR_SPIO) {
                reported++;
@@ -773,8 +643,8 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
        psycho_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",
-              p->index, (is_pbm_a ? 'A' : 'B'),
+       printk("%s: PCI Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & PSYCHO_PCIAFSR_PMA) ?
                 "Master Abort" :
                 ((error_bits & PSYCHO_PCIAFSR_PTA) ?
@@ -783,15 +653,13 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
                   "Excessive Retries" :
                   ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
                    "Parity Error" : "???"))))));
-       printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
-              p->index, (is_pbm_a ? 'A' : 'B'),
+       printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+              pbm->name,
               (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
               (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
               (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
-       printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",
-              p->index, (is_pbm_a ? 'A' : 'B'), afar);
-       printk("PSYCHO%d(PBM%c): PCI Secondary errors [",
-              p->index, (is_pbm_a ? 'A' : 'B'));
+       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: PCI Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & PSYCHO_PCIAFSR_SMA) {
                reported++;
@@ -823,11 +691,11 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
         * a bug in the IOMMU support code or a PCI device driver.
         */
        if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
-               psycho_check_iommu_error(p, afsr, afar, PCI_ERR);
-               pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+               psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+               pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
-               pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+               pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
        /* For excessive retries, PSYCHO/PBM will abort the device
         * and there is no way to specifically check for excessive
@@ -837,7 +705,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
         */
 
        if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
-               pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+               pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
        return IRQ_HANDLED;
 }
@@ -847,34 +715,49 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
 #define  PSYCHO_ECCCTRL_EE      0x8000000000000000UL /* Enable ECC Checking */
 #define  PSYCHO_ECCCTRL_UE      0x4000000000000000UL /* Enable UE Interrupts */
 #define  PSYCHO_ECCCTRL_CE      0x2000000000000000UL /* Enable CE INterrupts */
-static void psycho_register_error_handlers(struct pci_controller_info *p)
+static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
        struct of_device *op = of_find_device_by_node(pbm->prom_node);
-       unsigned long base = p->pbm_A.controller_regs;
+       unsigned long base = pbm->controller_regs;
        u64 tmp;
+       int err;
 
        if (!op)
                return;
 
        /* Psycho interrupt property order is:
-        * 0: PCIERR PBM B INO
+        * 0: PCIERR INO for this PBM
         * 1: UE ERR
         * 2: CE ERR
         * 3: POWER FAIL
         * 4: SPARE HARDWARE
-        * 5: PCIERR PBM A INO
+        * 5: POWER MANAGEMENT
         */
 
        if (op->num_irqs < 6)
                return;
 
-       request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
-       request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
-       request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
-                   "PSYCHO PCIERR-A", &p->pbm_A);
-       request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
-                   "PSYCHO PCIERR-B", &p->pbm_B);
+       /* We really mean to ignore the return result here.  Two
+        * PCI controller share the same interrupt numbers and
+        * drive the same front-end hardware.  Whichever of the
+        * two get in here first will register the IRQ handler
+        * the second will just error out since we do not pass in
+        * IRQF_SHARED.
+        */
+       err = request_irq(op->irqs[1], psycho_ue_intr, 0,
+                         "PSYCHO_UE", pbm);
+       err = request_irq(op->irqs[2], psycho_ce_intr, 0,
+                         "PSYCHO_CE", pbm);
+
+       /* This one, however, ought not to fail.  We can just warn
+        * about it since the system can still operate properly even
+        * if this fails.
+        */
+       err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
+                         "PSYCHO_PCIERR", pbm);
+       if (err)
+               printk(KERN_WARNING "%s: Could not register PCIERR, "
+                      "err=%d\n", pbm->name, err);
 
        /* Enable UE and CE interrupts for controller. */
        psycho_write(base + PSYCHO_ECC_CTRL,
@@ -918,54 +801,45 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void pbm_scan_bus(struct pci_controller_info *p,
-                        struct pci_pbm_info *pbm)
+static void psycho_scan_bus(struct pci_pbm_info *pbm)
 {
+       pbm_config_busmastering(pbm);
+       pbm->is_66mhz_capable = 0;
        pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void psycho_scan_bus(struct pci_controller_info *p)
-{
-       pbm_config_busmastering(&p->pbm_B);
-       p->pbm_B.is_66mhz_capable = 0;
-       pbm_config_busmastering(&p->pbm_A);
-       p->pbm_A.is_66mhz_capable = 1;
-       pbm_scan_bus(p, &p->pbm_B);
-       pbm_scan_bus(p, &p->pbm_A);
 
        /* After the PCI bus scan is complete, we can register
         * the error interrupt handlers.
         */
-       psycho_register_error_handlers(p);
+       psycho_register_error_handlers(pbm);
 }
 
-static void psycho_iommu_init(struct pci_controller_info *p)
+static void psycho_iommu_init(struct pci_pbm_info *pbm)
 {
-       struct iommu *iommu = p->pbm_A.iommu;
+       struct iommu *iommu = pbm->iommu;
        unsigned long i;
        u64 control;
 
        /* Register addresses. */
-       iommu->iommu_control  = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE;
-       iommu->iommu_flush    = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH;
+       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
        /* PSYCHO's IOMMU lacks ctx flushing. */
        iommu->iommu_ctxflush = 0;
 
        /* We use the main control register of PSYCHO as the write
         * completion register.
         */
-       iommu->write_complete_reg = p->pbm_A.controller_regs + PSYCHO_CONTROL;
+       iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
 
        /*
         * Invalidate TLB Entries.
         */
-       control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
        control |= PSYCHO_IOMMU_CTRL_DENAB;
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
        for(i = 0; i < 16; i++) {
-               psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-               psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
+               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
        }
 
        /* Leave diag mode enabled for full-flushing done
@@ -973,17 +847,17 @@ static void psycho_iommu_init(struct pci_controller_info *p)
         */
        pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
 
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE,
+       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
                     __pa(iommu->page_table));
 
-       control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
        control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
        control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
 
        /* If necessary, hook us up for starfire IRQ translations. */
        if (this_is_starfire)
-               starfire_hookup(p->pbm_A.portid);
+               starfire_hookup(pbm->portid);
 }
 
 #define PSYCHO_IRQ_RETRY       0x1a00UL
@@ -998,36 +872,35 @@ static void psycho_iommu_init(struct pci_controller_info *p)
 #define  PSYCHO_PCIDIAG_IPAPAR  0x0000000000000002UL /* Invert PIO address parity    */
 #define  PSYCHO_PCIDIAG_LPBACK  0x0000000000000001UL /* Enable loopback mode         */
 
-static void psycho_controller_hwinit(struct pci_controller_info *p)
+static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
 {
        u64 tmp;
 
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5);
+       psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
 
        /* Enable arbiter for all PCI slots. */
-       tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
+       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp);
+       psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
 
-       tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL);
+       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp);
+       psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
 
        /* Disable DMA write / PIO read synchronization on
         * both PCI bus segments.
         * [ U2P Erratum 1243770, STP2223BGA data sheet ]
         */
-       tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG);
+       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp);
+       psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
 
-       tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG);
+       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
+       psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
 }
 
-static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
-                                  struct pci_pbm_info *pbm,
+static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
                                   int is_pbm_a)
 {
        unsigned long base = pbm->controller_regs;
@@ -1088,7 +961,6 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
 static void psycho_pbm_init(struct pci_controller_info *p,
                            struct device_node *dp, int is_pbm_a)
 {
-       unsigned int *busrange;
        struct property *prop;
        struct pci_pbm_info *pbm;
 
@@ -1097,6 +969,15 @@ static void psycho_pbm_init(struct pci_controller_info *p,
        else
                pbm = &p->pbm_B;
 
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       pbm->scan_bus = psycho_scan_bus;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 8;
+
+       pbm->index = pci_num_pbms++;
+
        pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
        pbm->chip_version = 0;
        prop = of_find_property(dp, "version#", NULL);
@@ -1117,12 +998,9 @@ static void psycho_pbm_init(struct pci_controller_info *p,
 
        pci_determine_mem_io_space(pbm);
 
-       prop = of_find_property(dp, "bus-range", NULL);
-       busrange = prop->value;
-       pbm->pci_first_busno = busrange[0];
-       pbm->pci_last_busno = busrange[1];
+       pci_get_pbm_props(pbm);
 
-       psycho_pbm_strbuf_init(p, pbm, is_pbm_a);
+       psycho_pbm_strbuf_init(pbm, is_pbm_a);
 }
 
 #define PSYCHO_CONFIGSPACE     0x001000000UL
@@ -1131,6 +1009,7 @@ void psycho_init(struct device_node *dp, char *model_name)
 {
        struct linux_prom64_registers *pr_regs;
        struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
        struct iommu *iommu;
        struct property *prop;
        u32 upa_portid;
@@ -1141,7 +1020,9 @@ void psycho_init(struct device_node *dp, char *model_name)
        if (prop)
                upa_portid = *(u32 *) prop->value;
 
-       for(p = pci_controller_root; p; p = p->next) {
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               struct pci_controller_info *p = pbm->parent;
+
                if (p->pbm_A.portid == upa_portid) {
                        is_pbm_a = (p->pbm_A.prom_node == NULL);
                        psycho_pbm_init(p, dp, is_pbm_a);
@@ -1161,14 +1042,8 @@ void psycho_init(struct device_node *dp, char *model_name)
        }
        p->pbm_A.iommu = p->pbm_B.iommu = iommu;
 
-       p->next = pci_controller_root;
-       pci_controller_root = p;
-
        p->pbm_A.portid = upa_portid;
        p->pbm_B.portid = upa_portid;
-       p->index = pci_num_controllers++;
-       p->scan_bus = psycho_scan_bus;
-       p->pci_ops = &psycho_ops;
 
        prop = of_find_property(dp, "reg", NULL);
        pr_regs = prop->value;
@@ -1185,9 +1060,9 @@ void psycho_init(struct device_node *dp, char *model_name)
         */
        pci_memspace_mask = 0x7fffffffUL;
 
-       psycho_controller_hwinit(p);
+       psycho_controller_hwinit(&p->pbm_A);
 
-       psycho_iommu_init(p);
+       psycho_iommu_init(&p->pbm_A);
 
        is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
        psycho_pbm_init(p, dp, is_pbm_a);
index 397862fbd9e1d0f46b7129471ace28ea58ae1a25..e2377796de894e6f08164cfca6f4870f4192eb36 100644 (file)
 #include <linux/interrupt.h>
 
 #include <asm/apb.h>
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/smp.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/of_device.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
 #define SABRE_MEMSPACE         0x100000000UL
 #define SABRE_MEMSPACE_SIZE    0x07fffffffUL
 
-/* UltraSparc-IIi Programmer's Manual, page 325, PCI
- * configuration space address format:
- * 
- *  32             24 23 16 15    11 10       8 7   2  1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define SABRE_CONFIG_BASE(PBM) \
-       ((PBM)->config_space | (1UL << 24))
-#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)   \
-       (((unsigned long)(BUS)   << 16) |       \
-        ((unsigned long)(DEVFN) << 8)  |       \
-        ((unsigned long)(REG)))
-
 static int hummingbird_p;
 static struct pci_bus *sabre_root_bus;
 
-static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
-                                    unsigned char bus,
-                                    unsigned int devfn,
-                                    int where)
-{
-       if (!pbm)
-               return NULL;
-       return (void *)
-               (SABRE_CONFIG_BASE(pbm) |
-                SABRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-static int sabre_out_of_range(unsigned char devfn)
-{
-       if (hummingbird_p)
-               return 0;
-
-       return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
-               ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
-               (PCI_SLOT(devfn) > 1));
-}
-
-static int __sabre_out_of_range(struct pci_pbm_info *pbm,
-                               unsigned char bus,
-                               unsigned char devfn)
-{
-       if (hummingbird_p)
-               return 0;
-
-       return ((pbm->parent == 0) ||
-               ((pbm == &pbm->parent->pbm_A) &&
-                (bus == pbm->pci_first_busno) &&
-                PCI_SLOT(devfn) > 8));
-}
-
-static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                               int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-       u16 tmp16;
-       u8 tmp8;
-
-       switch (size) {
-       case 1:
-               *value = 0xff;
-               break;
-       case 2:
-               *value = 0xffff;
-               break;
-       case 4:
-               *value = 0xffffffff;
-               break;
-       }
-
-       addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (__sabre_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_read8((u8 *) addr, &tmp8);
-               *value = tmp8;
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_read_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read16((u16 *) addr, &tmp16);
-               *value = tmp16;
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_read_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read32(addr, value);
-               break;
-       }
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
-                             int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus->sysdata;
-
-       if (bus == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_read_pci_cfg(bus, devfn, where,
-                                                   size, value);
-
-       if (!bus->number && sabre_out_of_range(devfn)) {
-               switch (size) {
-               case 1:
-                       *value = 0xff;
-                       break;
-               case 2:
-                       *value = 0xffff;
-                       break;
-               case 4:
-                       *value = 0xffffffff;
-                       break;
-               }
-               return PCIBIOS_SUCCESSFUL;
-       }
-
-       if (bus->number || PCI_SLOT(devfn))
-               return __sabre_read_pci_cfg(bus, devfn, where, size, value);
-
-       /* When accessing PCI config space of the PCI controller itself (bus
-        * 0, device slot 0, function 0) there are restrictions.  Each
-        * register must be accessed as it's natural size.  Thus, for example
-        * the Vendor ID must be accessed as a 16-bit quantity.
-        */
-
-       switch (size) {
-       case 1:
-               if (where < 8) {
-                       u32 tmp32;
-                       u16 tmp16;
-
-                       __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
-                       tmp16 = (u16) tmp32;
-                       if (where & 1)
-                               *value = tmp16 >> 8;
-                       else
-                               *value = tmp16 & 0xff;
-               } else
-                       return __sabre_read_pci_cfg(bus, devfn, where, 1, value);
-               break;
-
-       case 2:
-               if (where < 8)
-                       return __sabre_read_pci_cfg(bus, devfn, where, 2, value);
-               else {
-                       u32 tmp32;
-                       u8 tmp8;
-
-                       __sabre_read_pci_cfg(bus, devfn, where, 1, &tmp32);
-                       tmp8 = (u8) tmp32;
-                       *value = tmp8;
-                       __sabre_read_pci_cfg(bus, devfn, where + 1, 1, &tmp32);
-                       tmp8 = (u8) tmp32;
-                       *value |= tmp8 << 8;
-               }
-               break;
-
-       case 4: {
-               u32 tmp32;
-               u16 tmp16;
-
-               sabre_read_pci_cfg(bus, devfn, where, 2, &tmp32);
-               tmp16 = (u16) tmp32;
-               *value = tmp16;
-               sabre_read_pci_cfg(bus, devfn, where + 2, 2, &tmp32);
-               tmp16 = (u16) tmp32;
-               *value |= tmp16 << 16;
-               break;
-       }
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                                int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-
-       addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (__sabre_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_write8((u8 *) addr, value);
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_write_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write16((u16 *) addr, value);
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_write_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write32(addr, value);
-               break;
-       }
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
-                              int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus->sysdata;
-
-       if (bus == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_write_pci_cfg(bus, devfn, where,
-                                                    size, value);
-
-       if (bus->number)
-               return __sabre_write_pci_cfg(bus, devfn, where, size, value);
-
-       if (sabre_out_of_range(devfn))
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               if (where < 8) {
-                       u32 tmp32;
-                       u16 tmp16;
-
-                       __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
-                       tmp16 = (u16) tmp32;
-                       if (where & 1) {
-                               value &= 0x00ff;
-                               value |= tmp16 << 8;
-                       } else {
-                               value &= 0xff00;
-                               value |= tmp16;
-                       }
-                       tmp32 = (u32) tmp16;
-                       return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32);
-               } else
-                       return __sabre_write_pci_cfg(bus, devfn, where, 1, value);
-               break;
-       case 2:
-               if (where < 8)
-                       return __sabre_write_pci_cfg(bus, devfn, where, 2, value);
-               else {
-                       __sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff);
-                       __sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8);
-               }
-               break;
-       case 4:
-               sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff);
-               sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops sabre_ops = {
-       .read =         sabre_read_pci_cfg,
-       .write =        sabre_write_pci_cfg,
-};
-
 /* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_controller_info *p,
+static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
                                    unsigned long afsr,
                                    unsigned long afar)
 {
-       struct iommu *iommu = p->pbm_A.iommu;
+       struct iommu *iommu = pbm->iommu;
        unsigned long iommu_tag[16];
        unsigned long iommu_data[16];
        unsigned long flags;
@@ -526,8 +241,8 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
                        type_string = "Unknown";
                        break;
                };
-               printk("SABRE%d: IOMMU Error, type[%s]\n",
-                      p->index, type_string);
+               printk("%s: IOMMU Error, type[%s]\n",
+                      pbm->name, type_string);
 
                /* Enter diagnostic mode and probe for error'd
                 * entries in the IOTLB.
@@ -536,7 +251,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
                sabre_write(iommu->iommu_control,
                            (control | SABRE_IOMMUCTRL_DENAB));
                for (i = 0; i < 16; i++) {
-                       unsigned long base = p->pbm_A.controller_regs;
+                       unsigned long base = pbm->controller_regs;
 
                        iommu_tag[i] =
                                sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
@@ -566,13 +281,13 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
                                type_string = "Unknown";
                                break;
                        };
-                       printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
-                              p->index, i, tag, type_string,
+                       printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
+                              pbm->name, i, tag, type_string,
                               ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
                               ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
                               ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
-                       printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
-                              p->index, i, data,
+                       printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
+                              pbm->name, i, data,
                               ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
                               ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
                               ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
@@ -584,9 +299,9 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
 
 static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
-       unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
@@ -604,21 +319,21 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        sabre_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",
-              p->index,
+       printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
+              pbm->name,
               ((error_bits & SABRE_UEAFSR_PDRD) ?
                "DMA Read" :
                ((error_bits & SABRE_UEAFSR_PDWR) ?
                 "DMA Write" : "???")),
               ((error_bits & SABRE_UEAFSR_PDTE) ?
                ":Translation Error" : ""));
-       printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
-              p->index,
+       printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
+              pbm->name,
               (afsr & SABRE_UEAFSR_BMSK) >> 32UL,
               (afsr & SABRE_UEAFSR_OFF) >> 29UL,
               ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));
-       printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);
-       printk("SABRE%d: UE Secondary errors [", p->index);
+       printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: UE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & SABRE_UEAFSR_SDRD) {
                reported++;
@@ -637,16 +352,16 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       sabre_check_iommu_error(p, afsr, afar);
+       sabre_check_iommu_error(pbm, afsr, afar);
 
        return IRQ_HANDLED;
 }
 
 static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
-       unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
@@ -663,8 +378,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        sabre_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("SABRE%d: Correctable Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: Correctable Error, primary error type[%s]\n",
+              pbm->name,
               ((error_bits & SABRE_CEAFSR_PDRD) ?
                "DMA Read" :
                ((error_bits & SABRE_CEAFSR_PDWR) ?
@@ -673,15 +388,15 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        /* XXX Use syndrome and afar to print out module string just like
         * XXX UDB CE trap handler does... -DaveM
         */
-       printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+       printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
               "was_block(%d)\n",
-              p->index,
+              pbm->name,
               (afsr & SABRE_CEAFSR_ESYND) >> 48UL,
               (afsr & SABRE_CEAFSR_BMSK) >> 32UL,
               (afsr & SABRE_CEAFSR_OFF) >> 29UL,
               ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));
-       printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);
-       printk("SABRE%d: CE Secondary errors [", p->index);
+       printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: CE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & SABRE_CEAFSR_SDRD) {
                reported++;
@@ -698,13 +413,13 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
+static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
 {
        unsigned long csr_reg, csr, csr_error_bits;
        irqreturn_t ret = IRQ_NONE;
        u16 stat;
 
-       csr_reg = p->pbm_A.controller_regs + SABRE_PCICTRL;
+       csr_reg = pbm->controller_regs + SABRE_PCICTRL;
        csr = sabre_read(csr_reg);
        csr_error_bits =
                csr & SABRE_PCICTRL_SERR;
@@ -714,8 +429,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
 
                /* Log 'em.  */
                if (csr_error_bits & SABRE_PCICTRL_SERR)
-                       printk("SABRE%d: PCI SERR signal asserted.\n",
-                              p->index);
+                       printk("%s: PCI SERR signal asserted.\n",
+                              pbm->name);
                ret = IRQ_HANDLED;
        }
        pci_bus_read_config_word(sabre_root_bus, 0,
@@ -725,8 +440,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
                    PCI_STATUS_REC_TARGET_ABORT |
                    PCI_STATUS_REC_MASTER_ABORT |
                    PCI_STATUS_SIG_SYSTEM_ERROR)) {
-               printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
-                      p->index, stat);
+               printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
+                      pbm->name, stat);
                pci_bus_write_config_word(sabre_root_bus, 0,
                                          PCI_STATUS, 0xffff);
                ret = IRQ_HANDLED;
@@ -736,13 +451,13 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
 
 static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
+       struct pci_pbm_info *pbm = dev_id;
        unsigned long afsr_reg, afar_reg;
        unsigned long afsr, afar, error_bits;
        int reported;
 
-       afsr_reg = p->pbm_A.controller_regs + SABRE_PIOAFSR;
-       afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR;
+       afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
+       afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
 
        /* Latch error status. */
        afar = sabre_read(afar_reg);
@@ -755,12 +470,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
                 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
                 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
        if (!error_bits)
-               return sabre_pcierr_intr_other(p);
+               return sabre_pcierr_intr_other(pbm);
        sabre_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("SABRE%d: PCI Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: PCI Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & SABRE_PIOAFSR_PMA) ?
                 "Master Abort" :
                 ((error_bits & SABRE_PIOAFSR_PTA) ?
@@ -769,12 +484,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
                   "Excessive Retries" :
                   ((error_bits & SABRE_PIOAFSR_PPERR) ?
                    "Parity Error" : "???"))))));
-       printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",
-              p->index,
+       printk("%s: bytemask[%04lx] was_block(%d)\n",
+              pbm->name,
               (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
               (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
-       printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);
-       printk("SABRE%d: PCI Secondary errors [", p->index);
+       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: PCI Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & SABRE_PIOAFSR_SMA) {
                reported++;
@@ -806,11 +521,11 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
         * a bug in the IOMMU support code or a PCI device driver.
         */
        if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
-               sabre_check_iommu_error(p, afsr, afar);
-               pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+               sabre_check_iommu_error(pbm, afsr, afar);
+               pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
-               pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+               pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
        /* For excessive retries, SABRE/PBM will abort the device
         * and there is no way to specifically check for excessive
@@ -820,18 +535,18 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
         */
 
        if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
-               pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
+               pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
        return IRQ_HANDLED;
 }
 
-static void sabre_register_error_handlers(struct pci_controller_info *p)
+static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
        struct device_node *dp = pbm->prom_node;
        struct of_device *op;
        unsigned long base = pbm->controller_regs;
        u64 tmp;
+       int err;
 
        if (pbm->chip_type == PBM_CHIP_TYPE_SABRE)
                dp = dp->parent;
@@ -858,22 +573,31 @@ static void sabre_register_error_handlers(struct pci_controller_info *p)
                     SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
                     SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
 
-       request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p);
+       err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
+       if (err)
+               printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
+                      pbm->name, err);
 
        sabre_write(base + SABRE_CE_AFSR,
                    (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
                     SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
 
-       request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p);
-       request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED,
-                   "SABRE PCIERR", p);
+       err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
+       if (err)
+               printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
+                      pbm->name, err);
+       err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+                         "SABRE_PCIERR", pbm);
+       if (err)
+               printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
+                      pbm->name, err);
 
        tmp = sabre_read(base + SABRE_PCICTRL);
        tmp |= SABRE_PCICTRL_ERREN;
        sabre_write(base + SABRE_PCICTRL, tmp);
 }
 
-static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
+static void apb_init(struct pci_bus *sabre_bus)
 {
        struct pci_dev *pdev;
 
@@ -909,7 +633,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
        }
 }
 
-static void sabre_scan_bus(struct pci_controller_info *p)
+static void sabre_scan_bus(struct pci_pbm_info *pbm)
 {
        static int once;
        struct pci_bus *pbus;
@@ -918,7 +642,7 @@ static void sabre_scan_bus(struct pci_controller_info *p)
         * at 66Mhz, but the front side of APB runs at 33Mhz
         * for both segments.
         */
-       p->pbm_A.is_66mhz_capable = 0;
+       pbm->is_66mhz_capable = 0;
 
        /* This driver has not been verified to handle
         * multiple SABREs yet, so trap this.
@@ -932,41 +656,41 @@ static void sabre_scan_bus(struct pci_controller_info *p)
        }
        once++;
 
-       pbus = pci_scan_one_pbm(&p->pbm_A);
+       pbus = pci_scan_one_pbm(pbm);
        if (!pbus)
                return;
 
        sabre_root_bus = pbus;
 
-       apb_init(p, pbus);
+       apb_init(pbus);
 
-       sabre_register_error_handlers(p);
+       sabre_register_error_handlers(pbm);
 }
 
-static void sabre_iommu_init(struct pci_controller_info *p,
+static void sabre_iommu_init(struct pci_pbm_info *pbm,
                             int tsbsize, unsigned long dvma_offset,
                             u32 dma_mask)
 {
-       struct iommu *iommu = p->pbm_A.iommu;
+       struct iommu *iommu = pbm->iommu;
        unsigned long i;
        u64 control;
 
        /* Register addresses. */
-       iommu->iommu_control  = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE;
-       iommu->iommu_flush    = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH;
-       iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC;
+       iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
+       iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
+       iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
+       iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
        /* Sabre's IOMMU lacks ctx flushing. */
        iommu->iommu_ctxflush = 0;
                                         
        /* Invalidate TLB Entries. */
-       control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
        control |= SABRE_IOMMUCTRL_DENAB;
-       sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
 
        for(i = 0; i < 16; i++) {
-               sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-               sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+               sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
+               sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
        }
 
        /* Leave diag mode enabled for full-flushing done
@@ -974,10 +698,10 @@ static void sabre_iommu_init(struct pci_controller_info *p,
         */
        pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
 
-       sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE,
+       sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
                    __pa(iommu->page_table));
 
-       control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
        control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
        control |= SABRE_IOMMUCTRL_ENAB;
        switch(tsbsize) {
@@ -992,22 +716,24 @@ static void sabre_iommu_init(struct pci_controller_info *p,
                prom_halt();
                break;
        }
-       sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
 }
 
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
+static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
 {
-       struct pci_pbm_info *pbm;
-
-       pbm = &p->pbm_A;
        pbm->name = dp->full_name;
        printk("%s: SABRE PCI Bus Module\n", pbm->name);
 
+       pbm->scan_bus = sabre_scan_bus;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 8;
+
+       pbm->index = pci_num_pbms++;
+
        pbm->chip_type = PBM_CHIP_TYPE_SABRE;
        pbm->parent = p;
        pbm->prom_node = dp;
-       pbm->pci_first_busno = p->pci_first_busno;
-       pbm->pci_last_busno = p->pci_last_busno;
+       pci_get_pbm_props(pbm);
 
        pci_determine_mem_io_space(pbm);
 }
@@ -1016,9 +742,9 @@ void sabre_init(struct device_node *dp, char *model_name)
 {
        const struct linux_prom64_registers *pr_regs;
        struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
        struct iommu *iommu;
        int tsbsize;
-       const u32 *busrange;
        const u32 *vdma;
        u32 upa_portid, dma_mask;
        u64 clear_irq;
@@ -1053,17 +779,15 @@ void sabre_init(struct device_node *dp, char *model_name)
                prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
                prom_halt();
        }
-       p->pbm_A.iommu = iommu;
+       pbm = &p->pbm_A;
+       pbm->iommu = iommu;
 
        upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-       p->next = pci_controller_root;
-       pci_controller_root = p;
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
 
-       p->pbm_A.portid = upa_portid;
-       p->index = pci_num_controllers++;
-       p->scan_bus = sabre_scan_bus;
-       p->pci_ops = &sabre_ops;
+       pbm->portid = upa_portid;
 
        /*
         * Map in SABRE register set and report the presence of this SABRE.
@@ -1074,26 +798,26 @@ void sabre_init(struct device_node *dp, char *model_name)
        /*
         * First REG in property is base of entire SABRE register space.
         */
-       p->pbm_A.controller_regs = pr_regs[0].phys_addr;
+       pbm->controller_regs = pr_regs[0].phys_addr;
 
        /* Clear interrupts */
 
        /* PCI first */
        for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-               sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
 
        /* Then OBIO */
        for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-               sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
 
        /* Error interrupts are enabled later after the bus scan. */
-       sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL,
+       sabre_write(pbm->controller_regs + SABRE_PCICTRL,
                    (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
                     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
 
        /* Now map in PCI config space for entire SABRE. */
-       p->pbm_A.config_space =
-               (p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
+       pbm->config_space =
+               (pbm->controller_regs + SABRE_CONFIGSPACE);
 
        vdma = of_get_property(dp, "virtual-dma", NULL);
 
@@ -1117,14 +841,10 @@ void sabre_init(struct device_node *dp, char *model_name)
                        prom_halt();
        }
 
-       sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
-
-       busrange = of_get_property(dp, "bus-range", NULL);
-       p->pci_first_busno = busrange[0];
-       p->pci_last_busno = busrange[1];
+       sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
 
        /*
         * Look for APB underneath.
         */
-       sabre_pbm_init(p, dp);
+       sabre_pbm_init(p, pbm, dp);
 }
index 91a7385e5d32798652fc8c9f74727275909a8fc8..ae76898bbe2b0fcfa239669f31a794eb56191935 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/oplib.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
@@ -103,125 +104,6 @@ static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,
                 SCHIZO_CONFIG_ENCODE(bus, devfn, where));
 }
 
-/* Just make sure the bus number is in range.  */
-static int schizo_out_of_range(struct pci_pbm_info *pbm,
-                              unsigned char bus,
-                              unsigned char devfn)
-{
-       if (bus < pbm->pci_first_busno ||
-           bus > pbm->pci_last_busno)
-               return 1;
-       return 0;
-}
-
-/* SCHIZO PCI configuration space accessors. */
-
-static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                              int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-       u16 tmp16;
-       u8 tmp8;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-                                                   size, value);
-       switch (size) {
-       case 1:
-               *value = 0xff;
-               break;
-       case 2:
-               *value = 0xffff;
-               break;
-       case 4:
-               *value = 0xffffffff;
-               break;
-       }
-
-       addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (schizo_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-       switch (size) {
-       case 1:
-               pci_config_read8((u8 *)addr, &tmp8);
-               *value = tmp8;
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_read_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read16((u16 *)addr, &tmp16);
-               *value = tmp16;
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_read_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_read32(addr, value);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                               int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       unsigned char bus = bus_dev->number;
-       u32 *addr;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-                                                    size, value);
-       addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
-       if (!addr)
-               return PCIBIOS_SUCCESSFUL;
-
-       if (schizo_out_of_range(pbm, bus, devfn))
-               return PCIBIOS_SUCCESSFUL;
-
-       switch (size) {
-       case 1:
-               pci_config_write8((u8 *)addr, value);
-               break;
-
-       case 2:
-               if (where & 0x01) {
-                       printk("pci_write_config_word: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-               pci_config_write16((u16 *)addr, value);
-               break;
-
-       case 4:
-               if (where & 0x03) {
-                       printk("pci_write_config_dword: misaligned reg [%x]\n",
-                              where);
-                       return PCIBIOS_SUCCESSFUL;
-               }
-
-               pci_config_write32(addr, value);
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops schizo_ops = {
-       .read =         schizo_read_pci_cfg,
-       .write =        schizo_write_pci_cfg,
-};
-
 /* SCHIZO error handling support. */
 enum schizo_error_type {
        UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
@@ -238,25 +120,6 @@ static unsigned long stc_line_buf[16];
 #define SCHIZO_PCIERR_B_INO    0x33 /* PBM B PCI bus error */
 #define SCHIZO_SERR_INO                0x34 /* Safari interface error */
 
-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
-{
-       ino &= IMAP_INO;
-       if (p->pbm_A.ino_bitmap & (1UL << ino))
-               return &p->pbm_A;
-       if (p->pbm_B.ino_bitmap & (1UL << ino))
-               return &p->pbm_B;
-
-       printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
-              "PBM_A[%016lx] PBM_B[%016lx]",
-              p->index, ino,
-              p->pbm_A.ino_bitmap,
-              p->pbm_B.ino_bitmap);
-       printk("PCI%d: Using PBM_A, report this problem immediately.\n",
-              p->index);
-
-       return &p->pbm_A;
-}
-
 #define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
 #define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
 #define SCHIZO_STC_LINE        0xbb00UL /* --> 0xbb80 */
@@ -522,9 +385,10 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
 
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
-       unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       struct pci_controller_info *p = pbm->parent;
+       unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported, limit;
 
@@ -549,28 +413,28 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
        schizo_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: Uncorrectable Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & SCHIZO_UEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SCHIZO_UEAFSR_PDRD) ?
                  "DMA Read" :
                  ((error_bits & SCHIZO_UEAFSR_PDWR) ?
                   "DMA Write" : "???")))));
-       printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
-              p->index,
+       printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+              pbm->name,
               (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
               (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
               (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
-       printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
-              p->index,
+       printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+              pbm->name,
               (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
               (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
               (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
               (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
               (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
-       printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
-       printk("PCI%d: UE Secondary errors [", p->index);
+       printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: UE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & SCHIZO_UEAFSR_SPIO) {
                reported++;
@@ -610,9 +474,9 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 
 static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
-       unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
-       unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
+       struct pci_pbm_info *pbm = dev_id;
+       unsigned long afsr_reg = pbm->controller_regs + SCHIZO_CE_AFSR;
+       unsigned long afar_reg = pbm->controller_regs + SCHIZO_CE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported, limit;
 
@@ -637,8 +501,8 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
        schizo_write(afsr_reg, error_bits);
 
        /* Log the error. */
-       printk("PCI%d: Correctable Error, primary error type[%s]\n",
-              p->index,
+       printk("%s: Correctable Error, primary error type[%s]\n",
+              pbm->name,
               (((error_bits & SCHIZO_CEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SCHIZO_CEAFSR_PDRD) ?
@@ -649,20 +513,20 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
        /* XXX Use syndrome and afar to print out module string just like
         * XXX UDB CE trap handler does... -DaveM
         */
-       printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
-              p->index,
+       printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+              pbm->name,
               (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
               (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
               (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
-       printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
-              p->index,
+       printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+              pbm->name,
               (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
               (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
               (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
               (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
               (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
-       printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
-       printk("PCI%d: CE Secondary errors [", p->index);
+       printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+       printk("%s: CE Secondary errors [", pbm->name);
        reported = 0;
        if (afsr & SCHIZO_CEAFSR_SPIO) {
                reported++;
@@ -881,10 +745,10 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
         */
        if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
                schizo_check_iommu_error(p, PCI_ERR);
-               pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+               pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
-               pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+               pci_scan_for_master_abort(pbm, pbm->pci_bus);
 
        /* For excessive retries, PSYCHO/PBM will abort the device
         * and there is no way to specifically check for excessive
@@ -894,7 +758,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
         */
 
        if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
-               pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+               pci_scan_for_parity_error(pbm, pbm->pci_bus);
 
        return IRQ_HANDLED;
 }
@@ -940,22 +804,23 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
  */
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
-       struct pci_controller_info *p = dev_id;
+       struct pci_pbm_info *pbm = dev_id;
+       struct pci_controller_info *p = pbm->parent;
        u64 errlog;
 
-       errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
-       schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
+       errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
                     errlog & ~(SAFARI_ERRLOG_ERROUT));
 
        if (!(errlog & BUS_ERROR_UNMAP)) {
-               printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
-                      p->index, errlog);
+               printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
+                      pbm->name, errlog);
 
                return IRQ_HANDLED;
        }
 
-       printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
-              p->index);
+       printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+              pbm->name);
        schizo_check_iommu_error(p, SAFARI_ERR);
 
        return IRQ_HANDLED;
@@ -972,6 +837,16 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 #define SCHIZO_SAFARI_IRQCTRL  0x10010UL
 #define  SCHIZO_SAFIRQCTRL_EN   0x8000000000000000UL
 
+static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
+{
+       ino &= IMAP_INO;
+
+       if (pbm->ino_bitmap & (1UL << ino))
+               return 1;
+
+       return 0;
+}
+
 /* How the Tomatillo IRQs are routed around is pure guesswork here.
  *
  * All the Tomatillo devices I see in prtconf dumps seem to have only
@@ -986,11 +861,11 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
  * PCI bus units of the same Tomatillo.  I still have not really
  * figured this out...
  */
-static void tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct pci_pbm_info *pbm;
-       struct of_device *op;
+       struct of_device *op = of_find_device_by_node(pbm->prom_node);
        u64 tmp, err_mask, err_no_mask;
+       int err;
 
        /* Tomatillo IRQ property layout is:
         * 0: PCIERR
@@ -1000,44 +875,42 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
         * 4: POWER FAIL?
         */
 
-       pbm = pbm_for_ino(p, SCHIZO_UE_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
-                           "TOMATILLO_UE", p);
-
-       pbm = pbm_for_ino(p, SCHIZO_CE_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
-                           "TOMATILLO CE", p);
-
-       pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-                           "TOMATILLO PCIERR-A", pbm);
-
-
-       pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-                           "TOMATILLO PCIERR-B", pbm);
-
-       pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
-                           "TOMATILLO SERR", p);
+       if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+               err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+                                 "TOMATILLO_UE", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register UE, "
+                              "err=%d\n", pbm->name, err);
+       }
+       if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+               err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+                                 "TOMATILLO_CE", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register CE, "
+                              "err=%d\n", pbm->name, err);
+       }
+       err = 0;
+       if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+               err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+                                 "TOMATILLO_PCIERR", pbm);
+       } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+               err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+                                 "TOMATILLO_PCIERR", pbm);
+       }
+       if (err)
+               printk(KERN_WARNING "%s: Could not register PCIERR, "
+                      "err=%d\n", pbm->name, err);
+
+       if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+               err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+                                 "TOMATILLO_SERR", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register SERR, "
+                              "err=%d\n", pbm->name, err);
+       }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
-
-       schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
+       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
                     (SCHIZO_ECCCTRL_EE |
                      SCHIZO_ECCCTRL_UE |
                      SCHIZO_ECCCTRL_CE));
@@ -1053,15 +926,10 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
 
        err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-       tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
-       tmp |= err_mask;
-       tmp &= ~err_no_mask;
-       schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
-       tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
        err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
                    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -1070,8 +938,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
                    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
                    SCHIZO_PCIAFSR_STTO);
 
-       schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
-       schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
 
        err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
                    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -1083,22 +950,18 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
                    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
                    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
-       schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
                     (SCHIZO_SAFERRCTRL_EN | err_mask));
 
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
-                    (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
-       schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
                     (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
-static void schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct pci_pbm_info *pbm;
-       struct of_device *op;
+       struct of_device *op = of_find_device_by_node(pbm->prom_node);
        u64 tmp, err_mask, err_no_mask;
+       int err;
 
        /* Schizo IRQ property layout is:
         * 0: PCIERR
@@ -1108,39 +971,42 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
         * 4: POWER FAIL?
         */
 
-       pbm = pbm_for_ino(p, SCHIZO_UE_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
-                           "SCHIZO_UE", p);
-
-       pbm = pbm_for_ino(p, SCHIZO_CE_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
-                           "SCHIZO CE", p);
-
-       pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-                           "SCHIZO PCIERR-A", pbm);
-
-
-       pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
-                           "SCHIZO PCIERR-B", pbm);
-
-       pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
-       op = of_find_device_by_node(pbm->prom_node);
-       if (op)
-               request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
-                           "SCHIZO SERR", p);
+       if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+               err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+                                 "SCHIZO_UE", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register UE, "
+                              "err=%d\n", pbm->name, err);
+       }
+       if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+               err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+                                 "SCHIZO_CE", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register CE, "
+                              "err=%d\n", pbm->name, err);
+       }
+       err = 0;
+       if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+               err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+                                 "SCHIZO_PCIERR", pbm);
+       } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+               err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+                                 "SCHIZO_PCIERR", pbm);
+       }
+       if (err)
+               printk(KERN_WARNING "%s: Could not register PCIERR, "
+                      "err=%d\n", pbm->name, err);
+
+       if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+               err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+                                 "SCHIZO_SERR", pbm);
+               if (err)
+                       printk(KERN_WARNING "%s: Could not register SERR, "
+                              "err=%d\n", pbm->name, err);
+       }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
+       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
                     (SCHIZO_ECCCTRL_EE |
                      SCHIZO_ECCCTRL_UE |
                      SCHIZO_ECCCTRL_CE));
@@ -1159,25 +1025,12 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
-       tmp |= err_mask;
-       tmp &= ~err_no_mask;
-       schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
-       schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR,
-                    (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-                     SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-                     SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-                     SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-                     SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-                     SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
-
-       tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
 
-       schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
                     (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
                      SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
                      SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
@@ -1210,11 +1063,8 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
                      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
                     (SCHIZO_SAFERRCTRL_EN | err_mask));
-
-       schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
-                    (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1234,27 +1084,19 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_pbm_info *pbm)
 {
-       pbm_config_busmastering(&p->pbm_B);
-       p->pbm_B.is_66mhz_capable =
-               (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
-                != NULL);
-       pbm_config_busmastering(&p->pbm_A);
-       p->pbm_A.is_66mhz_capable =
-               (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
+       pbm_config_busmastering(pbm);
+       pbm->is_66mhz_capable =
+               (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
                 != NULL);
 
-       p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
-       p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
+       pbm->pci_bus = pci_scan_one_pbm(pbm);
 
-       /* After the PCI bus scan is complete, we can register
-        * the error interrupt handlers.
-        */
-       if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
-               tomatillo_register_error_handlers(p);
+       if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+               tomatillo_register_error_handlers(pbm);
        else
-               schizo_register_error_handlers(p);
+               schizo_register_error_handlers(pbm);
 }
 
 #define SCHIZO_STRBUF_CONTROL          (0x02800UL)
@@ -1491,10 +1333,8 @@ static void schizo_pbm_init(struct pci_controller_info *p,
                            int chip_type)
 {
        const struct linux_prom64_registers *regs;
-       const unsigned int *busrange;
        struct pci_pbm_info *pbm;
        const char *chipset_name;
-       const u32 *ino_bitmap;
        int is_pbm_a;
 
        switch (chip_type) {
@@ -1531,6 +1371,15 @@ static void schizo_pbm_init(struct pci_controller_info *p,
        else
                pbm = &p->pbm_B;
 
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       pbm->scan_bus = schizo_scan_bus;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 8;
+
+       pbm->index = pci_num_pbms++;
+
        pbm->portid = portid;
        pbm->parent = p;
        pbm->prom_node = dp;
@@ -1555,13 +1404,7 @@ static void schizo_pbm_init(struct pci_controller_info *p,
 
        pci_determine_mem_io_space(pbm);
 
-       ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
-       pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
-                          ((u64)ino_bitmap[0] <<  0UL));
-
-       busrange = of_get_property(dp, "bus-range", NULL);
-       pbm->pci_first_busno = busrange[0];
-       pbm->pci_last_busno = busrange[1];
+       pci_get_pbm_props(pbm);
 
        schizo_pbm_iommu_init(pbm);
        schizo_pbm_strbuf_init(pbm);
@@ -1580,23 +1423,15 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
 static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
 {
        struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
 
        portid = of_getintprop_default(dp, "portid", 0xff);
 
-       for (p = pci_controller_root; p; p = p->next) {
-               struct pci_pbm_info *pbm;
-
-               if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-                       continue;
-
-               pbm = (p->pbm_A.prom_node ?
-                      &p->pbm_A :
-                      &p->pbm_B);
-
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
                if (portid_compare(pbm->portid, portid, chip_type)) {
-                       schizo_pbm_init(p, dp, portid, chip_type);
+                       schizo_pbm_init(pbm->parent, dp, portid, chip_type);
                        return;
                }
        }
@@ -1617,13 +1452,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
 
        p->pbm_B.iommu = iommu;
 
-       p->next = pci_controller_root;
-       pci_controller_root = p;
-
-       p->index = pci_num_controllers++;
-       p->scan_bus = schizo_scan_bus;
-       p->pci_ops = &schizo_ops;
-
        /* Like PSYCHO we have a 2GB aligned area for memory space. */
        pci_memspace_mask = 0x7fffffffUL;
 
index 1ccf4c9a9a4330b4b40cfd21bb50e116ebf744af..34df4047587a4db2c95506410e5e2edd96b35837 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/irq.h>
 #include <linux/msi.h>
 
-#include <asm/pbm.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
 #include <asm/upa.h>
@@ -594,112 +593,15 @@ const struct pci_iommu_ops pci_sun4v_iommu_ops = {
        .dma_sync_sg_for_cpu            = pci_4v_dma_sync_sg_for_cpu,
 };
 
-static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
-{
-       if (bus < pbm->pci_first_busno ||
-           bus > pbm->pci_last_busno)
-               return 1;
-       return 0;
-}
-
-static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                                 int where, int size, u32 *value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       u32 devhandle = pbm->devhandle;
-       unsigned int bus = bus_dev->number;
-       unsigned int device = PCI_SLOT(devfn);
-       unsigned int func = PCI_FUNC(devfn);
-       unsigned long ret;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
-                                                   size, value);
-       if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
-               ret = ~0UL;
-       } else {
-               ret = pci_sun4v_config_get(devhandle,
-                               HV_PCI_DEVICE_BUILD(bus, device, func),
-                               where, size);
-#if 0
-               printk("rcfg: [%x:%x:%x:%d]=[%lx]\n",
-                      devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
-                      where, size, ret);
-#endif
-       }
-       switch (size) {
-       case 1:
-               *value = ret & 0xff;
-               break;
-       case 2:
-               *value = ret & 0xffff;
-               break;
-       case 4:
-               *value = ret & 0xffffffff;
-               break;
-       };
-
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
-                                  int where, int size, u32 value)
-{
-       struct pci_pbm_info *pbm = bus_dev->sysdata;
-       u32 devhandle = pbm->devhandle;
-       unsigned int bus = bus_dev->number;
-       unsigned int device = PCI_SLOT(devfn);
-       unsigned int func = PCI_FUNC(devfn);
-       unsigned long ret;
-
-       if (bus_dev == pbm->pci_bus && devfn == 0x00)
-               return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
-                                                    size, value);
-       if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
-               /* Do nothing. */
-       } else {
-               ret = pci_sun4v_config_put(devhandle,
-                               HV_PCI_DEVICE_BUILD(bus, device, func),
-                               where, size, value);
-#if 0
-               printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n",
-                      devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
-                      where, size, value, ret);
-#endif
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_sun4v_ops = {
-       .read =         pci_sun4v_read_pci_cfg,
-       .write =        pci_sun4v_write_pci_cfg,
-};
-
-
-static void pbm_scan_bus(struct pci_controller_info *p,
-                        struct pci_pbm_info *pbm)
-{
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void pci_sun4v_scan_bus(struct pci_controller_info *p)
+static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
 {
        struct property *prop;
        struct device_node *dp;
 
-       if ((dp = p->pbm_A.prom_node) != NULL) {
-               prop = of_find_property(dp, "66mhz-capable", NULL);
-               p->pbm_A.is_66mhz_capable = (prop != NULL);
-
-               pbm_scan_bus(p, &p->pbm_A);
-       }
-       if ((dp = p->pbm_B.prom_node) != NULL) {
-               prop = of_find_property(dp, "66mhz-capable", NULL);
-               p->pbm_B.is_66mhz_capable = (prop != NULL);
-
-               pbm_scan_bus(p, &p->pbm_B);
-       }
+       dp = pbm->prom_node;
+       prop = of_find_property(dp, "66mhz-capable", NULL);
+       pbm->is_66mhz_capable = (prop != NULL);
+       pbm->pci_bus = pci_scan_one_pbm(pbm);
 
        /* XXX register error interrupt handlers XXX */
 }
@@ -802,20 +704,6 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
                       pbm->name, sz);
 }
 
-static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
-{
-       struct property *prop;
-       unsigned int *busrange;
-
-       prop = of_find_property(pbm->prom_node, "bus-range", NULL);
-
-       busrange = prop->value;
-
-       pbm->pci_first_busno = busrange[0];
-       pbm->pci_last_busno = busrange[1];
-
-}
-
 #ifdef CONFIG_PCI_MSI
 struct pci_sun4v_msiq_entry {
        u64             version_type;
@@ -1019,114 +907,6 @@ h_error:
        return -EINVAL;
 }
 
-static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
-{
-       const u32 *val;
-       int len;
-
-       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
-       if (!val || len != 4)
-               goto no_msi;
-       pbm->msiq_num = *val;
-       if (pbm->msiq_num) {
-               const struct msiq_prop {
-                       u32 first_msiq;
-                       u32 num_msiq;
-                       u32 first_devino;
-               } *mqp;
-               const struct msi_range_prop {
-                       u32 first_msi;
-                       u32 num_msi;
-               } *mrng;
-               const struct addr_range_prop {
-                       u32 msi32_high;
-                       u32 msi32_low;
-                       u32 msi32_len;
-                       u32 msi64_high;
-                       u32 msi64_low;
-                       u32 msi64_len;
-               } *arng;
-
-               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-
-               pbm->msiq_ent_count = *val;
-
-               mqp = of_get_property(pbm->prom_node,
-                                     "msi-eq-to-devino", &len);
-               if (!mqp || len != sizeof(struct msiq_prop))
-                       goto no_msi;
-
-               pbm->msiq_first = mqp->first_msiq;
-               pbm->msiq_first_devino = mqp->first_devino;
-
-               val = of_get_property(pbm->prom_node, "#msi", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msi_num = *val;
-
-               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
-               if (!mrng || len != sizeof(struct msi_range_prop))
-                       goto no_msi;
-               pbm->msi_first = mrng->first_msi;
-
-               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msi_data_mask = *val;
-
-               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
-               if (!val || len != 4)
-                       goto no_msi;
-               pbm->msix_data_width = *val;
-
-               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
-                                      &len);
-               if (!arng || len != sizeof(struct addr_range_prop))
-                       goto no_msi;
-               pbm->msi32_start = ((u64)arng->msi32_high << 32) |
-                       (u64) arng->msi32_low;
-               pbm->msi64_start = ((u64)arng->msi64_high << 32) |
-                       (u64) arng->msi64_low;
-               pbm->msi32_len = arng->msi32_len;
-               pbm->msi64_len = arng->msi64_len;
-
-               if (msi_bitmap_alloc(pbm))
-                       goto no_msi;
-
-               if (msi_queue_alloc(pbm)) {
-                       msi_bitmap_free(pbm);
-                       goto no_msi;
-               }
-
-               printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
-                      "devino[0x%x]\n",
-                      pbm->name,
-                      pbm->msiq_first, pbm->msiq_num,
-                      pbm->msiq_ent_count,
-                      pbm->msiq_first_devino);
-               printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
-                      "width[%u]\n",
-                      pbm->name,
-                      pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
-                      pbm->msix_data_width);
-               printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
-                      "addr64[0x%lx:0x%x]\n",
-                      pbm->name,
-                      pbm->msi32_start, pbm->msi32_len,
-                      pbm->msi64_start, pbm->msi64_len);
-               printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
-                      pbm->name,
-                      pbm->msi_queues);
-       }
-
-       return;
-
-no_msi:
-       pbm->msiq_num = 0;
-       printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
-}
 
 static int alloc_msi(struct pci_pbm_info *pbm)
 {
@@ -1245,6 +1025,117 @@ static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
         */
        sun4v_destroy_msi(virt_irq);
 }
+
+static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
+{
+       const u32 *val;
+       int len;
+
+       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+       if (!val || len != 4)
+               goto no_msi;
+       pbm->msiq_num = *val;
+       if (pbm->msiq_num) {
+               const struct msiq_prop {
+                       u32 first_msiq;
+                       u32 num_msiq;
+                       u32 first_devino;
+               } *mqp;
+               const struct msi_range_prop {
+                       u32 first_msi;
+                       u32 num_msi;
+               } *mrng;
+               const struct addr_range_prop {
+                       u32 msi32_high;
+                       u32 msi32_low;
+                       u32 msi32_len;
+                       u32 msi64_high;
+                       u32 msi64_low;
+                       u32 msi64_len;
+               } *arng;
+
+               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+
+               pbm->msiq_ent_count = *val;
+
+               mqp = of_get_property(pbm->prom_node,
+                                     "msi-eq-to-devino", &len);
+               if (!mqp || len != sizeof(struct msiq_prop))
+                       goto no_msi;
+
+               pbm->msiq_first = mqp->first_msiq;
+               pbm->msiq_first_devino = mqp->first_devino;
+
+               val = of_get_property(pbm->prom_node, "#msi", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msi_num = *val;
+
+               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+               if (!mrng || len != sizeof(struct msi_range_prop))
+                       goto no_msi;
+               pbm->msi_first = mrng->first_msi;
+
+               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msi_data_mask = *val;
+
+               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+               if (!val || len != 4)
+                       goto no_msi;
+               pbm->msix_data_width = *val;
+
+               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+                                      &len);
+               if (!arng || len != sizeof(struct addr_range_prop))
+                       goto no_msi;
+               pbm->msi32_start = ((u64)arng->msi32_high << 32) |
+                       (u64) arng->msi32_low;
+               pbm->msi64_start = ((u64)arng->msi64_high << 32) |
+                       (u64) arng->msi64_low;
+               pbm->msi32_len = arng->msi32_len;
+               pbm->msi64_len = arng->msi64_len;
+
+               if (msi_bitmap_alloc(pbm))
+                       goto no_msi;
+
+               if (msi_queue_alloc(pbm)) {
+                       msi_bitmap_free(pbm);
+                       goto no_msi;
+               }
+
+               printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
+                      "devino[0x%x]\n",
+                      pbm->name,
+                      pbm->msiq_first, pbm->msiq_num,
+                      pbm->msiq_ent_count,
+                      pbm->msiq_first_devino);
+               printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
+                      "width[%u]\n",
+                      pbm->name,
+                      pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
+                      pbm->msix_data_width);
+               printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
+                      "addr64[0x%lx:0x%x]\n",
+                      pbm->name,
+                      pbm->msi32_start, pbm->msi32_len,
+                      pbm->msi64_start, pbm->msi64_len);
+               printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
+                      pbm->name,
+                      pbm->msi_queues);
+       }
+       pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
+       pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
+
+       return;
+
+no_msi:
+       pbm->msiq_num = 0;
+       printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+}
 #else /* CONFIG_PCI_MSI */
 static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 {
@@ -1260,6 +1151,15 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
        else
                pbm = &p->pbm_A;
 
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       pbm->scan_bus = pci_sun4v_scan_bus;
+       pbm->pci_ops = &sun4v_pci_ops;
+       pbm->config_space_reg_bits = 12;
+
+       pbm->index = pci_num_pbms++;
+
        pbm->parent = p;
        pbm->prom_node = dp;
 
@@ -1271,7 +1171,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
 
        pci_determine_mem_io_space(pbm);
 
-       pci_sun4v_get_bus_range(pbm);
+       pci_get_pbm_props(pbm);
        pci_sun4v_iommu_init(pbm);
        pci_sun4v_msi_init(pbm);
 }
@@ -1279,6 +1179,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
 void sun4v_pci_init(struct device_node *dp, char *model_name)
 {
        struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
        struct iommu *iommu;
        struct property *prop;
        struct linux_prom64_registers *regs;
@@ -1290,18 +1191,9 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
 
        devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
 
-       for (p = pci_controller_root; p; p = p->next) {
-               struct pci_pbm_info *pbm;
-
-               if (p->pbm_A.prom_node && p->pbm_B.prom_node)
-                       continue;
-
-               pbm = (p->pbm_A.prom_node ?
-                      &p->pbm_A :
-                      &p->pbm_B);
-
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
                if (pbm->devhandle == (devhandle ^ 0x40)) {
-                       pci_sun4v_pbm_init(p, dp, devhandle);
+                       pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
                        return;
                }
        }
@@ -1331,18 +1223,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
 
        p->pbm_B.iommu = iommu;
 
-       p->next = pci_controller_root;
-       pci_controller_root = p;
-
-       p->index = pci_num_controllers++;
-
-       p->scan_bus = pci_sun4v_scan_bus;
-#ifdef CONFIG_PCI_MSI
-       p->setup_msi_irq = pci_sun4v_setup_msi_irq;
-       p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
-#endif
-       p->pci_ops = &pci_sun4v_ops;
-
        /* Like PSYCHO and SCHIZO we have a 2GB aligned area
         * for memory space.
         */
index c54d4d8af0142530d861074fe6afdb8b9081d207..b7976b14d0bac15319520d13316cb4492605eeb7 100644 (file)
@@ -1636,10 +1636,21 @@ static struct device_node * __init create_node(phandle node, struct device_node
 
 static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
 {
+       struct device_node *ret = NULL, *prev_sibling = NULL;
        struct device_node *dp;
 
-       dp = create_node(node, parent);
-       if (dp) {
+       while (1) {
+               dp = create_node(node, parent);
+               if (!dp)
+                       break;
+
+               if (prev_sibling)
+                       prev_sibling->sibling = dp;
+
+               if (!ret)
+                       ret = dp;
+               prev_sibling = dp;
+
                *(*nextp) = dp;
                *nextp = &dp->allnext;
 
@@ -1648,10 +1659,10 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
 
                dp->child = build_tree(dp, prom_getchild(node), nextp);
 
-               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+               node = prom_getsibling(node);
        }
 
-       return dp;
+       return ret;
 }
 
 void __init prom_build_devicetree(void)
index 3b05428cc9091e00dd2d7f588af3b5082b952e17..91f6e2a74ad5fdc263c94fec5dd41dfb06ea254c 100644 (file)
@@ -1002,24 +1002,24 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
        u64 control;
 
        irq = sbus_build_irq(sbus, SYSIO_UE_INO);
-       if (request_irq(irq, sysio_ue_handler,
-                       IRQF_SHARED, "SYSIO UE", sbus) < 0) {
+       if (request_irq(irq, sysio_ue_handler, 0,
+                       "SYSIO_UE", sbus) < 0) {
                prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
                            sbus->portid);
                prom_halt();
        }
 
        irq = sbus_build_irq(sbus, SYSIO_CE_INO);
-       if (request_irq(irq, sysio_ce_handler,
-                       IRQF_SHARED, "SYSIO CE", sbus) < 0) {
+       if (request_irq(irq, sysio_ce_handler, 0,
+                       "SYSIO_CE", sbus) < 0) {
                prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
                            sbus->portid);
                prom_halt();
        }
 
        irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
-       if (request_irq(irq, sysio_sbus_error_handler,
-                       IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) {
+       if (request_irq(irq, sysio_sbus_error_handler, 0,
+                       "SYSIO_SBERR", sbus) < 0) {
                prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
                            sbus->portid);
                prom_halt();
index 692e46a6b8da1dc002dc17a8540b83c3cce962fb..abd83129b2e73480031791032ea6a698eac26af8 100644 (file)
@@ -793,7 +793,7 @@ asmlinkage long sys32_utimes(char __user *filename,
                tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
        }
 
-       return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL);
+       return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
 }
 
 /* These are here just in case some old sparc32 binary calls it. */
index 48c36fe6dc624f91a4e85fdbf6129f2da85e4a92..5fe7f9ad4a92c35a92d75c314636a3fbb968a52d 100644 (file)
@@ -81,6 +81,7 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
+/*310*/        .word compat_sys_utimensat
 
 #endif /* CONFIG_COMPAT */
 
@@ -152,6 +153,7 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/        .word sys_utimensat
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -269,5 +271,6 @@ sunos_sys_table:
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys
+/*310*/        .long sunos_nosys
 
 #endif
index dc652f2102906b54192196ee35f100cbc1f80221..d0fde36395b4a07e9dfa7586b8cc90d8a69bb782 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/kdebug.h>
 
+#include <asm/smp.h>
 #include <asm/delay.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
index c32e309f778832e572a215f6f6adc7aedc6831aa..b582024d21994498b7959270d5c265e7eac65cdf 100644 (file)
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-       return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
-
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
-
-static inline int notify_page_fault(enum die_val val, const char *str,
-                       struct pt_regs *regs, long err, int trap, int sig)
-{
-       struct die_args args = {
-               .regs = regs,
-               .str = str,
-               .err = err,
-               .trapnr = trap,
-               .signr = sig
-       };
-       return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+       int ret = 0;
+
+       /* kprobe_running() needs smp_processor_id() */
+       if (!user_mode(regs)) {
+               preempt_disable();
+               if (kprobe_running() && kprobe_fault_handler(regs, 0))
+                       ret = 1;
+               preempt_enable();
+       }
+       return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, const char *str,
-                       struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
 {
-       return NOTIFY_DONE;
+       return 0;
 }
 #endif
 
@@ -120,9 +107,6 @@ static void __kprobes unhandled_fault(unsigned long address,
        printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
               (tsk->mm ? (unsigned long) tsk->mm->pgd :
                          (unsigned long) tsk->active_mm->pgd));
-       if (notify_die(DIE_GPF, "general protection fault", regs,
-                      0, 0, SIGSEGV) == NOTIFY_STOP)
-               return;
        die_if_kernel("Oops", regs);
 }
 
@@ -299,8 +283,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
 
        fault_code = get_thread_fault_code();
 
-       if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
-                      fault_code, 0, SIGSEGV) == NOTIFY_STOP)
+       if (notify_page_fault(regs))
                return;
 
        si_code = SEGV_MAPERR;
index 354cc6b70530c3873e51698845e4a799d437c826..c504312219b42b8f9797c50fe1569e5f05163a84 100644 (file)
@@ -277,7 +277,8 @@ config HIGHMEM
 
 config KERNEL_STACK_ORDER
        int "Kernel stack size order"
-       default 2
+       default 1 if 64BIT
+       default 0 if !64BIT
        help
        This option determines the size of UML kernel stacks.  They will
        be 1 << order pages.  The default is OK unless you're running Valgrind
@@ -320,21 +321,7 @@ source "crypto/Kconfig"
 
 source "lib/Kconfig"
 
-menu "SCSI support"
-depends on BROKEN
-
-config SCSI
-       tristate "SCSI support"
-
-# This gives us free_dma, which scsi.c wants.
-config GENERIC_ISA_DMA
-       bool
-       depends on SCSI
-       default y
-
-source "arch/um/Kconfig.scsi"
-
-endmenu
+source "drivers/scsi/Kconfig"
 
 source "drivers/md/Kconfig"
 
diff --git a/arch/um/Kconfig.scsi b/arch/um/Kconfig.scsi
deleted file mode 100644 (file)
index c291c94..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-comment "SCSI support type (disk, tape, CD-ROM)"
-       depends on SCSI
-
-config BLK_DEV_SD
-       tristate "SCSI disk support"
-       depends on SCSI
-
-config SD_EXTRA_DEVS
-       int "Maximum number of SCSI disks that can be loaded as modules"
-       depends on BLK_DEV_SD
-       default "40"
-
-config CHR_DEV_ST
-       tristate "SCSI tape support"
-       depends on SCSI
-
-config BLK_DEV_SR
-       tristate "SCSI CD-ROM support"
-       depends on SCSI
-
-config BLK_DEV_SR_VENDOR
-       bool "Enable vendor-specific extensions (for SCSI CDROM)"
-       depends on BLK_DEV_SR
-
-config SR_EXTRA_DEVS
-       int "Maximum number of CDROM devices that can be loaded as modules"
-       depends on BLK_DEV_SR
-       default "2"
-
-config CHR_DEV_SG
-       tristate "SCSI generic support"
-       depends on SCSI
-
-comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
-       depends on SCSI
-
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-config SCSI_DEBUG_QUEUES
-       bool "Enable extra checks in new queueing code"
-       depends on SCSI
-
-#fi
-config SCSI_MULTI_LUN
-       bool "Probe all LUNs on each SCSI device"
-       depends on SCSI
-
-config SCSI_CONSTANTS
-       bool "Verbose SCSI error reporting (kernel size +=12K)"
-       depends on SCSI
-
-config SCSI_LOGGING
-       bool "SCSI logging facility"
-       depends on SCSI
-
-config SCSI_DEBUG
-       tristate "SCSI debugging host simulator (EXPERIMENTAL)"
-       depends on SCSI
-
index f938fa822146bb86e2a5fbada7fcb8548102b91b..a54d0efecae1567074ca28ec77edcb70e8bb88ae 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MCONSOLE=y
 # CONFIG_MAGIC_SYSRQ is not set
 CONFIG_NEST_LEVEL=0
 # CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_KERNEL_STACK_ORDER=0
 CONFIG_UML_REAL_TIME_CLOCK=y
 
 #
index 5593a802708321ac919247574bf16ec48856c246..541f4a8ca512ab3519a19005e490b2a9246d7ae3 100644 (file)
@@ -28,3 +28,5 @@ DEFINE(UM_NR_CPUS, NR_CPUS);
 
 /* For crypto assembler code. */
 DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+
+DEFINE(UM_THREAD_SIZE, THREAD_SIZE);
index 50a49691e0e62fd3666851de8b70c2b521d1074f..8d7f7c1cb9c64e40dd96cd17f8e65fe3b9a323da 100644 (file)
@@ -117,4 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs);
 
 extern void copy_sc(union uml_pt_regs *regs, void *from);
 
+unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+unsigned long from_irq_stack(int nested);
+
 #endif
index 688d181b5f8ae602fb34509cbd876fd343aa273a..4d9fb26387d565290a58ef093d34f3c25d10042b 100644 (file)
@@ -272,7 +272,6 @@ extern void do_longjmp(void *p, int val);
 
 /* util.c */
 extern void stack_protections(unsigned long address);
-extern void task_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
index 11bafab669e942b517e403b13cb966eb2c9242b0..0f312085ce1d26ce7bec6b890d646f4f0194fc14 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/i386/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-i386/archsetjmp.h
  */
 
 #ifndef _KLIBC_ARCHSETJMP_H
index 9a5e1a6ec80042095b5f3562d2c2107e85431508..2af8f12ca16169a8f78f2a1d0b138bd563f98334 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/x86_64/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-x86_64/archsetjmp.h
  */
 
 #ifndef _KLIBC_ARCHSETJMP_H
index e36f92b463ce04dc64ec0f076954e48cf0cb276a..87a4e4427d8db2e3e7a83fd8ee0667d287516029 100644 (file)
@@ -97,6 +97,8 @@ SECTIONS
   .data           : {
     . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data .data.* .gnu.linkonce.d.*)
     SORT(CONSTRUCTORS)
   }
index cda91aa8e703162564c2163064ed7efe567649d1..d4f1d1ab252ba0757e47499db066bdb09cbf62bc 100644 (file)
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com)
  * Licensed under the GPL
  */
 
@@ -33,28 +33,20 @@ EXPORT_SYMBOL(init_task);
 /*
  * Initial thread structure.
  *
- * We need to make sure that this is 16384-byte aligned due to the
+ * We need to make sure that this is 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) };
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
+
+union thread_union cpu0_irqstack
+       __attribute__((__section__(".data.init_irqstack"))) =
+               { INIT_THREAD_INFO(init_task) };
 
 void unprotect_stack(unsigned long stack)
 {
-       os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
-                      1, 1, 0);
+       os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 8f2ed369031507c8aa01992d46dbaea62b3721ca..dba04d88b4320bde93b7ce4bee3f728193fd257f 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
@@ -32,6 +32,7 @@
 #include "sigio.h"
 #include "um_malloc.h"
 #include "misc_constants.h"
+#include "as-layout.h"
 
 /*
  * Generic, controller-independent functions:
@@ -53,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v)
        if (i < NR_IRQS) {
                spin_lock_irqsave(&irq_desc[i].lock, flags);
                action = irq_desc[i].action;
-               if (!action) 
+               if (!action)
                        goto skip;
                seq_printf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -468,3 +469,113 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler)
  out:
        return err;
 }
+
+/*
+ * IRQ stack entry and exit:
+ *
+ * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
+ * and switch over to the IRQ stack after some preparation.  We use
+ * sigaltstack to receive signals on a separate stack from the start.
+ * These two functions make sure the rest of the kernel won't be too
+ * upset by being on a different stack.  The IRQ stack has a
+ * thread_info structure at the bottom so that current et al continue
+ * to work.
+ *
+ * to_irq_stack copies the current task's thread_info to the IRQ stack
+ * thread_info and sets the tasks's stack to point to the IRQ stack.
+ *
+ * from_irq_stack copies the thread_info struct back (flags may have
+ * been modified) and resets the task's stack pointer.
+ *
+ * Tricky bits -
+ *
+ * What happens when two signals race each other?  UML doesn't block
+ * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
+ * could arrive while a previous one is still setting up the
+ * thread_info.
+ *
+ * There are three cases -
+ *     The first interrupt on the stack - sets up the thread_info and
+ * handles the interrupt
+ *     A nested interrupt interrupting the copying of the thread_info -
+ * can't handle the interrupt, as the stack is in an unknown state
+ *     A nested interrupt not interrupting the copying of the
+ * thread_info - doesn't do any setup, just handles the interrupt
+ *
+ * The first job is to figure out whether we interrupted stack setup.
+ * This is done by xchging the signal mask with thread_info->pending.
+ * If the value that comes back is zero, then there is no setup in
+ * progress, and the interrupt can be handled.  If the value is
+ * non-zero, then there is stack setup in progress.  In order to have
+ * the interrupt handled, we leave our signal in the mask, and it will
+ * be handled by the upper handler after it has set up the stack.
+ *
+ * Next is to figure out whether we are the outer handler or a nested
+ * one.  As part of setting up the stack, thread_info->real_thread is
+ * set to non-NULL (and is reset to NULL on exit).  This is the
+ * nesting indicator.  If it is non-NULL, then the stack is already
+ * set up and the handler can run.
+ */
+
+static unsigned long pending_mask;
+
+unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+{
+       struct thread_info *ti;
+       unsigned long mask, old;
+       int nested;
+
+       mask = xchg(&pending_mask, 1 << sig);
+       if(mask != 0){
+               /* If any interrupts come in at this point, we want to
+                * make sure that their bits aren't lost by our
+                * putting our bit in.  So, this loop accumulates bits
+                * until xchg returns the same value that we put in.
+                * When that happens, there were no new interrupts,
+                * and pending_mask contains a bit for each interrupt
+                * that came in.
+                */
+               old = 1 << sig;
+               do {
+                       old |= mask;
+                       mask = xchg(&pending_mask, old);
+               } while(mask != old);
+               return 1;
+       }
+
+       ti = current_thread_info();
+       nested = (ti->real_thread != NULL);
+       if(!nested){
+               struct task_struct *task;
+               struct thread_info *tti;
+
+               task = cpu_tasks[ti->cpu].task;
+               tti = task_thread_info(task);
+               *ti = *tti;
+               ti->real_thread = tti;
+               task->stack = ti;
+       }
+
+       mask = xchg(&pending_mask, 0);
+       *mask_out |= mask | nested;
+       return 0;
+}
+
+unsigned long from_irq_stack(int nested)
+{
+       struct thread_info *ti, *to;
+       unsigned long mask;
+
+       ti = current_thread_info();
+
+       pending_mask = 1;
+
+       to = ti->real_thread;
+       current->stack = to;
+       ti->real_thread = NULL;
+       *to = *ti;
+
+       mask = xchg(&pending_mask, 0);
+       return mask & ~1;
+}
+
index ef36facd8fe9a7ff814c81dd1f3976ba3054e019..2a69a7ce5792eedc43283e7f8adaefb7c7744314 100644 (file)
@@ -163,8 +163,12 @@ static int start_kernel_proc(void *unused)
 
 extern int userspace_pid[];
 
+extern char cpu0_irqstack[];
+
 int start_uml_skas(void)
 {
+       stack_protections((unsigned long) &cpu0_irqstack);
+       set_sigstack(cpu0_irqstack, THREAD_SIZE);
        if(proc_mm)
                userspace_pid[0] = start_userspace(0);
 
@@ -178,20 +182,23 @@ int start_uml_skas(void)
 
 int external_pid_skas(struct task_struct *task)
 {
-#warning Need to look up userspace_pid by cpu
+       /* FIXME: Need to look up userspace_pid by cpu */
        return(userspace_pid[0]);
 }
 
 int thread_pid_skas(struct task_struct *task)
 {
-#warning Need to look up userspace_pid by cpu
+       /* FIXME: Need to look up userspace_pid by cpu */
        return(userspace_pid[0]);
 }
 
 void kill_off_processes_skas(void)
 {
        if(proc_mm)
-#warning need to loop over userspace_pids in kill_off_processes_skas
+               /*
+                * FIXME: need to loop over userspace_pids in
+                * kill_off_processes_skas
+                */
                os_kill_ptraced_process(userspace_pid[0], 1);
        else {
                struct task_struct *p;
index 98e21743e604046da3e324e43215dd5b38129f62..40126cb5180103c194590b6e35d4ff9ae413317e 100644 (file)
@@ -57,7 +57,7 @@ void flush_thread_tt(void)
        enable_timer();
        free_page(stack);
        protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
-       task_protections((unsigned long) current_thread);
+       stack_protections((unsigned long) current_thread);
        force_flush_all();
        unblock_signals();
 }
index c631303cb800cf80a8593a22836b1ee47cf7f7f6..74347adf81bfbcf745f62587d21a0bdaeffb7064 100644 (file)
@@ -209,7 +209,7 @@ void finish_fork_handler(int sig)
        if(current->mm != current->parent->mm)
                protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
                               1, 0, 1);
-       task_protections((unsigned long) current_thread);
+       stack_protections((unsigned long) current_thread);
 
        free_page(current->thread.temp_stack);
        local_irq_disable();
index 1cf954a47fd7719c83e818e53428f9de027ed99a..ecc458fe51b910d91374664660db4446723fd46d 100644 (file)
@@ -459,7 +459,7 @@ int __init linux_main(int argc, char **argv)
 
        uml_postsetup();
 
-       task_protections((unsigned long) &init_thread_info);
+       stack_protections((unsigned long) &init_thread_info);
        os_flush_stdout();
 
        return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
index f6301274cf3cfea9fdb0eb3680cbe349da63fd57..bc59f97e34d00ab2886b75af77376e52d6edb432 100644 (file)
@@ -59,6 +59,8 @@ SECTIONS
   {
     . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data)
     *(.gnu.linkonce.d*)
     CONSTRUCTORS
index 92a7b59120d616692021376bea33ff5226053b04..2d9d2ca39299f2e74ee2be3a47daf0d877d213e8 100644 (file)
@@ -239,6 +239,7 @@ out:
        return ok;
 }
 
+#ifdef UML_CONFIG_MODE_TT
 void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
 {
        int flags = 0, pages;
@@ -260,6 +261,7 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
                              "errno = %d\n", errno);
        }
 }
+#endif
 
 void init_new_thread_signals(void)
 {
index 48d49341530121e004a9efadf4a0637504e3d5ba..18e5c8b67eb8cebbe84db25bed7e64e623522dc9 100644 (file)
@@ -61,15 +61,19 @@ void sig_handler(int sig, struct sigcontext *sc)
 
 static void real_alarm_handler(int sig, struct sigcontext *sc)
 {
+       union uml_pt_regs regs;
+
        if(sig == SIGALRM)
                switch_timers(0);
 
-       CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
-                        sig, sc);
+       if(sc != NULL)
+               copy_sc(&regs, sc);
+       regs.skas.is_user = 0;
+       unblock_signals();
+       timer_handler(sig, &regs);
 
        if(sig == SIGALRM)
                switch_timers(1);
-
 }
 
 void alarm_handler(int sig, struct sigcontext *sc)
@@ -113,6 +117,46 @@ void remove_sigstack(void)
 
 void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
 
+void handle_signal(int sig, struct sigcontext *sc)
+{
+       unsigned long pending = 0;
+
+       do {
+               int nested, bail;
+
+               /*
+                * pending comes back with one bit set for each
+                * interrupt that arrived while setting up the stack,
+                * plus a bit for this interrupt, plus the zero bit is
+                * set if this is a nested interrupt.
+                * If bail is true, then we interrupted another
+                * handler setting up the stack.  In this case, we
+                * have to return, and the upper handler will deal
+                * with this interrupt.
+                */
+               bail = to_irq_stack(sig, &pending);
+               if(bail)
+                       return;
+
+               nested = pending & 1;
+               pending &= ~1;
+
+               while((sig = ffs(pending)) != 0){
+                       sig--;
+                       pending &= ~(1 << sig);
+                       (*handlers[sig])(sig, sc);
+               }
+
+               /* Again, pending comes back with a mask of signals
+                * that arrived while tearing down the stack.  If this
+                * is non-zero, we just go back, set up the stack
+                * again, and handle the new interrupts.
+                */
+               if(!nested)
+                       pending = from_irq_stack(nested);
+       } while(pending);
+}
+
 extern void hard_handler(int sig);
 
 void set_handler(int sig, void (*handler)(int), int flags, ...)
index 8e490fff3d476a5c54fc49adc17e94b327d6f53e..5c89463207996a60e942366f561a7fb2f2273f82 100644 (file)
@@ -68,7 +68,7 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
        int err, pid = mm_idp->u.pid;
 
        if(proc_mm)
-#warning Need to look up userspace_pid by cpu
+               /* FIXME: Need to look up userspace_pid by cpu */
                pid = userspace_pid[0];
 
        multi_count++;
index 5c088a55396ce3a0b5fbe97f40499cdd9362c7d6..f9d2f8545afedd12f06a2e3a216eea2757759999 100644 (file)
@@ -288,7 +288,8 @@ int start_userspace(unsigned long stub_stack)
 void userspace(union uml_pt_regs *regs)
 {
        int err, status, op, pid = userspace_pid[0];
-       int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+       /* To prevent races if using_sysemu changes under us.*/
+       int local_using_sysemu;
 
        while(1){
                restore_registers(pid, regs);
@@ -296,7 +297,8 @@ void userspace(union uml_pt_regs *regs)
                /* Now we set local_using_sysemu to be used for one loop */
                local_using_sysemu = get_using_sysemu();
 
-               op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+               op = SELECT_PTRACE_OPERATION(local_using_sysemu,
+                                            singlestepping(NULL));
 
                err = ptrace(op, pid, 0, 0);
                if(err)
@@ -490,8 +492,8 @@ void map_stub_pages(int fd, unsigned long code,
 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
 {
        (*buf)[0].JB_IP = (unsigned long) handler;
-       (*buf)[0].JB_SP = (unsigned long) stack +
-               (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
+       (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
+               sizeof(void *);
 }
 
 #define INIT_JMP_NEW_THREAD 0
@@ -533,8 +535,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
        case INIT_JMP_NEW_THREAD:
                (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
                (*switch_buf)[0].JB_SP = (unsigned long) stack +
-                       (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
-                       sizeof(void *);
+                       UM_THREAD_SIZE - sizeof(void *);
                break;
        case INIT_JMP_CALLBACK:
                (*cb_proc)(cb_arg);
@@ -586,7 +587,7 @@ void switch_mm_skas(struct mm_id *mm_idp)
 {
        int err;
 
-#warning need cpu pid in switch_mm_skas
+       /* FIXME: need cpu pid in switch_mm_skas */
        if(proc_mm){
                err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
                             mm_idp->u.mm_fd);
index 0d3eae5183526cc53aded9ce2e6ca66b6dc9574f..f311609f93daaf7079476a067e2e2ab24bc8a202 100644 (file)
@@ -1,15 +1,13 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
-       struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
-
-       (*handlers[sig])(sig, sc);
+       handle_signal(sig, (struct sigcontext *) (&sig + 1));
 }
index 3f369e5f976b724232e4cf4a4f9fe1e90782dbe0..82a388822cd35c55b006f9dbe0d3f1230b83b620 100644 (file)
@@ -1,16 +1,16 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
        struct ucontext *uc;
        asm("movq %%rdx, %0" : "=r" (uc));
 
-       (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
+       handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext);
 }
index c307a89ed2598cef9a0c619cc8576e353115aa54..7cbcf484e13d3337d8bbaaa06d3fed165a02f377 100644 (file)
 
 void stack_protections(unsigned long address)
 {
-       int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
-       if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
-               panic("protecting stack failed, errno = %d", errno);
-}
-
-void task_protections(unsigned long address)
-{
-       unsigned long guard = address + UM_KERN_PAGE_SIZE;
-       unsigned long stack = guard + UM_KERN_PAGE_SIZE;
-       int prot = 0, pages;
-
-#ifdef notdef
-       if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
-               panic("protecting guard page failed, errno = %d", errno);
-#endif
-       pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
-       prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-       if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
+       if(mprotect((void *) address, UM_THREAD_SIZE,
+                   PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
                panic("protecting stack failed, errno = %d", errno);
 }
 
@@ -72,7 +55,7 @@ int raw(int fd)
 
        /* XXX tcsetattr could have applied only some changes
         * (and cfmakeraw() is a set of changes) */
-       return(0);
+       return 0;
 }
 
 void setup_machinename(char *machine_out)
index 24f291369070dc7511f011b10c813f337b8b7b7b..cee5c3142d41c41644341e62a5acb86f6247aa9b 100644 (file)
@@ -29,7 +29,7 @@ int main (void)
        DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace));
        DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked));
        DEFINE (TASK_THREAD, offsetof (struct task_struct, thread));
-       DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+       DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, stack));
        DEFINE (TASK_MM, offsetof (struct task_struct, mm));
        DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
        DEFINE (TASK_PID, offsetof (struct task_struct, pid));
index 8bc521ca081f9a32fec0d51d12e8ef4f1044f8c3..e4327a8d6bcd0eb28244097c24f14a98638239d5 100644 (file)
@@ -523,7 +523,7 @@ END(ret_from_trap)
 
 
 /* This the initial entry point for a new child thread, with an appropriate
-   stack in place that makes it look the the child is in the middle of an
+   stack in place that makes it look that the child is in the middle of an
    syscall.  This function is actually `returned to' from switch_thread
    (copy_thread makes ret_from_fork the return address in each new thread's
    saved context).  */
index f21068378272f0b8dbce0ce1d7f8b29ccfa0b286..52be79beb30624c9a71f49eb8ce10f6f0dd8311b 100644 (file)
@@ -716,4 +716,7 @@ ia32_sys_call_table:
        .quad sys_getcpu
        .quad sys_epoll_pwait
        .quad compat_sys_utimensat      /* 320 */
+       .quad sys_signalfd
+       .quad sys_timerfd
+       .quad sys_eventfd
 ia32_syscall_end:              
index 213d90e047550e9d2d348aa28e855d94730781ca..6c34bdd22e2634df6bdb41cc1db8aba482ddf33f 100644 (file)
@@ -62,13 +62,6 @@ void __init x86_64_start_kernel(char * real_mode_data)
 {
        int i;
 
-       /*
-        * Make sure kernel is aligned to 2MB address. Catching it at compile
-        * time is better. Change your config file and compile the kernel
-        * for a 2MB aligned address (CONFIG_PHYSICAL_START)
-        */
-       BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
-
        /* clear bss before set_intr_gate with early_idt_handler */
        clear_bss();
 
index 4d582589fa89cd1dc6ede837ec5d4350293d61cd..d8bfe315471cfdf6d3a078fd4a72bd014f03acca 100644 (file)
@@ -1413,7 +1413,7 @@ static void ack_apic_level(unsigned int irq)
 
        /*
         * We must acknowledge the irq before we move it or the acknowledge will
-        * not propogate properly.
+        * not propagate properly.
         */
        ack_APIC_irq();
 
index 3bc30d2c13d3289809cd538f07cef4fc8033c0dc..3eaceac3248140ae85d6643dae9f61cb3a01a8a0 100644 (file)
@@ -32,7 +32,7 @@ atomic_t irq_err_count;
  */
 static inline void stack_overflow_check(struct pt_regs *regs)
 {
-       u64 curbase = (u64) current->thread_info;
+       u64 curbase = (u64)task_stack_page(current);
        static unsigned long warned = -60*HZ;
 
        if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
index 442169640e452ccd4e54240c7ed9684a6d4f5ba8..a14375dd54252d1ca6405e1f28a4e7246ae3cbbe 100644 (file)
@@ -720,9 +720,11 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                mce_create_device(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                mce_remove_device(cpu);
                break;
        }
index d0bd5d66e103d8d491dc728cb06a82dec86425ba..03356e64f9c8cde580f27075e00451440d2751e3 100644 (file)
@@ -654,9 +654,11 @@ static int threshold_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                threshold_create_device(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                threshold_remove_device(cpu);
                break;
        default:
index 8c2ac41187c126aeef9bc0535b3f58d5c3332b3b..d28f01379b9b5f31aff3c17bad2964c7bfa2ff5d 100644 (file)
@@ -778,6 +778,7 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
                        return;
                if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
                                                                == NOTIFY_STOP)
+                       return;
                if (!do_nmi_callback(regs,cpu))
                        unknown_nmi_error(reason, regs);
 
index dc32cef961950915fbaa185e36ab802d5f7cea3b..51d4c6fa88c8785776354ae0ca115fc46176b7b4 100644 (file)
@@ -327,7 +327,7 @@ static int __cpuinit
 cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
 {
        long cpu = (long)arg;
-       if (action == CPU_ONLINE)
+       if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
                smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1);
        return NOTIFY_DONE;
 }
index b256cfbef3447bfcc647904e7ccc1c6cdd123f21..698079b3a3368f86735a584daa26384456d11dc1 100644 (file)
@@ -70,7 +70,7 @@ int main(void)
        DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
        DEFINE(TASK_PID, offsetof (struct task_struct, pid));
        DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
-       DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+       DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
        DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
        BLANK();
 
index ca76f071666e895aea125f3927d07bcb385fdcd7..f5319d78c876135326374c530f7f85f13f961d72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/xtensa/pci-dma.c
+ * arch/xtensa/kernel/pci-dma.c
  *
  * DMA coherent memory allocation.
  *
index 640aa839d63fe45ff7bcd6ca04f81b47bbdad409..109e91b91ffaa403dcb56e828798d923ebec0a50 100644 (file)
@@ -1306,7 +1306,7 @@ static void as_exit_queue(elevator_t *e)
        struct as_data *ad = e->elevator_data;
 
        del_timer_sync(&ad->antic_timer);
-       kblockd_flush();
+       kblockd_flush_work(&ad->antic_work);
 
        BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
        BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
index b5664440896c654f848c524409f5ba8a4255cae7..93a2cf654597c25502da7fb128745c11c01581c9 100644 (file)
@@ -213,6 +213,59 @@ struct gendisk *get_gendisk(dev_t dev, int *part)
        return  kobj ? to_disk(kobj) : NULL;
 }
 
+/*
+ * print a full list of all partitions - intended for places where the root
+ * filesystem can't be mounted and thus to give the victim some idea of what
+ * went wrong
+ */
+void __init printk_all_partitions(void)
+{
+       int n;
+       struct gendisk *sgp;
+
+       mutex_lock(&block_subsys_lock);
+       /* For each block device... */
+       list_for_each_entry(sgp, &block_subsys.list, kobj.entry) {
+               char buf[BDEVNAME_SIZE];
+               /*
+                * Don't show empty devices or things that have been surpressed
+                */
+               if (get_capacity(sgp) == 0 ||
+                   (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
+                       continue;
+
+               /*
+                * Note, unlike /proc/partitions, I am showing the numbers in
+                * hex - the same format as the root= option takes.
+                */
+               printk("%02x%02x %10llu %s",
+                       sgp->major, sgp->first_minor,
+                       (unsigned long long)get_capacity(sgp) >> 1,
+                       disk_name(sgp, 0, buf));
+               if (sgp->driverfs_dev != NULL &&
+                   sgp->driverfs_dev->driver != NULL)
+                       printk(" driver: %s\n",
+                               sgp->driverfs_dev->driver->name);
+               else
+                       printk(" (driver?)\n");
+
+               /* now show the partitions */
+               for (n = 0; n < sgp->minors - 1; ++n) {
+                       if (sgp->part[n] == NULL)
+                               continue;
+                       if (sgp->part[n]->nr_sects == 0)
+                               continue;
+                       printk("  %02x%02x %10llu %s\n",
+                               sgp->major, n + 1 + sgp->first_minor,
+                               (unsigned long long)sgp->part[n]->nr_sects >> 1,
+                               disk_name(sgp, n + 1, buf));
+               } /* partition subloop */
+       } /* Block device loop */
+
+       mutex_unlock(&block_subsys_lock);
+       return;
+}
+
 #ifdef CONFIG_PROC_FS
 /* iterator */
 static void *part_start(struct seq_file *part, loff_t *pos)
index d99d402953a3c118fa0275e89eb4a417a2d1de33..17e18897342841887ec25b45585cfe49478bf77a 100644 (file)
@@ -1704,7 +1704,7 @@ EXPORT_SYMBOL(blk_stop_queue);
  *     on a queue, such as calling the unplug function after a timeout.
  *     A block device may call blk_sync_queue to ensure that any
  *     such activity is cancelled, thus allowing it to release resources
- *     the the callbacks might use. The caller must already have made sure
+ *     that the callbacks might use. The caller must already have made sure
  *     that its ->make_request_fn will not re-add plugging prior to calling
  *     this function.
  *
@@ -1712,7 +1712,6 @@ EXPORT_SYMBOL(blk_stop_queue);
 void blk_sync_queue(struct request_queue *q)
 {
        del_timer_sync(&q->unplug_timer);
-       kblockd_flush();
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -3508,7 +3507,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
         * If a CPU goes away, splice its entries to the current CPU
         * and trigger a run of the softirq
         */
-       if (action == CPU_DEAD) {
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
                int cpu = (unsigned long) hcpu;
 
                local_irq_disable();
@@ -3632,11 +3631,11 @@ int kblockd_schedule_work(struct work_struct *work)
 
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-void kblockd_flush(void)
+void kblockd_flush_work(struct work_struct *work)
 {
-       flush_workqueue(kblockd_workqueue);
+       cancel_work_sync(work);
 }
-EXPORT_SYMBOL(kblockd_flush);
+EXPORT_SYMBOL(kblockd_flush_work);
 
 int __init blk_dev_init(void)
 {
index 620e14cabdc605ab0bfb9167758dbd2ca1b09ce6..4ca0ab3448d9f3887cd3c64594f0006c71194dfd 100644 (file)
@@ -271,7 +271,7 @@ config CRYPTO_SERPENT
 
          Keys are allowed to be from 0 to 256 bits in length, in steps
          of 8 bits.  Also includes the 'Tnepres' algorithm, a reversed
-         variant of Serpent for compatibility with old kerneli code.
+         variant of Serpent for compatibility with old kerneli.org code.
 
          See also:
          <http://www.cl.cam.ac.uk/~rja14/serpent.html>
index 6958ea83ee440e9f3425fd2aa0ff301f24ff1866..e5fb7cca5107d742ccd999bc87eaaf024a204f07 100644 (file)
@@ -24,8 +24,6 @@
 #include "internal.h"
 
 struct cryptomgr_param {
-       struct task_struct *thread;
-
        struct rtattr *tb[CRYPTOA_MAX];
 
        struct {
@@ -81,6 +79,7 @@ err:
 
 static int cryptomgr_schedule_probe(struct crypto_larval *larval)
 {
+       struct task_struct *thread;
        struct cryptomgr_param *param;
        const char *name = larval->alg.cra_name;
        const char *p;
@@ -130,8 +129,8 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
 
        memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
 
-       param->thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
-       if (IS_ERR(param->thread))
+       thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
+       if (IS_ERR(thread))
                goto err_free_param;
 
        return NOTIFY_STOP;
index 26ca9031ea496320106d62772dba56e178eae7c7..adad2f3d438a07929ca9842ac96fb8b3d4dac329 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_FC4)             += fc4/
 obj-$(CONFIG_SCSI)             += scsi/
 obj-$(CONFIG_ATA)              += ata/
 obj-$(CONFIG_FUSION)           += message/
+obj-$(CONFIG_FIREWIRE)         += firewire/
 obj-$(CONFIG_IEEE1394)         += ieee1394/
 obj-y                          += cdrom/
 obj-y                          += auxdisplay/
index 1683e5c5b94c5febc942d191489f0f30634cbe04..1cbe6190582494ed9f3557c58a17b659644f4979 100644 (file)
@@ -231,8 +231,10 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
                 * Obtain the method mutex if necessary. Do not acquire mutex for a
                 * recursive call.
                 */
-               if (acpi_os_get_thread_id() !=
-                   obj_desc->method.mutex->mutex.owner_thread_id) {
+               if (!walk_state ||
+                   !obj_desc->method.mutex->mutex.owner_thread ||
+                   (walk_state->thread !=
+                    obj_desc->method.mutex->mutex.owner_thread)) {
                        /*
                         * Acquire the method mutex. This releases the interpreter if we
                         * block (and reacquires it before it returns)
@@ -246,14 +248,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
                        }
 
                        /* Update the mutex and walk info and save the original sync_level */
-                       obj_desc->method.mutex->mutex.owner_thread_id =
-                               acpi_os_get_thread_id();
 
                        if (walk_state) {
                                obj_desc->method.mutex->mutex.
                                    original_sync_level =
                                    walk_state->thread->current_sync_level;
 
+                               obj_desc->method.mutex->mutex.owner_thread =
+                                   walk_state->thread;
                                walk_state->thread->current_sync_level =
                                    obj_desc->method.sync_level;
                        } else {
@@ -567,7 +569,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
 
                        acpi_os_release_mutex(method_desc->method.mutex->mutex.
                                              os_mutex);
-                       method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+                       method_desc->method.mutex->mutex.owner_thread = NULL;
                }
        }
 
index 6c6104a7a247ef6413ed817ea34c24edfaf96dda..fc9da4879cbfb932e3b2e8ea683b12835d2391ad 100644 (file)
@@ -866,8 +866,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
                    ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) &&
                     (op->common.parent->common.aml_opcode !=
                      AML_VAR_PACKAGE_OP)
-                    && (op->common.parent->common.aml_opcode !=
-                        AML_NAME_OP))) {
+                    && (op->common.parent->common.aml_opcode != AML_NAME_OP))) {
                        walk_state->result_obj = obj_desc;
                }
        }
index e4073e05a75ca1475bc39c03c3306028a8728622..71503c036f7c1496c2cd873a55a5e4bba676d6f2 100644 (file)
@@ -556,10 +556,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
                                         * indicate this to the interpreter, set the
                                         * object to the root
                                         */
-                                       obj_desc =
-                                           ACPI_CAST_PTR(union
-                                                         acpi_operand_object,
-                                                         acpi_gbl_root_node);
+                                       obj_desc = ACPI_CAST_PTR(union
+                                                                acpi_operand_object,
+                                                                acpi_gbl_root_node);
                                        status = AE_OK;
                                } else {
                                        /*
index 16c8e38b51ef944de7a1c90c6ae96cf30d61cfee..5afcdd9c74492aedd4eda84deeb3a9f3882e36c7 100644 (file)
@@ -630,12 +630,9 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
  *
  ******************************************************************************/
 
-struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
-                                                 union acpi_parse_object
-                                                 *origin,
-                                                 union acpi_operand_object
-                                                 *method_desc,
-                                                 struct acpi_thread_state
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+                                                 *origin, union acpi_operand_object
+                                                 *method_desc, struct acpi_thread_state
                                                  *thread)
 {
        struct acpi_walk_state *walk_state;
index e08cf98f504f12583174d23468a60bf4f9a28c14..82f496c07675c66e3cf76020cfbf81fc3dc4139f 100644 (file)
@@ -147,9 +147,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
        return 0;
 }
 
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event,
+                        unsigned count, int force_poll)
 {
-       if (acpi_ec_mode == EC_POLL) {
+       if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) {
                unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
                while (time_before(jiffies, delay)) {
                        if (acpi_ec_check_status(ec, event, 0))
@@ -173,14 +174,15 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
 
 static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
                                        const u8 * wdata, unsigned wdata_len,
-                                       u8 * rdata, unsigned rdata_len)
+                                       u8 * rdata, unsigned rdata_len,
+                                       int force_poll)
 {
        int result = 0;
        unsigned count = atomic_read(&ec->event_count);
        acpi_ec_write_cmd(ec, command);
 
        for (; wdata_len > 0; --wdata_len) {
-               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
                if (result) {
                        printk(KERN_ERR PREFIX
                               "write_cmd timeout, command = %d\n", command);
@@ -191,7 +193,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
        }
 
        if (!rdata_len) {
-               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
                if (result) {
                        printk(KERN_ERR PREFIX
                               "finish-write timeout, command = %d\n", command);
@@ -202,7 +204,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
        }
 
        for (; rdata_len > 0; --rdata_len) {
-               result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count);
+               result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll);
                if (result) {
                        printk(KERN_ERR PREFIX "read timeout, command = %d\n",
                               command);
@@ -217,7 +219,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
 
 static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
                               const u8 * wdata, unsigned wdata_len,
-                              u8 * rdata, unsigned rdata_len)
+                              u8 * rdata, unsigned rdata_len,
+                              int force_poll)
 {
        int status;
        u32 glk;
@@ -240,7 +243,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
        /* Make sure GPE is enabled before doing transaction */
        acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
 
-       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
+       status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
        if (status) {
                printk(KERN_DEBUG PREFIX
                       "input buffer is not empty, aborting transaction\n");
@@ -249,7 +252,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
 
        status = acpi_ec_transaction_unlocked(ec, command,
                                              wdata, wdata_len,
-                                             rdata, rdata_len);
+                                             rdata, rdata_len,
+                                             force_poll);
 
       end:
 
@@ -267,12 +271,12 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
 int acpi_ec_burst_enable(struct acpi_ec *ec)
 {
        u8 d;
-       return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+       return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
 }
 
 int acpi_ec_burst_disable(struct acpi_ec *ec)
 {
-       return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+       return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
 }
 
 static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
@@ -281,7 +285,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
        u8 d;
 
        result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
-                                    &address, 1, &d, 1);
+                                    &address, 1, &d, 1, 0);
        *data = d;
        return result;
 }
@@ -290,7 +294,7 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
 {
        u8 wdata[2] = { address, data };
        return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
-                                  wdata, 2, NULL, 0);
+                                  wdata, 2, NULL, 0, 0);
 }
 
 /*
@@ -349,13 +353,15 @@ EXPORT_SYMBOL(ec_write);
 
 int ec_transaction(u8 command,
                   const u8 * wdata, unsigned wdata_len,
-                  u8 * rdata, unsigned rdata_len)
+                  u8 * rdata, unsigned rdata_len,
+                  int force_poll)
 {
        if (!first_ec)
                return -ENODEV;
 
        return acpi_ec_transaction(first_ec, command, wdata,
-                                  wdata_len, rdata, rdata_len);
+                                  wdata_len, rdata, rdata_len,
+                                  force_poll);
 }
 
 EXPORT_SYMBOL(ec_transaction);
@@ -374,7 +380,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
         * bit to be cleared (and thus clearing the interrupt source).
         */
 
-       result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+       result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
        if (result)
                return result;
 
@@ -410,6 +416,7 @@ static u32 acpi_ec_gpe_handler(void *data)
        acpi_status status = AE_OK;
        u8 value;
        struct acpi_ec *ec = data;
+
        atomic_inc(&ec->event_count);
 
        if (acpi_ec_mode == EC_INTR) {
index 635ba449ebc2c97e98c2bc615f44e87bcaaf3092..e22f4a973c0fdc4d4cf5670e8ace14d83e75abe1 100644 (file)
@@ -341,9 +341,8 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
 
        /* A Non-NULL gpe_device means this is a GPE Block Device */
 
-       obj_desc =
-           acpi_ns_get_attached_object((struct acpi_namespace_node *)
-                                       gpe_device);
+       obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)
+                                              gpe_device);
        if (!obj_desc || !obj_desc->device.gpe_block) {
                return (NULL);
        }
index ad5bc76edf4660a43aa7ea624d9ef92905f020b9..902c287b3a4fd0295f2a9f38418a1ba1228904ab 100644 (file)
@@ -1033,8 +1033,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
 
                        if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
                             ACPI_GPE_DISPATCH_METHOD)
-                           && (gpe_event_info->
-                               flags & ACPI_GPE_TYPE_RUNTIME)) {
+                           && (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) {
                                gpe_enabled_count++;
                        }
 
index cae786ca8600edf12d26042b02c66a236a5a52ff..21cb749d0c75567534ebee05c78551bb289f1972 100644 (file)
@@ -196,15 +196,12 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
                notify_info->notify.value = (u16) notify_value;
                notify_info->notify.handler_obj = handler_obj;
 
-               acpi_ex_exit_interpreter();
-
-               acpi_ev_notify_dispatch(notify_info);
-
-               status = acpi_ex_enter_interpreter();
+               status =
+                   acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
+                                   notify_info);
                if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
+                       acpi_ut_delete_generic_state(notify_info);
                }
-
        }
 
        if (!handler_obj) {
@@ -323,8 +320,9 @@ static u32 acpi_ev_global_lock_handler(void *context)
                acpi_gbl_global_lock_acquired = TRUE;
                /* Send a unit to the semaphore */
 
-               if (ACPI_FAILURE(acpi_os_signal_semaphore(
-                       acpi_gbl_global_lock_semaphore, 1))) {
+               if (ACPI_FAILURE
+                   (acpi_os_signal_semaphore
+                    (acpi_gbl_global_lock_semaphore, 1))) {
                        ACPI_ERROR((AE_INFO,
                                    "Could not signal Global Lock semaphore"));
                }
@@ -450,7 +448,9 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
        }
 
        if (ACPI_FAILURE(status)) {
-               status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+               status =
+                   acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
+                                             timeout);
        }
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
index 96b0e84317482ed67d8ecdd493d678986cf1d6c9..e99f0c435a4724006c9d204c69349733b91d763f 100644 (file)
@@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 bit_width, acpi_integer * value)
 {
        acpi_status status;
-       acpi_status status2;
        acpi_adr_space_handler handler;
        acpi_adr_space_setup region_setup;
        union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * setup will potentially execute control methods
                 * (e.g., _REG method for this region)
                 */
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
                                      handler_desc->address_space.context,
@@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
                /* Re-enter the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
 
                /* Check for failure of the Region Setup */
 
@@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * exit the interpreter because the handler *might* block -- we don't
                 * know what it will do, so we can't hold the lock on the intepreter.
                 */
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
        }
 
        /* Call the handler */
@@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * We just returned from a non-default handler, we must re-enter the
                 * interpreter
                 */
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
index a4fa7e6822a30a7b40e3ff00abff1654af650174..400d90fca966ca9c08aa2c68233d56f47790bc00 100644 (file)
@@ -228,7 +228,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
 
                                /* Install a handler for this PCI root bridge */
 
-                               status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+                               status =
+                                   acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
                                if (ACPI_FAILURE(status)) {
                                        if (status == AE_SAME_HANDLER) {
                                                /*
index a3379bafa676dc7da65fd71aeed1db5091ad7de7..6d866a01f5f439e06f79624de1bd268267b93f2a 100644 (file)
@@ -91,7 +91,6 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
 
 ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
 #endif                         /*  ACPI_FUTURE_USAGE  */
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_fixed_event_handler
@@ -768,11 +767,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
                return (AE_BAD_PARAMETER);
        }
 
-       status = acpi_ex_enter_interpreter();
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
+       /* Must lock interpreter to prevent race conditions */
 
+       acpi_ex_enter_interpreter();
        status = acpi_ev_acquire_global_lock(timeout);
        acpi_ex_exit_interpreter();
 
index 17065e98807c1921d1fcee9aa51d5423fd84ffd3..9cbd3414a574ebf4cad5c94f54a7f95883363189 100644 (file)
@@ -472,7 +472,6 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-
 #ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
@@ -568,7 +567,6 @@ acpi_get_gpe_status(acpi_handle gpe_device,
 
 ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
 #endif                         /*  ACPI_FUTURE_USAGE  */
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_install_gpe_block
index d470e8b1f4ea6052a60643d45c800ce04aa2c7f6..79f2c0d42c06a59ff5a56b8c4062371aeb18362b 100644 (file)
@@ -512,9 +512,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
                 * Create a new string object and string buffer
                 * (-1 because of extra separator included in string_length from above)
                 */
-               return_desc =
-                   acpi_ut_create_string_object((acpi_size)
-                                                (string_length - 1));
+               return_desc = acpi_ut_create_string_object((acpi_size)
+                                                          (string_length - 1));
                if (!return_desc) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
index ae97812681a3ee7fa9ce448aadc0baaea51f7b39..6e9a23e47fef38e5c39497daa0c46a713d3ee726 100644 (file)
@@ -50,7 +50,6 @@
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("excreate")
-
 #ifndef ACPI_NO_METHOD_EXECUTION
 /*******************************************************************************
  *
@@ -583,10 +582,7 @@ acpi_ex_create_method(u8 * aml_start,
         * Get the sync_level. If method is serialized, a mutex will be
         * created for this method when it is parsed.
         */
-       if (acpi_gbl_all_methods_serialized) {
-               obj_desc->method.sync_level = 0;
-               obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
-       } else if (method_flags & AML_METHOD_SERIALIZED) {
+       if (method_flags & AML_METHOD_SERIALIZED) {
                /*
                 * ACPI 1.0: sync_level = 0
                 * ACPI 2.0: sync_level = sync_level in method declaration
index 1a73c14df2c5aa7d7f7cdd1c195bb1e202747139..51c9c29987c3d102a857ecf8d30f937771b27da4 100644 (file)
@@ -134,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = {
 static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
-       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
        {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
         "Acquire Depth"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
@@ -451,9 +451,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
 
        ACPI_FUNCTION_NAME(ex_dump_operand)
 
-           if (!
-               ((ACPI_LV_EXEC & acpi_dbg_level)
-                && (_COMPONENT & acpi_dbg_layer))) {
+           if (!((ACPI_LV_EXEC & acpi_dbg_level)
+                 && (_COMPONENT & acpi_dbg_layer))) {
                return;
        }
 
@@ -844,9 +843,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
        ACPI_FUNCTION_ENTRY();
 
        if (!flags) {
-               if (!
-                   ((ACPI_LV_OBJECTS & acpi_dbg_level)
-                    && (_COMPONENT & acpi_dbg_layer))) {
+               if (!((ACPI_LV_OBJECTS & acpi_dbg_level)
+                     && (_COMPONENT & acpi_dbg_layer))) {
                        return;
                }
        }
@@ -1011,9 +1009,8 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags)
        }
 
        if (!flags) {
-               if (!
-                   ((ACPI_LV_OBJECTS & acpi_dbg_level)
-                    && (_COMPONENT & acpi_dbg_layer))) {
+               if (!((ACPI_LV_OBJECTS & acpi_dbg_level)
+                     && (_COMPONENT & acpi_dbg_layer))) {
                        return_VOID;
                }
        }
index 4eb883bda6ae7f23800decda4a549042c64c8a94..6748e3ef09972472d9aeeaeaa1abf639773a77a8 100644 (file)
@@ -66,9 +66,10 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
  *
  ******************************************************************************/
 
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
-                         struct acpi_thread_state *thread)
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
 {
+       struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
+
        if (!thread) {
                return;
        }
@@ -173,13 +174,16 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
 
        /* Support for multiple acquires by the owning thread */
 
-       if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) {
-               /*
-                * The mutex is already owned by this thread, just increment the
-                * acquisition depth
-                */
-               obj_desc->mutex.acquisition_depth++;
-               return_ACPI_STATUS(AE_OK);
+       if (obj_desc->mutex.owner_thread) {
+               if (obj_desc->mutex.owner_thread->thread_id ==
+                   walk_state->thread->thread_id) {
+                       /*
+                        * The mutex is already owned by this thread, just increment the
+                        * acquisition depth
+                        */
+                       obj_desc->mutex.acquisition_depth++;
+                       return_ACPI_STATUS(AE_OK);
+               }
        }
 
        /* Acquire the mutex, wait if necessary. Special case for Global Lock */
@@ -202,7 +206,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
 
        /* Have the mutex: update mutex and walk info and save the sync_level */
 
-       obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id();
+       obj_desc->mutex.owner_thread = walk_state->thread;
        obj_desc->mutex.acquisition_depth = 1;
        obj_desc->mutex.original_sync_level =
            walk_state->thread->current_sync_level;
@@ -242,7 +246,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 
        /* The mutex must have been previously acquired in order to release it */
 
-       if (!obj_desc->mutex.owner_thread_id) {
+       if (!obj_desc->mutex.owner_thread) {
                ACPI_ERROR((AE_INFO,
                            "Cannot release Mutex [%4.4s], not acquired",
                            acpi_ut_get_node_name(obj_desc->mutex.node)));
@@ -262,14 +266,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
         * The Mutex is owned, but this thread must be the owner.
         * Special case for Global Lock, any thread can release
         */
-       if ((obj_desc->mutex.owner_thread_id !=
+       if ((obj_desc->mutex.owner_thread->thread_id !=
             walk_state->thread->thread_id)
            && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
                ACPI_ERROR((AE_INFO,
                            "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
                            (unsigned long)walk_state->thread->thread_id,
                            acpi_ut_get_node_name(obj_desc->mutex.node),
-                           (unsigned long)obj_desc->mutex.owner_thread_id));
+                           (unsigned long)obj_desc->mutex.owner_thread->
+                           thread_id));
                return_ACPI_STATUS(AE_AML_NOT_OWNER);
        }
 
@@ -296,7 +301,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 
        /* Unlink the mutex from the owner's list */
 
-       acpi_ex_unlink_mutex(obj_desc, walk_state->thread);
+       acpi_ex_unlink_mutex(obj_desc);
 
        /* Release the mutex, special case for Global Lock */
 
@@ -308,7 +313,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 
        /* Update the mutex and restore sync_level */
 
-       obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+       obj_desc->mutex.owner_thread = NULL;
        walk_state->thread->current_sync_level =
            obj_desc->mutex.original_sync_level;
 
@@ -363,7 +368,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
 
                /* Mark mutex unowned */
 
-               obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+               obj_desc->mutex.owner_thread = NULL;
 
                /* Update Thread sync_level (Last mutex is the important one) */
 
index 1ee4fb1175c680f5b8b7d3f706e467c5b73683ba..308eae52dc054d72c670fb8bccc8a90f6dd7e93d 100644 (file)
@@ -177,8 +177,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
 
        ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n"));
 
-       for (index = 0;
-            (index < ACPI_NAME_SIZE)
+       for (index = 0; (index < ACPI_NAME_SIZE)
             && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) {
                char_buf[index] = *aml_address++;
                ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index]));
index a6696621ff1b567d18652e4a31e8a86d574e99ef..efe5d4b461a47a7c91351608ce876ffc76de1566 100644 (file)
@@ -242,7 +242,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
                                            obj_desc->common_field.bit_length,
                                            0xFFFFFFFF
                                            /* Temp until we pass region_length as parameter */
-                                           );
+                   );
                bit_length = byte_alignment * 8;
 #endif
 
index ba761862a5990c85551c41a9bebaeeedd24b67eb..09d897b3f6d5b1848490eac18b9d09370409f782 100644 (file)
@@ -354,8 +354,7 @@ acpi_ex_resolve_operands(u16 opcode,
                        if ((opcode == AML_STORE_OP) &&
                            (ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
                             ACPI_TYPE_LOCAL_REFERENCE)
-                           && ((*stack_ptr)->reference.opcode ==
-                               AML_INDEX_OP)) {
+                           && ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) {
                                goto next_operand;
                        }
                        break;
index b2edf620ba8968d1086dfe1938be8727a8d1580e..9460baff30328f4c5565e2c5d671eabfdf4f634c 100644 (file)
@@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem")
 acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 {
        acpi_status status;
-       acpi_status status2;
 
        ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
 
@@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 
                /* We must wait, so unlock the interpreter */
 
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = acpi_os_wait_semaphore(semaphore, 1, timeout);
 
@@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 
                /* Reacquire the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-
-                       /* Report fatal error, could not acquire interpreter */
-
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 {
        acpi_status status;
-       acpi_status status2;
 
        ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
 
@@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 
                /* We must wait, so unlock the interpreter */
 
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = acpi_os_acquire_mutex(mutex, timeout);
 
@@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 
                /* Reacquire the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-
-                       /* Report fatal error, could not acquire interpreter */
-
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
@@ -209,20 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
 
 acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
 {
-       acpi_status status;
-
        ACPI_FUNCTION_ENTRY();
 
        /* Since this thread will sleep, we must release the interpreter */
 
-       acpi_ex_exit_interpreter();
+       acpi_ex_relinquish_interpreter();
 
        acpi_os_sleep(how_long);
 
        /* And now we must get the interpreter again */
 
-       status = acpi_ex_enter_interpreter();
-       return (status);
+       acpi_ex_reacquire_interpreter();
+       return (AE_OK);
 }
 
 /*******************************************************************************
index aea461f3a48cc02ab7269c8e7e7e9807657edefc..6b0aeccbb69b3f59738d5a9dd22fe875a1a2d018 100644 (file)
@@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
  *
  * PARAMETERS:  None
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: Enter the interpreter execution region.  Failure to enter
- *              the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ *              the interpreter region is a fatal system error. Used in
+ *              conjunction with exit_interpreter.
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
 {
        acpi_status status;
 
@@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void)
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
        if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+               ACPI_ERROR((AE_INFO,
+                           "Could not acquire AML Interpreter mutex"));
        }
 
-       return_ACPI_STATUS(status);
+       return_VOID;
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ex_exit_interpreter
+ * FUNCTION:    acpi_ex_reacquire_interpreter
  *
  * PARAMETERS:  None
  *
  * RETURN:      None
  *
- * DESCRIPTION: Exit the interpreter execution region
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ *              interpreter code. Failure to enter the interpreter region is a
+ *              fatal system error. Used in  conjuction with
+ *              relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+       ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+       /*
+        * If the global serialized flag is set, do not release the interpreter,
+        * since it was not actually released by acpi_ex_relinquish_interpreter.
+        * This forces the interpreter to be single threaded.
+        */
+       if (!acpi_gbl_all_methods_serialized) {
+               acpi_ex_enter_interpreter();
+       }
+
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_exit_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
  *
- * Cases where the interpreter is unlocked:
- *      1) Completion of the execution of a control method
- *      2) Method blocked on a Sleep() AML opcode
- *      3) Method blocked on an Acquire() AML opcode
- *      4) Method blocked on a Wait() AML opcode
- *      5) Method blocked to acquire the global lock
- *      6) Method blocked to execute a serialized control method that is
- *          already executing
- *      7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ *              routine used to exit the interpreter when all processing has
+ *              been completed.
  *
  ******************************************************************************/
 
@@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void)
 
        status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
        if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+               ACPI_ERROR((AE_INFO,
+                           "Could not release AML Interpreter mutex"));
+       }
+
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ *              interpreter - before attempting an operation that will possibly
+ *              block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ *      1) Method to be blocked on a Sleep() AML opcode
+ *      2) Method to be blocked on an Acquire() AML opcode
+ *      3) Method to be blocked on a Wait() AML opcode
+ *      4) Method to be blocked to acquire the global lock
+ *      5) Method to be blocked waiting to execute a serialized control method
+ *          that is currently executing
+ *      6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+       ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+       /*
+        * If the global serialized flag is set, do not release the interpreter.
+        * This forces the interpreter to be single threaded.
+        */
+       if (!acpi_gbl_all_methods_serialized) {
+               acpi_ex_exit_interpreter();
        }
 
        return_VOID;
@@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void)
  *
  * RETURN:      none
  *
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- *              belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ *              32-bit, as determined by the revision of the DSDT.
  *
  ******************************************************************************/
 
index c84b1faba28cf3900001c78f2b0700975faf4d61..76c525dc590b3b91aedfe0c99d6526eabfe5bbc9 100644 (file)
@@ -152,7 +152,6 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
 
 ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector)
 #endif
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_enter_sleep_state_prep
index 26fd0dd6953dc7be4792610f8e662276b46d6124..97b2ac57c16be69d7ad94c1899410f806164e9af 100644 (file)
@@ -75,7 +75,7 @@ ACPI_MODULE_NAME("nseval")
  * MUTEX:       Locks interpreter
  *
  ******************************************************************************/
-acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
 {
        acpi_status status;
 
@@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                 * Execute the method via the interpreter. The interpreter is locked
                 * here before calling into the AML parser
                 */
-               status = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-
+               acpi_ex_enter_interpreter();
                status = acpi_ps_execute_method(info);
                acpi_ex_exit_interpreter();
        } else {
@@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                 * resolution, we must lock it because we could access an opregion.
                 * The opregion access code assumes that the interpreter is locked.
                 */
-               status = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
+               acpi_ex_enter_interpreter();
 
                /* Function has a strange interface */
 
index c4ab615f77fea6a133f2f1cf9865217e9d02b0d5..33db2241044e5930430c5091f6580c9013721f15 100644 (file)
@@ -214,7 +214,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
                        u32 level, void *context, void **return_value)
 {
        acpi_object_type type;
-       acpi_status status;
+       acpi_status status = AE_OK;
        struct acpi_init_walk_info *info =
            (struct acpi_init_walk_info *)context;
        struct acpi_namespace_node *node =
@@ -268,10 +268,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
        /*
         * Must lock the interpreter before executing AML code
         */
-       status = acpi_ex_enter_interpreter();
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
+       acpi_ex_enter_interpreter();
 
        /*
         * Each of these types can contain executable AML code within the
index 94eb8f332d941bb67a0175e85f17d4560ecd4f4d..280b8357c46c32ebe3f5dc9933f6a19ae95f4d0e 100644 (file)
@@ -65,10 +65,8 @@ ACPI_MODULE_NAME("nswalk")
  *              within Scope is returned.
  *
  ******************************************************************************/
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
-                                                 struct acpi_namespace_node
-                                                 *parent_node,
-                                                 struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
+                                                 *parent_node, struct acpi_namespace_node
                                                  *child_node)
 {
        struct acpi_namespace_node *next_node = NULL;
index 8904d0fae6a2ff90794389456b6f62420c5410d3..be4f2899de74e6b6d91af7978f6f411452f1391b 100644 (file)
@@ -48,7 +48,6 @@
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsxfeval")
-
 #ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
@@ -73,8 +72,8 @@ ACPI_MODULE_NAME("nsxfeval")
 acpi_status
 acpi_evaluate_object_typed(acpi_handle handle,
                           acpi_string pathname,
-                          struct acpi_object_list * external_params,
-                          struct acpi_buffer * return_buffer,
+                          struct acpi_object_list *external_params,
+                          struct acpi_buffer *return_buffer,
                           acpi_object_type return_type)
 {
        acpi_status status;
@@ -143,7 +142,6 @@ acpi_evaluate_object_typed(acpi_handle handle,
 
 ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
 #endif                         /*  ACPI_FUTURE_USAGE  */
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_evaluate_object
@@ -170,7 +168,6 @@ acpi_evaluate_object(acpi_handle handle,
                     struct acpi_buffer *return_buffer)
 {
        acpi_status status;
-       acpi_status status2;
        struct acpi_evaluate_info *info;
        acpi_size buffer_space_needed;
        u32 i;
@@ -329,14 +326,12 @@ acpi_evaluate_object(acpi_handle handle,
                 * Delete the internal return object. NOTE: Interpreter must be
                 * locked to avoid race condition.
                 */
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_SUCCESS(status2)) {
+               acpi_ex_enter_interpreter();
 
-                       /* Remove one reference on the return object (should delete it) */
+               /* Remove one reference on the return object (should delete it) */
 
-                       acpi_ut_remove_reference(info->return_object);
-                       acpi_ex_exit_interpreter();
-               }
+               acpi_ut_remove_reference(info->return_object);
+               acpi_ex_exit_interpreter();
        }
 
       cleanup:
index 4dd0dabe81cbe12d8ec00d5756adeed8c3bdae84..8fcd6a15517f5810ee6b2b6f98ba33d01d8d707a 100644 (file)
@@ -228,7 +228,7 @@ int __init acpi_numa_init(void)
        return 0;
 }
 
-int __meminit acpi_get_pxm(acpi_handle h)
+int acpi_get_pxm(acpi_handle h)
 {
        unsigned long pxm;
        acpi_status status;
@@ -246,7 +246,7 @@ int __meminit acpi_get_pxm(acpi_handle h)
 }
 EXPORT_SYMBOL(acpi_get_pxm);
 
-int __meminit acpi_get_node(acpi_handle *handle)
+int acpi_get_node(acpi_handle *handle)
 {
        int pxm, node = -1;
 
index c2bed56915e1eafe1559d906ba06661764990d45..b998340e23d4126074a36cc1af38d05461b4bde9 100644 (file)
@@ -71,6 +71,7 @@ static unsigned int acpi_irq_irq;
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
+static struct workqueue_struct *kacpi_notify_wq;
 
 static void __init acpi_request_region (struct acpi_generic_address *addr,
        unsigned int length, char *desc)
@@ -137,8 +138,9 @@ acpi_status acpi_os_initialize1(void)
                return AE_NULL_ENTRY;
        }
        kacpid_wq = create_singlethread_workqueue("kacpid");
+       kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
        BUG_ON(!kacpid_wq);
-
+       BUG_ON(!kacpi_notify_wq);
        return AE_OK;
 }
 
@@ -150,6 +152,7 @@ acpi_status acpi_os_terminate(void)
        }
 
        destroy_workqueue(kacpid_wq);
+       destroy_workqueue(kacpi_notify_wq);
 
        return AE_OK;
 }
@@ -601,6 +604,23 @@ void acpi_os_derive_pci_id(acpi_handle rhandle,    /* upper bound  */
 }
 
 static void acpi_os_execute_deferred(struct work_struct *work)
+{
+       struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
+       if (!dpc) {
+               printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+               return;
+       }
+
+       dpc->function(dpc->context);
+       kfree(dpc);
+
+       /* Yield cpu to notify thread */
+       cond_resched();
+
+       return;
+}
+
+static void acpi_os_execute_notify(struct work_struct *work)
 {
        struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
 
@@ -637,14 +657,12 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        acpi_status status = AE_OK;
        struct acpi_os_dpc *dpc;
 
-       ACPI_FUNCTION_TRACE("os_queue_for_execution");
-
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                          "Scheduling function [%p(%p)] for deferred execution.\n",
                          function, context));
 
        if (!function)
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               return AE_BAD_PARAMETER;
 
        /*
         * Allocate/initialize DPC structure.  Note that this memory will be
@@ -662,14 +680,21 @@ acpi_status acpi_os_execute(acpi_execute_type type,
        dpc->function = function;
        dpc->context = context;
 
-       INIT_WORK(&dpc->work, acpi_os_execute_deferred);
-       if (!queue_work(kacpid_wq, &dpc->work)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+       if (type == OSL_NOTIFY_HANDLER) {
+               INIT_WORK(&dpc->work, acpi_os_execute_notify);
+               if (!queue_work(kacpi_notify_wq, &dpc->work)) {
+                       status = AE_ERROR;
+                       kfree(dpc);
+               }
+       } else {
+               INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+               if (!queue_work(kacpid_wq, &dpc->work)) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
                                  "Call to queue_work() failed.\n"));
-               kfree(dpc);
-               status = AE_ERROR;
+                       status = AE_ERROR;
+                       kfree(dpc);
+               }
        }
-
        return_ACPI_STATUS(status);
 }
 
index 16d8b6cc3c220407917111204ba587f6164845aa..9296e86761d74f2aa4000167f068f611d36486d3 100644 (file)
@@ -185,459 +185,453 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = {
 /* Index           Name                 Parser Args               Interpreter Args                ObjectType                    Class                      Type                  Flags */
 
 /* 00 */ ACPI_OP("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER,
-                        AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+                AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
 /* 01 */ ACPI_OP("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER,
-                        AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+                AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
 /* 02 */ ACPI_OP("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP,
-                        ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_SIMPLE,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_SIMPLE,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 03 */ ACPI_OP("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 04 */ ACPI_OP("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP,
-                        ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_CONSTANT),
+                ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_CONSTANT),
 /* 05 */ ACPI_OP("WordConst", ARGP_WORD_OP, ARGI_WORD_OP,
-                        ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_CONSTANT),
+                ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_CONSTANT),
 /* 06 */ ACPI_OP("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP,
-                        ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_CONSTANT),
+                ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_CONSTANT),
 /* 07 */ ACPI_OP("String", ARGP_STRING_OP, ARGI_STRING_OP,
-                        ACPI_TYPE_STRING, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_CONSTANT),
+                ACPI_TYPE_STRING, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_CONSTANT),
 /* 08 */ ACPI_OP("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
-                        ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_NO_OBJ,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_NO_OBJ,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 09 */ ACPI_OP("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP,
-                        ACPI_TYPE_BUFFER, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_OBJECT,
-                        AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+                ACPI_TYPE_BUFFER, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_OBJECT,
+                AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
 /* 0A */ ACPI_OP("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP,
-                        ACPI_TYPE_PACKAGE, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_OBJECT,
-                        AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+                ACPI_TYPE_PACKAGE, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_OBJECT,
+                AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
 /* 0B */ ACPI_OP("Method", ARGP_METHOD_OP, ARGI_METHOD_OP,
-                        ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_COMPLEX,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED | AML_DEFER),
+                ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_COMPLEX,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED | AML_DEFER),
 /* 0C */ ACPI_OP("Local0", ARGP_LOCAL0, ARGI_LOCAL0,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 0D */ ACPI_OP("Local1", ARGP_LOCAL1, ARGI_LOCAL1,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 0E */ ACPI_OP("Local2", ARGP_LOCAL2, ARGI_LOCAL2,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 0F */ ACPI_OP("Local3", ARGP_LOCAL3, ARGI_LOCAL3,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 10 */ ACPI_OP("Local4", ARGP_LOCAL4, ARGI_LOCAL4,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 11 */ ACPI_OP("Local5", ARGP_LOCAL5, ARGI_LOCAL5,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 12 */ ACPI_OP("Local6", ARGP_LOCAL6, ARGI_LOCAL6,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 13 */ ACPI_OP("Local7", ARGP_LOCAL7, ARGI_LOCAL7,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LOCAL_VARIABLE, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LOCAL_VARIABLE, 0),
 /* 14 */ ACPI_OP("Arg0", ARGP_ARG0, ARGI_ARG0,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 15 */ ACPI_OP("Arg1", ARGP_ARG1, ARGI_ARG1,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 16 */ ACPI_OP("Arg2", ARGP_ARG2, ARGI_ARG2,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 17 */ ACPI_OP("Arg3", ARGP_ARG3, ARGI_ARG3,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 18 */ ACPI_OP("Arg4", ARGP_ARG4, ARGI_ARG4,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 19 */ ACPI_OP("Arg5", ARGP_ARG5, ARGI_ARG5,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 1A */ ACPI_OP("Arg6", ARGP_ARG6, ARGI_ARG6,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_METHOD_ARGUMENT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_METHOD_ARGUMENT, 0),
 /* 1B */ ACPI_OP("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R),
 /* 1C */ ACPI_OP("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R),
 /* 1D */ ACPI_OP("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 1E */ ACPI_OP("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
 /* 1F */ ACPI_OP("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 20 */ ACPI_OP("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
 /* 21 */ ACPI_OP("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
 /* 22 */ ACPI_OP("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 23 */ ACPI_OP("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_2T_1R,
-                        AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_2T_1R,
+                AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT),
 /* 24 */ ACPI_OP("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 25 */ ACPI_OP("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 26 */ ACPI_OP("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 27 */ ACPI_OP("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 28 */ ACPI_OP("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 29 */ ACPI_OP("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 2A */ ACPI_OP("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
 /* 2B */ ACPI_OP("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 2C */ ACPI_OP("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP,
-                        ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY,
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 2D */ ACPI_OP("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP,
-                        ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY,
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 2E */ ACPI_OP("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
 /* 2F */ ACPI_OP("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R),
 /* 30 */ ACPI_OP("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
 /* 31 */ ACPI_OP("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R),
 /* 32 */ ACPI_OP("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R,
-                        AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R,
+                AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
 /* 33 */ ACPI_OP("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP,
-                        ARGI_CREATE_DWORD_FIELD_OP,
-                        ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_CREATE),
+                ARGI_CREATE_DWORD_FIELD_OP,
+                ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_CREATE),
 /* 34 */ ACPI_OP("CreateWordField", ARGP_CREATE_WORD_FIELD_OP,
-                        ARGI_CREATE_WORD_FIELD_OP,
-                        ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_CREATE),
+                ARGI_CREATE_WORD_FIELD_OP,
+                ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_CREATE),
 /* 35 */ ACPI_OP("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP,
-                        ARGI_CREATE_BYTE_FIELD_OP,
-                        ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_CREATE),
+                ARGI_CREATE_BYTE_FIELD_OP,
+                ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_CREATE),
 /* 36 */ ACPI_OP("CreateBitField", ARGP_CREATE_BIT_FIELD_OP,
-                        ARGI_CREATE_BIT_FIELD_OP,
-                        ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_CREATE),
+                ARGI_CREATE_BIT_FIELD_OP,
+                ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_CREATE),
 /* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
 /* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC |
-                        AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
 /* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC |
-                        AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
 /* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
-                        AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
+                AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
 /* 3B */ ACPI_OP("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
 /* 3C */ ACPI_OP("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
 /* 3D */ ACPI_OP("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
 /* 3E */ ACPI_OP("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+                AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
 /* 3F */ ACPI_OP("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+                AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
 /* 40 */ ACPI_OP("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+                AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
 /* 41 */ ACPI_OP("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+                AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
 /* 42 */ ACPI_OP("Return", ARGP_RETURN_OP, ARGI_RETURN_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_CONTROL,
-                        AML_TYPE_CONTROL, AML_HAS_ARGS),
+                ACPI_TYPE_ANY, AML_CLASS_CONTROL,
+                AML_TYPE_CONTROL, AML_HAS_ARGS),
 /* 43 */ ACPI_OP("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+                AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
 /* 44 */ ACPI_OP("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+                ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
 /* 45 */ ACPI_OP("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER,
-                        AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+                AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
 
 /* Prefixed opcodes (Two-byte opcodes with a prefix op) */
 
 /* 46 */ ACPI_OP("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 47 */ ACPI_OP("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
-                        AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+                AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
 /* 48 */ ACPI_OP("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
 /* 49 */ ACPI_OP("CreateField", ARGP_CREATE_FIELD_OP,
-                        ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,
-                        AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_FIELD | AML_CREATE),
+                ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,
+                AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_FIELD | AML_CREATE),
 /* 4A */ ACPI_OP("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R,
-                        AML_FLAGS_EXEC_1A_1T_0R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R,
+                AML_FLAGS_EXEC_1A_1T_0R),
 /* 4B */ ACPI_OP("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
-                        AML_FLAGS_EXEC_1A_0T_0R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+                AML_FLAGS_EXEC_1A_0T_0R),
 /* 4C */ ACPI_OP("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
-                        AML_FLAGS_EXEC_1A_0T_0R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+                AML_FLAGS_EXEC_1A_0T_0R),
 /* 4D */ ACPI_OP("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
 /* 4E */ ACPI_OP("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
 /* 4F */ ACPI_OP("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
-                        AML_FLAGS_EXEC_2A_0T_1R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+                AML_FLAGS_EXEC_2A_0T_1R),
 /* 50 */ ACPI_OP("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
-                        AML_FLAGS_EXEC_1A_0T_0R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+                AML_FLAGS_EXEC_1A_0T_0R),
 /* 51 */ ACPI_OP("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
 /* 52 */ ACPI_OP("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 53 */ ACPI_OP("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 54 */ ACPI_OP("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
 /* 55 */ ACPI_OP("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP,
-                        ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
-                        AML_TYPE_CONSTANT, 0),
+                ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+                AML_TYPE_CONSTANT, 0),
 /* 56 */ ACPI_OP("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_CONSTANT, 0),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_CONSTANT, 0),
 /* 57 */ ACPI_OP("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R,
-                        AML_FLAGS_EXEC_3A_0T_0R),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R,
+                AML_FLAGS_EXEC_3A_0T_0R),
 /* 58 */ ACPI_OP("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP,
-                        ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_COMPLEX,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED | AML_DEFER),
+                ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_COMPLEX,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED | AML_DEFER),
 /* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_FIELD),
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
 /* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP,
-                        ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_NO_OBJ,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_NO_OBJ,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 5B */ ACPI_OP("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP,
-                        ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_SIMPLE,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_SIMPLE,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 5C */ ACPI_OP("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP,
-                        ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_SIMPLE,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_SIMPLE,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 5D */ ACPI_OP("ThermalZone", ARGP_THERMAL_ZONE_OP,
-                        ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL,
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_FIELD),
+                ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
 /* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_FIELD),
+                ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
 
 /* Internal opcodes that map to invalid AML opcodes */
 
 /* 60 */ ACPI_OP("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
-                        AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+                AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
 /* 61 */ ACPI_OP("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
-                        AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+                AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
 /* 62 */ ACPI_OP("LGreaterEqual", ARGP_LGREATEREQUAL_OP,
-                        ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS,
-                        AML_HAS_ARGS | AML_CONSTANT),
+                ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY,
+                AML_CLASS_INTERNAL, AML_TYPE_BOGUS,
+                AML_HAS_ARGS | AML_CONSTANT),
 /* 63 */ ACPI_OP("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP,
-                        ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE),
+                ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE),
 /* 64 */ ACPI_OP("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP,
-                        ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL,
-                        AML_TYPE_METHOD_CALL,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
+                ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL,
+                AML_TYPE_METHOD_CALL,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
 /* 65 */ ACPI_OP("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, 0),
+                ACPI_TYPE_ANY, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, 0),
 /* 66 */ ACPI_OP("-ReservedField-", ARGP_RESERVEDFIELD_OP,
-                        ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+                ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY,
+                AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
 /* 67 */ ACPI_OP("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
-                        AML_TYPE_BOGUS,
-                        AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+                ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+                AML_TYPE_BOGUS,
+                AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
 /* 68 */ ACPI_OP("-AccessField-", ARGP_ACCESSFIELD_OP,
-                        ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+                ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY,
+                AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
 /* 69 */ ACPI_OP("-StaticString", ARGP_STATICSTRING_OP,
-                        ARGI_STATICSTRING_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+                ARGI_STATICSTRING_OP, ACPI_TYPE_ANY,
+                AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
 /* 6A */ ACPI_OP("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
-                        AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN,
-                        AML_HAS_ARGS | AML_HAS_RETVAL),
+                AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN,
+                AML_HAS_ARGS | AML_HAS_RETVAL),
 /* 6B */ ACPI_OP("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID,
-                        AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS),
+                AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS),
 /* 6C */ ACPI_OP("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
-                        AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS),
+                AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS),
 /* 6D */ ACPI_OP("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
-                        AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS),
+                AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS),
 
 /* ACPI 2.0 opcodes */
 
 /* 6E */ ACPI_OP("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP,
-                        ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
-                        AML_TYPE_LITERAL, AML_CONSTANT),
+                ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+                AML_TYPE_LITERAL, AML_CONSTANT),
        /* 6F */ ACPI_OP("Package", /* Var */ ARGP_VAR_PACKAGE_OP,
                         ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE,
                         AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT,
                         AML_HAS_ARGS | AML_DEFER),
 /* 70 */ ACPI_OP("ConcatenateResTemplate", ARGP_CONCAT_RES_OP,
-                        ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+                ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY,
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
 /* 71 */ ACPI_OP("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
 /* 72 */ ACPI_OP("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP,
-                        ARGI_CREATE_QWORD_FIELD_OP,
-                        ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
-                        AML_TYPE_CREATE_FIELD,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
-                        AML_DEFER | AML_CREATE),
+                ARGI_CREATE_QWORD_FIELD_OP,
+                ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+                AML_TYPE_CREATE_FIELD,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+                AML_DEFER | AML_CREATE),
 /* 73 */ ACPI_OP("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 74 */ ACPI_OP("ToDecimalString", ARGP_TO_DEC_STR_OP,
-                        ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY,
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 75 */ ACPI_OP("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 76 */ ACPI_OP("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R,
-                        AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R,
+                AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
 /* 77 */ ACPI_OP("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_2A_1T_1R,
-                        AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_2A_1T_1R,
+                AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
 /* 78 */ ACPI_OP("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
 /* 79 */ ACPI_OP("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R,
-                        AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT),
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R,
+                AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT),
 /* 7A */ ACPI_OP("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+                ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
 /* 7B */ ACPI_OP("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
-                        AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
+                ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+                AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
 /* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP,
-                        ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
-                        AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE | AML_NAMED),
+                ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
+                AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+                AML_NSNODE | AML_NAMED),
 /* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
-                        ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
-                        AML_TYPE_NAMED_NO_OBJ,
-                        AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
-                        AML_NSNODE),
+                ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+                AML_TYPE_NAMED_NO_OBJ,
+                AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE),
 
 /* ACPI 3.0 opcodes */
 
 /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY,
-                        AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
-                        AML_FLAGS_EXEC_0A_0T_1R)
+                AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
+                AML_FLAGS_EXEC_0A_0T_1R)
 
 /*! [End] no source code translation !*/
 };
index 8c6d3fdec38a7d08358a4cd7e60410b26510b5a8..0dd2ce8a3475d4c062a0a67941805fb29a3063ec 100644 (file)
@@ -567,7 +567,8 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
                                                     (*sub_object_list)->string.
                                                     length + 1);
                        } else {
-                               temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
+                               temp_size_needed +=
+                                   acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
                        }
                } else {
                        /*
index cc48ab05676c5ccefd1b342cd8532260c48d6470..50da494c3ee25f742ea67d3614c99812512299c1 100644 (file)
@@ -267,16 +267,19 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                 * If BIOS erroneously reversed the _PRT source_name and source_index,
                 * then reverse them back.
                 */
-               if (ACPI_GET_OBJECT_TYPE (sub_object_list[3]) != ACPI_TYPE_INTEGER) {
+               if (ACPI_GET_OBJECT_TYPE(sub_object_list[3]) !=
+                   ACPI_TYPE_INTEGER) {
                        if (acpi_gbl_enable_interpreter_slack) {
                                source_name_index = 3;
                                source_index_index = 2;
-                               printk(KERN_WARNING "ACPI: Handling Garbled _PRT entry\n");
+                               printk(KERN_WARNING
+                                      "ACPI: Handling Garbled _PRT entry\n");
                        } else {
                                ACPI_ERROR((AE_INFO,
-                                       "(PRT[%X].source_index) Need Integer, found %s",
-                                       index,
-                                       acpi_ut_get_object_type_name(sub_object_list[3])));
+                                           "(PRT[%X].source_index) Need Integer, found %s",
+                                           index,
+                                           acpi_ut_get_object_type_name
+                                           (sub_object_list[3])));
                                return_ACPI_STATUS(AE_BAD_DATA);
                        }
                }
index de20a5d6decf52053f33c63909f0ebef7972a814..46da116a4030eacb57756273641f4395b3f002b7 100644 (file)
@@ -46,7 +46,6 @@
 
 #define _COMPONENT          ACPI_RESOURCES
 ACPI_MODULE_NAME("rsdump")
-
 #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
 /* Local prototypes */
 static void acpi_rs_out_string(char *title, char *value);
@@ -489,10 +488,9 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
                        /*
                         * Optional resource_source for Address resources
                         */
-                       acpi_rs_dump_resource_source(ACPI_CAST_PTR
-                                                    (struct
-                                                     acpi_resource_source,
-                                                     target));
+                       acpi_rs_dump_resource_source(ACPI_CAST_PTR(struct
+                                                                  acpi_resource_source,
+                                                                  target));
                        break;
 
                default:
index 7e3c335ab320a8aab6e26554921961fa93679289..2c2adb6292c160bfa68771b692a0f98ca316d97d 100644 (file)
@@ -142,7 +142,7 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = {
 };
 #endif
 
-#endif /* ACPI_FUTURE_USAGE */
+#endif                         /* ACPI_FUTURE_USAGE */
 /*
  * Base sizes for external AML resource descriptors, indexed by internal type.
  * Includes size of the descriptor header (1 byte for small descriptors,
index a92755c8877d63fd57a12d6cb4f3747a14499f23..ca21e4660c79c8b4471a9ee41ec2cf058f96c7b9 100644 (file)
@@ -153,10 +153,9 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
 
                /* Perform the conversion */
 
-               status = acpi_rs_convert_resource_to_aml(resource,
-                                                        ACPI_CAST_PTR(union
-                                                                      aml_resource,
-                                                                      aml),
+               status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union
+                                                                                aml_resource,
+                                                                                aml),
                                                         acpi_gbl_set_resource_dispatch
                                                         [resource->type]);
                if (ACPI_FAILURE(status)) {
index 3b63b561b94e506291a7d91bb5a6468d867fa024..c7081afa893aeb22529ee2a8ea89bc39261b7eb9 100644 (file)
@@ -46,7 +46,6 @@
 
 #define _COMPONENT          ACPI_RESOURCES
 ACPI_MODULE_NAME("rsmisc")
-
 #define INIT_RESOURCE_TYPE(i)       i->resource_offset
 #define INIT_RESOURCE_LENGTH(i)     i->aml_offset
 #define INIT_TABLE_LENGTH(i)        i->value
@@ -429,8 +428,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
                         * Optional resource_source (Index and String)
                         */
                        aml_length =
-                           acpi_rs_set_resource_source(aml,
-                                                       (acpi_rs_length)
+                           acpi_rs_set_resource_source(aml, (acpi_rs_length)
                                                        aml_length, source);
                        acpi_rs_set_resource_length(aml_length, aml);
                        break;
index 2442a8f8df576e240fb40323da8689655d1732b3..11c0bd7b9cfdea8272f374f51d127654586f0a0c 100644 (file)
@@ -353,10 +353,8 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length,
                 *
                 * Zero the entire area of the buffer.
                 */
-               total_length =
-                   (u32)
-                   ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) +
-                   1;
+               total_length = (u32)
+               ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1;
                total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length);
 
                ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
index 991f8901498c1166817c3922f982469932e07f5a..f63813a358c57f37b96c9c0517f5b37b9d63ce4c 100644 (file)
@@ -217,7 +217,6 @@ acpi_get_current_resources(acpi_handle device_handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
-
 #ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
@@ -261,7 +260,6 @@ acpi_get_possible_resources(acpi_handle device_handle,
 
 ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
 #endif                         /*  ACPI_FUTURE_USAGE  */
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_set_current_resources
@@ -496,7 +494,6 @@ ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource)
  *              each resource in the list.
  *
  ******************************************************************************/
-
 acpi_status
 acpi_walk_resources(acpi_handle device_handle,
                    char *name,
index f8c63410bcbf55eb285e88f2d156ec95634d390f..bc7e16ec839366725ff6f0bd6e8259bb7fb6bc33 100644 (file)
@@ -29,7 +29,6 @@ static u32 acpi_suspend_states[] = {
        [PM_SUSPEND_ON] = ACPI_STATE_S0,
        [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
        [PM_SUSPEND_MEM] = ACPI_STATE_S3,
-       [PM_SUSPEND_DISK] = ACPI_STATE_S4,
        [PM_SUSPEND_MAX] = ACPI_STATE_S5
 };
 
@@ -94,14 +93,6 @@ static int acpi_pm_enter(suspend_state_t pm_state)
                do_suspend_lowlevel();
                break;
 
-       case PM_SUSPEND_DISK:
-               if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
-                       status = acpi_enter_sleep_state(acpi_state);
-               break;
-       case PM_SUSPEND_MAX:
-               acpi_power_off();
-               break;
-
        default:
                return -EINVAL;
        }
@@ -157,12 +148,13 @@ int acpi_suspend(u32 acpi_state)
        suspend_state_t states[] = {
                [1] = PM_SUSPEND_STANDBY,
                [3] = PM_SUSPEND_MEM,
-               [4] = PM_SUSPEND_DISK,
                [5] = PM_SUSPEND_MAX
        };
 
        if (acpi_state < 6 && states[acpi_state])
                return pm_suspend(states[acpi_state]);
+       if (acpi_state == 4)
+               return hibernate();
        return -EINVAL;
 }
 
@@ -189,6 +181,49 @@ static struct pm_ops acpi_pm_ops = {
        .finish = acpi_pm_finish,
 };
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static int acpi_hibernation_prepare(void)
+{
+       return acpi_sleep_prepare(ACPI_STATE_S4);
+}
+
+static int acpi_hibernation_enter(void)
+{
+       acpi_status status = AE_OK;
+       unsigned long flags = 0;
+
+       ACPI_FLUSH_CPU_CACHE();
+
+       local_irq_save(flags);
+       acpi_enable_wakeup_device(ACPI_STATE_S4);
+       /* This shouldn't return.  If it returns, we have a problem */
+       status = acpi_enter_sleep_state(ACPI_STATE_S4);
+       local_irq_restore(flags);
+
+       return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_finish(void)
+{
+       acpi_leave_sleep_state(ACPI_STATE_S4);
+       acpi_disable_wakeup_device(ACPI_STATE_S4);
+
+       /* reset firmware waking vector */
+       acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+       if (init_8259A_after_S1) {
+               printk("Broken toshiba laptop -> kicking interrupts\n");
+               init_8259A(0);
+       }
+}
+
+static struct hibernation_ops acpi_hibernation_ops = {
+       .prepare = acpi_hibernation_prepare,
+       .enter = acpi_hibernation_enter,
+       .finish = acpi_hibernation_finish,
+};
+#endif                         /* CONFIG_SOFTWARE_SUSPEND */
+
 /*
  * Toshiba fails to preserve interrupts over S1, reinitialization
  * of 8259 is needed after S1 resume.
@@ -227,14 +262,17 @@ int __init acpi_sleep_init(void)
                        sleep_states[i] = 1;
                        printk(" S%d", i);
                }
-               if (i == ACPI_STATE_S4) {
-                       if (sleep_states[i])
-                               acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
-               }
        }
        printk(")\n");
 
        pm_set_ops(&acpi_pm_ops);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+       if (sleep_states[ACPI_STATE_S4])
+               hibernation_set_ops(&acpi_hibernation_ops);
+#else
+       sleep_states[ACPI_STATE_S4] = 0;
+#endif
+
        return 0;
 }
-
index 5a76e5be61d5da1a1445feececba0f0a09f51bde..61f1822cc35050648c2958bf5b0de005f5920313 100644 (file)
@@ -60,7 +60,7 @@ acpi_system_write_sleep(struct file *file,
        state = simple_strtoul(str, NULL, 0);
 #ifdef CONFIG_SOFTWARE_SUSPEND
        if (state == 4) {
-               error = pm_suspend(PM_SUSPEND_DISK);
+               error = hibernate();
                goto Done;
        }
 #endif
@@ -349,8 +349,7 @@ acpi_system_write_alarm(struct file *file,
       end:
        return_VALUE(result ? result : count);
 }
-#endif /* HAVE_ACPI_LEGACY_ALARM */
-
+#endif                         /* HAVE_ACPI_LEGACY_ALARM */
 
 extern struct list_head acpi_wakeup_device_list;
 extern spinlock_t acpi_device_lock;
@@ -380,8 +379,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
                           dev->wakeup.state.enabled ? "enabled" : "disabled");
                if (ldev)
                        seq_printf(seq, "%s:%s",
-                               ldev->bus ? ldev->bus->name : "no-bus",
-                               ldev->bus_id);
+                                  ldev->bus ? ldev->bus->name : "no-bus",
+                                  ldev->bus_id);
                seq_printf(seq, "\n");
                put_device(ldev);
 
@@ -490,7 +489,7 @@ static u32 rtc_handler(void *context)
 
        return ACPI_INTERRUPT_HANDLED;
 }
-#endif /* HAVE_ACPI_LEGACY_ALARM */
+#endif                         /* HAVE_ACPI_LEGACY_ALARM */
 
 static int __init acpi_sleep_proc_init(void)
 {
@@ -517,7 +516,7 @@ static int __init acpi_sleep_proc_init(void)
                entry->proc_fops = &acpi_system_alarm_fops;
 
        acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
-#endif /* HAVE_ACPI_LEGACY_ALARM */
+#endif                         /* HAVE_ACPI_LEGACY_ALARM */
 
        /* 'wakeup device' [R/W] */
        entry =
index 1db833eb2417c5988890dc8ce4b62bed764e0d45..1285e91474fbff4c504d82e75ebe9b63c608eb24 100644 (file)
@@ -334,7 +334,8 @@ static void acpi_tb_convert_fadt(void)
                                     (acpi_gbl_FADT.xpm1a_event_block.address +
                                      pm1_register_length));
        /* Don't forget to copy space_id of the GAS */
-       acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+       acpi_gbl_xpm1a_enable.space_id =
+           acpi_gbl_FADT.xpm1a_event_block.space_id;
 
        /* The PM1B register block is optional, ignore if not present */
 
@@ -344,7 +345,8 @@ static void acpi_tb_convert_fadt(void)
                                             (acpi_gbl_FADT.xpm1b_event_block.
                                              address + pm1_register_length));
                /* Don't forget to copy space_id of the GAS */
-               acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+               acpi_gbl_xpm1b_enable.space_id =
+                   acpi_gbl_FADT.xpm1a_event_block.space_id;
 
        }
 
index 417ef5fa7666e4a09b49f25a764778778de84cd4..5b302c4e293f78dd734e9c322a6551f03c01b493 100644 (file)
@@ -201,6 +201,7 @@ acpi_status acpi_reallocate_root_table(void)
 
        return_ACPI_STATUS(AE_OK);
 }
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -262,7 +263,7 @@ ACPI_EXPORT_SYMBOL(acpi_load_table)
 acpi_status
 acpi_get_table_header(char *signature,
                      acpi_native_uint instance,
-                     struct acpi_table_header *out_table_header)
+                     struct acpi_table_header * out_table_header)
 {
        acpi_native_uint i;
        acpi_native_uint j;
@@ -321,7 +322,6 @@ acpi_get_table_header(char *signature,
 
 ACPI_EXPORT_SYMBOL(acpi_get_table_header)
 
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_unload_table_id
@@ -346,11 +346,11 @@ acpi_status acpi_unload_table_id(acpi_owner_id id)
                        continue;
                }
                /*
-               * Delete all namespace objects owned by this table. Note that these
-               * objects can appear anywhere in the namespace by virtue of the AML
-               * "Scope" operator. Thus, we need to track ownership by an ID, not
-               * simply a position within the hierarchy
-               */
+                * Delete all namespace objects owned by this table. Note that these
+                * objects can appear anywhere in the namespace by virtue of the AML
+                * "Scope" operator. Thus, we need to track ownership by an ID, not
+                * simply a position within the hierarchy
+                */
                acpi_tb_delete_namespace_by_owner(i);
                status = acpi_tb_release_owner_id(i);
                acpi_tb_set_table_loaded_flag(i, FALSE);
@@ -376,7 +376,7 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
  *****************************************************************************/
 acpi_status
 acpi_get_table(char *signature,
-              acpi_native_uint instance, struct acpi_table_header ** out_table)
+              acpi_native_uint instance, struct acpi_table_header **out_table)
 {
        acpi_native_uint i;
        acpi_native_uint j;
index 589b98b7b216e5096b9cb74fee45d6ae4035a0c9..1ada017d01efb8c8d03630b7c87bd7b01565fd5b 100644 (file)
@@ -59,8 +59,6 @@
 #define ACPI_THERMAL_NOTIFY_CRITICAL   0xF0
 #define ACPI_THERMAL_NOTIFY_HOT                0xF1
 #define ACPI_THERMAL_MODE_ACTIVE       0x00
-#define ACPI_THERMAL_MODE_PASSIVE      0x01
-#define ACPI_THERMAL_MODE_CRITICAL     0xff
 #define ACPI_THERMAL_PATH_POWEROFF     "/sbin/poweroff"
 
 #define ACPI_THERMAL_MAX_ACTIVE        10
@@ -86,9 +84,6 @@ static int acpi_thermal_resume(struct acpi_device *device);
 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_trip_points(struct file *,
-                                             const char __user *, size_t,
-                                             loff_t *);
 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
 static ssize_t acpi_thermal_write_cooling_mode(struct file *,
                                               const char __user *, size_t,
@@ -167,7 +162,6 @@ struct acpi_thermal {
        unsigned long temperature;
        unsigned long last_temperature;
        unsigned long polling_frequency;
-       u8 cooling_mode;
        volatile u8 zombie;
        struct acpi_thermal_flags flags;
        struct acpi_thermal_state state;
@@ -193,7 +187,6 @@ static const struct file_operations acpi_thermal_temp_fops = {
 static const struct file_operations acpi_thermal_trip_fops = {
        .open = acpi_thermal_trip_open_fs,
        .read = seq_read,
-       .write = acpi_thermal_write_trip_points,
        .llseek = seq_lseek,
        .release = single_release,
 };
@@ -297,11 +290,6 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       tz->cooling_mode = mode;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
-                         mode ? "passive" : "active"));
-
        return 0;
 }
 
@@ -889,67 +877,6 @@ static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
        return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
 }
 
-static ssize_t
-acpi_thermal_write_trip_points(struct file *file,
-                              const char __user * buffer,
-                              size_t count, loff_t * ppos)
-{
-       struct seq_file *m = file->private_data;
-       struct acpi_thermal *tz = m->private;
-
-       char *limit_string;
-       int num, critical, hot, passive;
-       int *active;
-       int i = 0;
-
-
-       limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
-       if (!limit_string)
-               return -ENOMEM;
-
-       active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
-       if (!active) {
-               kfree(limit_string);
-               return -ENOMEM;
-       }
-
-       if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
-               count = -EINVAL;
-               goto end;
-       }
-
-       if (copy_from_user(limit_string, buffer, count)) {
-               count = -EFAULT;
-               goto end;
-       }
-
-       limit_string[count] = '\0';
-
-       num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
-                    &critical, &hot, &passive,
-                    &active[0], &active[1], &active[2], &active[3], &active[4],
-                    &active[5], &active[6], &active[7], &active[8],
-                    &active[9]);
-       if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
-               count = -EINVAL;
-               goto end;
-       }
-
-       tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
-       tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
-       tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
-       for (i = 0; i < num - 3; i++) {
-               if (!(tz->trips.active[i].flags.valid))
-                       break;
-               tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
-       }
-
-      end:
-       kfree(active);
-       kfree(limit_string);
-       return count;
-}
-
 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
 {
        struct acpi_thermal *tz = seq->private;
@@ -958,15 +885,10 @@ static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
        if (!tz)
                goto end;
 
-       if (!tz->flags.cooling_mode) {
+       if (!tz->flags.cooling_mode)
                seq_puts(seq, "<setting not supported>\n");
-       }
-
-       if (tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL)
-               seq_printf(seq, "cooling mode:  critical\n");
        else
-               seq_printf(seq, "cooling mode:  %s\n",
-                          tz->cooling_mode ? "passive" : "active");
+               seq_puts(seq, "0 - Active; 1 - Passive\n");
 
       end:
        return 0;
@@ -1223,28 +1145,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
        result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
        if (!result)
                tz->flags.cooling_mode = 1;
-       else {
-               /* Oh,we have not _SCP method.
-                  Generally show cooling_mode by _ACx, _PSV,spec 12.2 */
-               tz->flags.cooling_mode = 0;
-               if (tz->trips.active[0].flags.valid
-                   && tz->trips.passive.flags.valid) {
-                       if (tz->trips.passive.temperature >
-                           tz->trips.active[0].temperature)
-                               tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
-                       else
-                               tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
-               } else if (!tz->trips.active[0].flags.valid
-                          && tz->trips.passive.flags.valid) {
-                       tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
-               } else if (tz->trips.active[0].flags.valid
-                          && !tz->trips.passive.flags.valid) {
-                       tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
-               } else {
-                       /* _ACx and _PSV are optional, but _CRT is required */
-                       tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL;
-               }
-       }
 
        /* Get default polling frequency [_TZP] (optional) */
        if (tzp)
index 55a764807499800b9f95c69c09c6ebaf9452a712..6e56d5f7c43a05a9e4c1f9d90d16e3cd2c0111a6 100644 (file)
@@ -107,7 +107,6 @@ acpi_status acpi_ut_create_caches(void)
        if (ACPI_FAILURE(status)) {
                return (status);
        }
-
 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
 
        /* Memory allocation lists */
index 870f6edeb5f28c6529889912c316459dcb1ae44e..285a0f5317604c21f088d273f611d53d9eff494d 100644 (file)
@@ -45,7 +45,6 @@
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utcache")
-
 #ifdef ACPI_USE_LOCAL_CACHE
 /*******************************************************************************
  *
@@ -64,7 +63,7 @@ ACPI_MODULE_NAME("utcache")
 acpi_status
 acpi_os_create_cache(char *cache_name,
                     u16 object_size,
-                    u16 max_depth, struct acpi_memory_list **return_cache)
+                    u16 max_depth, struct acpi_memory_list ** return_cache)
 {
        struct acpi_memory_list *cache;
 
index 84d529db0a6669234082d228ebc0f51f52a24f8f..4c1e00874dffab04407ddaf8975e7700d72dc5c5 100644 (file)
@@ -814,7 +814,9 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
                /*
                 * Create the object array
                 */
-               target_object->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.count + 1) * sizeof(void *));
+               target_object->package.elements =
+                   ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.
+                                         count + 1) * sizeof(void *));
                if (!target_object->package.elements) {
                        status = AE_NO_MEMORY;
                        goto error_exit;
index 61ad4f2daee2e8e4c8761e87de68eb5442b69601..c7e128e5369b2d5853acf17e8ff109dc2d1fe021 100644 (file)
@@ -45,7 +45,6 @@
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utdebug")
-
 #ifdef ACPI_DEBUG_OUTPUT
 static acpi_thread_id acpi_gbl_prev_thread_id;
 static char *acpi_gbl_fn_entry_str = "----Entry";
@@ -181,7 +180,8 @@ acpi_ut_debug_print(u32 requested_debug_level,
                if (ACPI_LV_THREADS & acpi_dbg_level) {
                        acpi_os_printf
                            ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
-                            (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
+                            (unsigned long)acpi_gbl_prev_thread_id,
+                            (unsigned long)thread_id);
                }
 
                acpi_gbl_prev_thread_id = thread_id;
index 673a0caa4073438f3f22af2dcad6a6e9f4bdc029..f777cebdc46dd85f8ec66b491096f9d2f20af1a3 100644 (file)
@@ -170,6 +170,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                        acpi_os_delete_mutex(object->mutex.os_mutex);
                        acpi_gbl_global_lock_mutex = NULL;
                } else {
+                       acpi_ex_unlink_mutex(object);
                        acpi_os_delete_mutex(object->mutex.os_mutex);
                }
                break;
index af33358a964b81f25ad0c404f61838ddbd1ba145..1621655d6e2b331e23bd9beaf56e59fab7298e8d 100644 (file)
@@ -55,12 +55,10 @@ ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
  * Static global variable initialization.
  *
  ******************************************************************************/
-
 /*
  * We want the debug switches statically initialized so they
  * are already set when the debugger is entered.
  */
-
 /* Debug switch - level and trace mask */
 u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
 
@@ -735,5 +733,5 @@ void acpi_ut_init_globals(void)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_dbg_level)
-ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
-ACPI_EXPORT_SYMBOL(acpi_gpe_count)
+    ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+    ACPI_EXPORT_SYMBOL(acpi_gpe_count)
index 50133fffe42045f7b1155e2edb8edd2ca6900529..2d19f71e9cfa44c95b1588a484f622d549340444 100644 (file)
@@ -802,9 +802,8 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
 
                valid_digits++;
 
-               if (sign_of0x
-                   && ((valid_digits > 16)
-                       || ((valid_digits > 8) && mode32))) {
+               if (sign_of0x && ((valid_digits > 16)
+                                 || ((valid_digits > 8) && mode32))) {
                        /*
                         * This is to_integer operation case.
                         * No any restrictions for string-to-integer conversion,
@@ -1049,6 +1048,7 @@ acpi_ut_exception(char *module_name,
        acpi_os_vprintf(format, args);
        acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
 }
+
 EXPORT_SYMBOL(acpi_ut_exception);
 
 void ACPI_INTERNAL_VAR_XFACE
index cbad2ef5987d1a52e9f89c3bd78a1c180447d33d..4820bc86d1f5d44ec1e90e07332e93a57974a0ce 100644 (file)
@@ -244,7 +244,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
                          "Thread %lX attempting to acquire Mutex [%s]\n",
-                         (unsigned long) this_thread_id,
+                         (unsigned long)this_thread_id,
                          acpi_ut_get_mutex_name(mutex_id)));
 
        status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
@@ -252,7 +252,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
        if (ACPI_SUCCESS(status)) {
                ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
                                  "Thread %lX acquired Mutex [%s]\n",
-                                 (unsigned long) this_thread_id,
+                                 (unsigned long)this_thread_id,
                                  acpi_ut_get_mutex_name(mutex_id)));
 
                acpi_gbl_mutex_info[mutex_id].use_count++;
@@ -260,7 +260,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
        } else {
                ACPI_EXCEPTION((AE_INFO, status,
                                "Thread %lX could not acquire Mutex [%X]",
-                               (unsigned long) this_thread_id, mutex_id));
+                               (unsigned long)this_thread_id, mutex_id));
        }
 
        return (status);
@@ -287,7 +287,7 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
        this_thread_id = acpi_os_get_thread_id();
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
                          "Thread %lX releasing Mutex [%s]\n",
-                         (unsigned long) this_thread_id,
+                         (unsigned long)this_thread_id,
                          acpi_ut_get_mutex_name(mutex_id)));
 
        if (mutex_id > ACPI_MAX_MUTEX) {
index e8fe1ba6cc243f705caf9c940d472b9846dc7e46..cbbd3315a1e22bbc9eacc32942ccaded198c14a7 100644 (file)
@@ -46,7 +46,6 @@
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utresrc")
-
 #if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
 /*
  * Strings used to decode resource descriptors.
index de3276f4f4683ec4aee9fb4a794ec9ace654636f..e9a57806cd34ecc32c1ab9d9881efabbeb96bfbc 100644 (file)
@@ -337,7 +337,6 @@ acpi_status acpi_terminate(void)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_terminate)
-
 #ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
@@ -470,7 +469,6 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
 #endif                         /*  ACPI_FUTURE_USAGE  */
-
 /*****************************************************************************
  *
  * FUNCTION:    acpi_purge_cached_objects
index 45dbdc14915fc428c9ed58bc0c4381c63e4ec76f..f031b87323308e3131898edecf3be5863e171070 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+       depends on HAS_IOMEM
 
 config ATA
        tristate "ATA device support"
@@ -435,7 +436,7 @@ config PATA_OPTIDMA
        help
          This option enables DMA/PIO support for the later OPTi
          controllers found on some old motherboards and in some
-         latops
+         laptops.
 
          If unsure, say N.
 
index 03a0acff6cfa495b916e56de667542116700a39b..cb3eab6e379da2ab9ef8dd6b17021c2d7abaf6ad 100644 (file)
@@ -489,8 +489,7 @@ static void taskfile_load_raw(struct ata_port *ap,
 
        /* convert gtf to tf */
        tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
-       tf.protocol = atadev->class == ATA_DEV_ATAPI ?
-               ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
+       tf.protocol = ATA_PROT_NODATA;
        tf.feature = gtf->tfa[0];       /* 0x1f1 */
        tf.nsect   = gtf->tfa[1];       /* 0x1f2 */
        tf.lbal    = gtf->tfa[2];       /* 0x1f3 */
index a7950885d18e8d5dfad224960ed7c9172d8385dd..4595d1f8cf60e2a3875863c8e6f08297d08164d1 100644 (file)
@@ -895,6 +895,7 @@ static u64 ata_read_native_max_address(struct ata_device *dev)
 /**
  *     ata_set_native_max_address_ext  -       LBA48 native max set
  *     @dev: Device to query
+ *     @new_sectors: new max sectors value to set for the device
  *
  *     Perform an LBA48 size set max upon the device in question. Return the
  *     actual LBA48 size or zero if the command fails.
@@ -932,6 +933,7 @@ static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sector
 /**
  *     ata_set_native_max_address      -       LBA28 native max set
  *     @dev: Device to query
+ *     @new_sectors: new max sectors value to set for the device
  *
  *     Perform an LBA28 size set max upon the device in question. Return the
  *     actual LBA28 size or zero if the command fails.
@@ -1316,7 +1318,7 @@ void ata_port_flush_task(struct ata_port *ap)
        spin_unlock_irqrestore(ap->lock, flags);
 
        DPRINTK("flush #1\n");
-       flush_workqueue(ata_wq);
+       cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */
 
        /*
         * At this point, if a task is running, it's guaranteed to see
@@ -1327,7 +1329,7 @@ void ata_port_flush_task(struct ata_port *ap)
                if (ata_msg_ctl(ap))
                        ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
                                        __FUNCTION__);
-               flush_workqueue(ata_wq);
+               cancel_work_sync(&ap->port_task.work);
        }
 
        spin_lock_irqsave(ap->lock, flags);
@@ -6475,9 +6477,9 @@ void ata_port_detach(struct ata_port *ap)
        /* Flush hotplug task.  The sequence is similar to
         * ata_port_flush_task().
         */
-       flush_workqueue(ata_aux_wq);
+       cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */
        cancel_delayed_work(&ap->hotplug_task);
-       flush_workqueue(ata_aux_wq);
+       cancel_work_sync(&ap->hotplug_task.work);
 
  skip_eh:
        /* remove the associated SCSI host */
index 75dc84797ff322eb9b9ffce033c2581dc5f5f4c2..11245e331f779f80b5896e1478a9e20093cbbcde 100644 (file)
@@ -357,6 +357,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),        /* I-O Data CFA */
        PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),        /* Mitsubishi CFA */
        PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+       PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
        PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),        /* SanDisk CFA */
        PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),        /* Toshiba */
        PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
index 27685ce63ceb27a92f8780c6c1c6aca48aa5745d..fb8c9e14b8d48d808740739df9772b044ade57ad 100644 (file)
@@ -375,7 +375,7 @@ static __init int qdi_init(void)
                                res = inb(port + 3);
                                if (res & 1) {
                                        /* Single channel mode */
-                                       if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04))
+                                       if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
                                                ct++;
                                } else {
                                        /* Dual channel mode */
index 5df354d573e8183c5174b8049bbf69b9860b7fb8..203f463ac39f8dc3ca0e4fd6ae595a564b6901ba 100644 (file)
@@ -1142,14 +1142,14 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        static int printed_version;
        unsigned int board_idx = (unsigned int) ent->driver_data;
        const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
-       struct device *dev = &pdev->dev;
+       struct ata_host *host;
        int rc;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev,
                           "version " DRV_VERSION "\n");
 
-       host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+       host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
        if (!host)
                return -ENOMEM;
 
index e2e795e5823671732947df073389dc54d814ed6b..a097595d4dc7a741d7bb01c8048085aced401abd 100644 (file)
@@ -257,6 +257,8 @@ static void nv_adma_port_stop(struct ata_port *ap);
 static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
 static int nv_adma_port_resume(struct ata_port *ap);
 #endif
+static void nv_adma_freeze(struct ata_port *ap);
+static void nv_adma_thaw(struct ata_port *ap);
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -444,8 +446,8 @@ static const struct ata_port_operations nv_adma_ops = {
        .bmdma_status           = ata_bmdma_status,
        .qc_prep                = nv_adma_qc_prep,
        .qc_issue               = nv_adma_qc_issue,
-       .freeze                 = nv_ck804_freeze,
-       .thaw                   = nv_ck804_thaw,
+       .freeze                 = nv_adma_freeze,
+       .thaw                   = nv_adma_thaw,
        .error_handler          = nv_adma_error_handler,
        .post_internal_cmd      = nv_adma_post_internal_cmd,
        .data_xfer              = ata_data_xfer,
@@ -815,8 +817,16 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                        u16 status;
                        u32 gen_ctl;
                        u32 notifier, notifier_error;
+                       
+                       /* if ADMA is disabled, use standard ata interrupt handler */
+                       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+                               u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
+                                       >> (NV_INT_PORT_SHIFT * i);
+                               handled += nv_host_intr(ap, irq_stat);
+                               continue;
+                       }
 
-                       /* if in ATA register mode, use standard ata interrupt handler */
+                       /* if in ATA register mode, check for standard interrupts */
                        if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
                                u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
                                        >> (NV_INT_PORT_SHIFT * i);
@@ -826,7 +836,6 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                            command is active, to prevent losing interrupts. */
                                        irq_stat |= NV_INT_DEV;
                                handled += nv_host_intr(ap, irq_stat);
-                               continue;
                        }
 
                        notifier = readl(mmio + NV_ADMA_NOTIFIER);
@@ -912,22 +921,77 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
        return IRQ_RETVAL(handled);
 }
 
+static void nv_adma_freeze(struct ata_port *ap)
+{
+       struct nv_adma_port_priv *pp = ap->private_data;
+       void __iomem *mmio = pp->ctl_block;
+       u16 tmp;
+
+       nv_ck804_freeze(ap);
+
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+               return;
+
+       /* clear any outstanding CK804 notifications */
+       writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+               ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
+
+       /* Disable interrupt */
+       tmp = readw(mmio + NV_ADMA_CTL);
+       writew( tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+               mmio + NV_ADMA_CTL);
+       readw( mmio + NV_ADMA_CTL );    /* flush posted write */
+}
+
+static void nv_adma_thaw(struct ata_port *ap)
+{
+       struct nv_adma_port_priv *pp = ap->private_data;
+       void __iomem *mmio = pp->ctl_block;
+       u16 tmp;
+
+       nv_ck804_thaw(ap);
+
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+               return;
+
+       /* Enable interrupt */
+       tmp = readw(mmio + NV_ADMA_CTL);
+       writew( tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+               mmio + NV_ADMA_CTL);
+       readw( mmio + NV_ADMA_CTL );    /* flush posted write */
+}
+
 static void nv_adma_irq_clear(struct ata_port *ap)
 {
        struct nv_adma_port_priv *pp = ap->private_data;
        void __iomem *mmio = pp->ctl_block;
-       u16 status = readw(mmio + NV_ADMA_STAT);
-       u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
-       u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
-       void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+       u32 notifier_clears[2];
 
-       /* clear ADMA status */
-       writew(status, mmio + NV_ADMA_STAT);
-       writel(notifier | notifier_error,
-              pp->notifier_clear_block);
+       if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) {
+               ata_bmdma_irq_clear(ap);
+               return;
+       }
+
+       /* clear any outstanding CK804 notifications */
+       writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+               ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
 
-       /** clear legacy status */
-       iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
+       /* clear ADMA status */
+       writew(0xffff, mmio + NV_ADMA_STAT);
+       
+       /* clear notifiers - note both ports need to be written with
+          something even though we are only clearing on one */
+       if (ap->port_no == 0) {
+               notifier_clears[0] = 0xFFFFFFFF;
+               notifier_clears[1] = 0;
+       } else {
+               notifier_clears[0] = 0;
+               notifier_clears[1] = 0xFFFFFFFF;
+       }
+       pp = ap->host->ports[0]->private_data;
+       writel(notifier_clears[0], pp->notifier_clear_block);
+       pp = ap->host->ports[1]->private_data;
+       writel(notifier_clears[1], pp->notifier_clear_block);
 }
 
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
index f56549b90aa63e3d4849dcef9e491dc519ebacfb..3a7d9b5332af93fd8daf709613a190aa8ab849b2 100644 (file)
@@ -45,7 +45,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME       "sata_promise"
-#define DRV_VERSION    "2.05"
+#define DRV_VERSION    "2.07"
 
 
 enum {
@@ -653,6 +653,8 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
        qc->err_mask |= ac_err_mask;
 
        pdc_reset_port(ap);
+
+       ata_port_abort(ap);
 }
 
 static inline unsigned int pdc_host_intr( struct ata_port *ap,
@@ -924,6 +926,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        struct ata_host *host;
        void __iomem *base;
        int n_ports, i, rc;
+       int is_sataii_tx4;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -962,10 +965,23 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
        }
        host->iomap = pcim_iomap_table(pdev);
 
-       for (i = 0; i < host->n_ports; i++)
+       is_sataii_tx4 = 0;
+       if ((pi->flags & (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) == (PDC_FLAG_GEN_II|PDC_FLAG_4_PORTS)) {
+               is_sataii_tx4 = 1;
+               dev_printk(KERN_INFO, &pdev->dev, "applying SATAII TX4 port numbering workaround\n");
+       }
+       for (i = 0; i < host->n_ports; i++) {
+               static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2};
+               int ata_nr;
+
+               ata_nr = i;
+               if (is_sataii_tx4)
+                       ata_nr = sataii_tx4_port_remap[i];
+
                pdc_ata_setup_port(host->ports[i],
-                                  base + 0x200 + i * 0x80,
-                                  base + 0x400 + i * 0x100);
+                                  base + 0x200 + ata_nr * 0x80,
+                                  base + 0x400 + ata_nr * 0x100);
+       }
 
        /* initialize adapter */
        pdc_host_init(host);
index 305ab7c68ca529743409f827b426f0c8c276017f..939c9246fdd1305b218e53712945b55974f901d0 100644 (file)
@@ -93,6 +93,10 @@ static struct pci_driver svia_pci_driver = {
        .name                   = DRV_NAME,
        .id_table               = svia_pci_tbl,
        .probe                  = svia_init_one,
+#ifdef CONFIG_PM
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = ata_pci_device_resume,
+#endif
        .remove                 = ata_pci_remove_one,
 };
 
@@ -112,6 +116,10 @@ static struct scsi_host_template svia_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
+#ifdef CONFIG_PM
+       .suspend                = ata_scsi_device_suspend,
+       .resume                 = ata_scsi_device_resume,
+#endif
 };
 
 static const struct ata_port_operations vt6420_sata_ops = {
index 0300e7f54cc4442e18d9d9966e5d8e7ddafe79bd..2e18a63ead36d735049d7297fedbc1c77b53d5db 100644 (file)
@@ -6,6 +6,7 @@
 #
 
 menu "Auxiliary Display support"
+       depends on PARPORT
 
 config KS0108
        tristate "KS0108 LCD Controller"
index e177c9533b6cc6654e2c8afd3567021672d0c51a..e1c0730a3b995d246ad965330854e768f746ab65 100644 (file)
@@ -101,19 +101,6 @@ static void add_dr(struct device *dev, struct devres_node *node)
        list_add_tail(&node->entry, &dev->devres_head);
 }
 
-/**
- * devres_alloc - Allocate device resource data
- * @release: Release function devres will be associated with
- * @size: Allocation size
- * @gfp: Allocation flags
- *
- * allocate devres of @size bytes.  The allocated area is zeroed, then
- * associated with @release.  The returned pointer can be passed to
- * other devres_*() functions.
- *
- * RETURNS:
- * Pointer to allocated devres on success, NULL on failure.
- */
 #ifdef CONFIG_DEBUG_DEVRES
 void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
                      const char *name)
@@ -128,6 +115,19 @@ void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
 }
 EXPORT_SYMBOL_GPL(__devres_alloc);
 #else
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * Allocate devres of @size bytes.  The allocated area is zeroed, then
+ * associated with @release.  The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
 void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
 {
        struct devres *dr;
@@ -416,7 +416,7 @@ static int release_nodes(struct device *dev, struct list_head *first,
 }
 
 /**
- * devres_release_all - Release all resources
+ * devres_release_all - Release all managed resources
  * @dev: Device to release resources for
  *
  * Release all resources associated with @dev.  This function is
@@ -600,7 +600,7 @@ static int devm_kzalloc_match(struct device *dev, void *res, void *data)
 }
 
 /**
- * devm_kzalloc - Managed kzalloc
+ * devm_kzalloc - Resource-managed kzalloc
  * @dev: Device to allocate memory for
  * @size: Allocation size
  * @gfp: Allocation gfp flags
@@ -628,7 +628,7 @@ void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
 EXPORT_SYMBOL_GPL(devm_kzalloc);
 
 /**
- * devm_kfree - Managed kfree
+ * devm_kfree - Resource-managed kfree
  * @dev: Device this memory belongs to
  * @p: Memory to free
  *
index eb84d9d44645c43b3205b31cdd50d9a1654b3b4c..869ff8c001460929a6b5721129b434c9cd50ef4f 100644 (file)
@@ -360,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
  *     This function creates a simple platform device that requires minimal
  *     resource and memory management. Canned release function freeing
  *     memory allocated for the device allows drivers using such devices
- *     to be unloaded iwithout waiting for the last reference to the device
+ *     to be unloaded without waiting for the last reference to the device
  *     to be dropped.
  *
  *     This interface is primarily intended for use with legacy drivers
index 067a9e8bc377f2cdfe670112bb493714f0faaeaf..8d8cdfec6529e683a194cd49547b81aa8c3680f6 100644 (file)
@@ -126,10 +126,13 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                rc = topology_add_dev(cpu);
                break;
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                topology_remove_dev(cpu);
                break;
        }
index 17ee97f3a99b59900bd6b89f373e871a3662c6ce..b4c8319138b29fbd762941ae74b4cbcc7d441cd3 100644 (file)
@@ -444,8 +444,6 @@ config CDROM_PKTCDVD_WCACHE
          this option is dangerous unless the CD-RW media is known good, as we
          don't do deferred write error handling yet.
 
-source "drivers/s390/block/Kconfig"
-
 config ATA_OVER_ETH
        tristate "ATA over Ethernet support"
        depends on NET
@@ -453,6 +451,8 @@ config ATA_OVER_ETH
        This driver provides Support for ATA over Ethernet block
        devices like the Coraid EtherDrive (R) Storage Blade.
 
+source "drivers/s390/block/Kconfig"
+
 endmenu
 
 endif
index af6d7274a7cc9a28c84d5bf7a4dfba1b6fdf0789..18cdd8c7762693d659bcc58c6e42b20e7b0e39dc 100644 (file)
@@ -243,17 +243,13 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
                transfer_result = lo_do_transfer(lo, WRITE, page, offset,
                                bvec->bv_page, bv_offs, size, IV);
                if (unlikely(transfer_result)) {
-                       char *kaddr;
-
                        /*
                         * The transfer failed, but we still write the data to
                         * keep prepare/commit calls balanced.
                         */
                        printk(KERN_ERR "loop: transfer error block %llu\n",
                               (unsigned long long)index);
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       memset(kaddr + offset, 0, size);
-                       kunmap_atomic(kaddr, KM_USER0);
+                       zero_user_page(page, offset, size, KM_USER0);
                }
                flush_dcache_page(page);
                ret = aops->commit_write(file, page, offset,
index 090796bef78f16374f8c94f2bf70e23e602deabd..069ae39a9cd9023eb62d9115f2885383c2df86ef 100644 (file)
@@ -366,20 +366,25 @@ static struct disk_attribute pid_attr = {
        .show = pid_show,
 };
 
-static void nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *lo)
 {
        struct request *req;
+       int ret;
 
        BUG_ON(lo->magic != LO_MAGIC);
 
        lo->pid = current->pid;
-       sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+       ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+       if (ret) {
+               printk(KERN_ERR "nbd: sysfs_create_file failed!");
+               return ret;
+       }
 
        while ((req = nbd_read_stat(lo)) != NULL)
                nbd_end_request(req);
 
        sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
-       return;
+       return 0;
 }
 
 static void nbd_clear_que(struct nbd_device *lo)
@@ -569,7 +574,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
        case NBD_DO_IT:
                if (!lo->file)
                        return -EINVAL;
-               nbd_do_it(lo);
+               error = nbd_do_it(lo);
+               if (error)
+                       return error;
                /* on return tidy up in case we have a signal */
                /* Forcibly shutdown the socket causing all listeners
                 * to error
index 43d4ebcb3b4410b6f1218e22df8cbee482744a39..a1512da3241069b7abc5f7395da5a098fdc57e0b 100644 (file)
@@ -151,7 +151,7 @@ static int ramdisk_commit_write(struct file *file, struct page *page,
 }
 
 /*
- * ->writepage to the the blockdev's mapping has to redirty the page so that the
+ * ->writepage to the blockdev's mapping has to redirty the page so that the
  * VM doesn't go and steal it.  We return AOP_WRITEPAGE_ACTIVATE so that the VM
  * won't try to (pointlessly) write the page again for a while.
  *
index 0f4203b499af65771ccb63bac79cae5ec2ad4f80..6055b9c0ac0f0b2f96380bebbb227b1fcaad055f 100644 (file)
@@ -307,7 +307,9 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 
        if (hu) {
                struct hci_dev *hdev = hu->hdev;
-               hci_uart_close(hdev);
+
+               if (hdev)
+                       hci_uart_close(hdev);
 
                if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
                        hu->proto->close(hu);
@@ -473,12 +475,18 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                        tty->low_latency = 1;
                } else
                        return -EBUSY;
+               break;
 
        case HCIUARTGETPROTO:
                if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
                        return hu->proto->id;
                return -EUNATCH;
 
+       case HCIUARTGETDEVICE:
+               if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+                       return hu->hdev->id;
+               return -EUNATCH;
+
        default:
                err = n_tty_ioctl(tty, file, cmd, arg);
                break;
index b250e6789dee68abd323392daa6a831337e20989..1097ce72393f2813bc82d140df1cca0495124b30 100644 (file)
@@ -28,8 +28,9 @@
 #endif
 
 /* Ioctls */
-#define HCIUARTSETPROTO        _IOW('U', 200, int)
-#define HCIUARTGETPROTO        _IOR('U', 201, int)
+#define HCIUARTSETPROTO                _IOW('U', 200, int)
+#define HCIUARTGETPROTO                _IOR('U', 201, int)
+#define HCIUARTGETDEVICE       _IOR('U', 202, int)
 
 /* UART protocols */
 #define HCI_UART_MAX_PROTO     4
index 1e32fb834eb82747abf650434cb550cb06404126..abcafac647382a7144519542f1ea2ec9b576b332 100644 (file)
@@ -6,6 +6,7 @@ menu "Character devices"
 
 config VT
        bool "Virtual terminal" if EMBEDDED
+       depends on !S390
        select INPUT
        default y if !VIOCONS
        ---help---
@@ -81,6 +82,7 @@ config VT_HW_CONSOLE_BINDING
 
 config SERIAL_NONSTANDARD
        bool "Non-standard serial port support"
+       depends on HAS_IOMEM
        ---help---
          Say Y here if you have any non-standard serial boards -- boards
          which aren't supported using the standard "dumb" serial driver.
@@ -631,7 +633,8 @@ config HVC_CONSOLE
 
 config HVC_ISERIES
        bool "iSeries Hypervisor Virtual Console support"
-       depends on PPC_ISERIES && !VIOCONS
+       depends on PPC_ISERIES
+       default y
        select HVC_DRIVER
        help
          iSeries machines support a hypervisor virtual console.
@@ -764,7 +767,7 @@ config NVRAM
 
 config RTC
        tristate "Enhanced Real Time Clock Support"
-       depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
+       depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -812,7 +815,7 @@ config SGI_IP27_RTC
 
 config GEN_RTC
        tristate "Generic /dev/rtc emulation"
-       depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV
+       depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -857,6 +860,7 @@ config COBALT_LCD
 
 config DTLK
        tristate "Double Talk PC internal speech card support"
+       depends on ISA
        help
          This driver is for the DoubleTalk PC, a speech synthesizer
          manufactured by RC Systems (<http://www.rcsys.com/>).  It is also
@@ -1042,7 +1046,7 @@ config HPET_MMAP
 
 config HANGCHECK_TIMER
        tristate "Hangcheck timer"
-       depends on X86 || IA64 || PPC64
+       depends on X86 || IA64 || PPC64 || S390
        help
          The hangcheck-timer module detects when the system has gone
          out to lunch past a certain margin.  It can reboot the system
@@ -1077,5 +1081,7 @@ config DEVPORT
        depends on ISA || PCI
        default y
 
+source "drivers/s390/char/Kconfig"
+
 endmenu
 
index 892db7096986aaa9e0af7f111cfb614982e84686..32ed19c9ec1c0b1bb36c4e0f51811ca3814377e7 100644 (file)
@@ -65,7 +65,7 @@ int drm_dma_setup(drm_device_t * dev)
  * \param dev DRM device.
  *
  * Free all pages associated with DMA buffers, the buffers and pages lists, and
- * finally the the drm_device::dma structure itself.
+ * finally the drm_device::dma structure itself.
  */
 void drm_dma_takedown(drm_device_t * dev)
 {
index 35540cfb43dd0fecf5d3b8fac30cbea2236796ff..b5c5b9fa84c3cd55bf7e0c8343fe6e6dc15771c3 100644 (file)
@@ -157,7 +157,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
  * \param address access address.
  * \return pointer to the page structure.
  *
- * Get the the mapping, find the real physical page to map, get the page, and
+ * Get the mapping, find the real physical page to map, get the page, and
  * return it.
  */
 static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
index a881f96c983efbb2fc5ecc8e1f34f152044c64db..ecda760ae8c0596af1c04837768c5917cfd3548f 100644 (file)
@@ -293,7 +293,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
 #       define R300_PVS_CNTL_1_PROGRAM_START_SHIFT   0
 #       define R300_PVS_CNTL_1_POS_END_SHIFT         10
 #       define R300_PVS_CNTL_1_PROGRAM_END_SHIFT     20
-/* Addresses are relative the the vertex program parameters area. */
+/* Addresses are relative to the vertex program parameters area. */
 #define R300_VAP_PVS_CNTL_2                 0x22D4
 #       define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
 #       define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT  16
index 49f914e7921636c96bd363c9b95fcc1fb307257d..9e1fc02967ffe7c73739dc5634d2e11f73998e50 100644 (file)
@@ -12,7 +12,7 @@
  *
  *     This driver allows use of the real time clock (built into
  *     nearly all computers) from user space. It exports the /dev/rtc
- *     interface supporting various ioctl() and also the /proc/dev/rtc
+ *     interface supporting various ioctl() and also the /proc/driver/rtc
  *     pseudo-file for status information.
  *
  *     The ioctls can be used to set the interrupt behaviour where
@@ -377,7 +377,7 @@ static int gen_rtc_release(struct inode *inode, struct file *file)
 #ifdef CONFIG_PROC_FS
 
 /*
- *     Info exported via "/proc/rtc".
+ *     Info exported via "/proc/driver/rtc".
  */
 
 static int gen_rtc_proc_output(char *buf)
index 5f3acd8e64b86d9e6ac8e685b61329322aada8c6..7cda04b335343aeb52e94b7007c38a3e3fae0c35 100644 (file)
@@ -91,3 +91,17 @@ config HW_RANDOM_OMAP
          module will be called omap-rng.
 
          If unsure, say Y.
+
+config HW_RANDOM_PASEMI
+       tristate "PA Semi HW Random Number Generator support"
+       depends on HW_RANDOM && PPC_PASEMI
+       default HW_RANDOM
+       ---help---
+         This driver provides kernel-side support for the Random Number
+         Generator hardware found on PA6T-1682M processor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pasemi-rng.
+
+         If unsure, say Y.
+
index c41fa19454e3910dfce0a1bbe4d7d33eddca77fe..c8b7300e2fb183f6ed6c6d1eb4f6ccfa358fb6bc 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
 obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
 obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
 obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644 (file)
index 0000000..fa6040b
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip rng
+ *
+ * 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.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+
+#define SDCRNG_CTL_REG                 0x00
+#define   SDCRNG_CTL_FVLD_M            0x0000f000
+#define   SDCRNG_CTL_FVLD_S            12
+#define   SDCRNG_CTL_KSZ               0x00000800
+#define   SDCRNG_CTL_RSRC_CRG          0x00000010
+#define   SDCRNG_CTL_RSRC_RRG          0x00000000
+#define   SDCRNG_CTL_CE                        0x00000004
+#define   SDCRNG_CTL_RE                        0x00000002
+#define   SDCRNG_CTL_DR                        0x00000001
+#define   SDCRNG_CTL_SELECT_RRG_RNG    (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
+#define   SDCRNG_CTL_SELECT_CRG_RNG    (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
+#define SDCRNG_VAL_REG                 0x20
+
+#define MODULE_NAME "pasemi_rng"
+
+static int pasemi_rng_data_present(struct hwrng *rng)
+{
+       void __iomem *rng_regs = (void __iomem *)rng->priv;
+
+       return (in_le32(rng_regs + SDCRNG_CTL_REG)
+               & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+}
+
+static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       void __iomem *rng_regs = (void __iomem *)rng->priv;
+       *data = in_le32(rng_regs + SDCRNG_VAL_REG);
+       return 4;
+}
+
+static int pasemi_rng_init(struct hwrng *rng)
+{
+       void __iomem *rng_regs = (void __iomem *)rng->priv;
+       u32 ctl;
+
+       ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
+       out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
+       out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
+
+       return 0;
+}
+
+static void pasemi_rng_cleanup(struct hwrng *rng)
+{
+       void __iomem *rng_regs = (void __iomem *)rng->priv;
+       u32 ctl;
+
+       ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
+       out_le32(rng_regs + SDCRNG_CTL_REG,
+                in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
+}
+
+static struct hwrng pasemi_rng = {
+       .name           = MODULE_NAME,
+       .init           = pasemi_rng_init,
+       .cleanup        = pasemi_rng_cleanup,
+       .data_present   = pasemi_rng_data_present,
+       .data_read      = pasemi_rng_data_read,
+};
+
+static int __devinit rng_probe(struct of_device *ofdev,
+                              const struct of_device_id *match)
+{
+       void __iomem *rng_regs;
+       struct device_node *rng_np = ofdev->node;
+       struct resource res;
+       int err = 0;
+
+       err = of_address_to_resource(rng_np, 0, &res);
+       if (err)
+               return -ENODEV;
+
+       rng_regs = ioremap(res.start, 0x100);
+
+       if (!rng_regs)
+               return -ENOMEM;
+
+       pasemi_rng.priv = (unsigned long)rng_regs;
+
+       printk(KERN_INFO "Registering PA Semi RNG\n");
+
+       err = hwrng_register(&pasemi_rng);
+
+       if (err)
+               iounmap(rng_regs);
+
+       return err;
+}
+
+static int __devexit rng_remove(struct of_device *dev)
+{
+       void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
+
+       hwrng_unregister(&pasemi_rng);
+       iounmap(rng_regs);
+
+       return 0;
+}
+
+static struct of_device_id rng_match[] = {
+       {
+               .compatible      = "1682m-rng",
+       },
+       {},
+};
+
+static struct of_platform_driver rng_driver = {
+       .name           = "pasemi-rng",
+       .match_table    = rng_match,
+       .probe          = rng_probe,
+       .remove         = rng_remove,
+};
+
+static int __init rng_init(void)
+{
+       return of_register_platform_driver(&rng_driver);
+}
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+       of_unregister_platform_driver(&rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
index a6dcb29181571af022ca6a642b0dba2eb3539ca9..b894f67fdf14194fcef98d13b24af52031f7b9a6 100644 (file)
@@ -3,6 +3,8 @@
 #
 
 menu "IPMI"
+       depends on HAS_IOMEM
+
 config IPMI_HANDLER
        tristate 'IPMI top-level message handler'
        help
index c09160383a5332c9635c4813215dabd9063bade8..6e55cfb9c65a3f03a12d0431040532cebdeb2e7c 100644 (file)
@@ -705,15 +705,13 @@ static int __init mmtimer_init(void)
        maxn++;
 
        /* Allocate list of node ptrs to mmtimer_t's */
-       timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+       timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
        if (timers == NULL) {
                printk(KERN_ERR "%s: failed to allocate memory for device\n",
                                MMTIMER_NAME);
                goto out3;
        }
 
-       memset(timers,0,(sizeof(mmtimer_t *)*maxn));
-
        /* Allocate mmtimer_t's for each online node */
        for_each_online_node(node) {
                timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
index 6ac3ca4c723c2c660c5d084b9c7834035767fbb5..b3d4ccc33a47e777d1a391ae9a85bde2f450051e 100644 (file)
@@ -1544,21 +1544,18 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol
 }
 
 struct tty_ldisc tty_ldisc_N_TTY = {
-       TTY_LDISC_MAGIC,        /* magic */
-       "n_tty",                /* name */
-       0,                      /* num */
-       0,                      /* flags */
-       n_tty_open,             /* open */
-       n_tty_close,            /* close */
-       n_tty_flush_buffer,     /* flush_buffer */
-       n_tty_chars_in_buffer,  /* chars_in_buffer */
-       read_chan,              /* read */
-       write_chan,             /* write */
-       n_tty_ioctl,            /* ioctl */
-       n_tty_set_termios,      /* set_termios */
-       normal_poll,            /* poll */
-       NULL,                   /* hangup */
-       n_tty_receive_buf,      /* receive_buf */
-       n_tty_write_wakeup      /* write_wakeup */
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_tty",
+       .open            = n_tty_open,
+       .close           = n_tty_close,
+       .flush_buffer    = n_tty_flush_buffer,
+       .chars_in_buffer = n_tty_chars_in_buffer,
+       .read            = read_chan,
+       .write           = write_chan,
+       .ioctl           = n_tty_ioctl,
+       .set_termios     = n_tty_set_termios,
+       .poll            = normal_poll,
+       .receive_buf     = n_tty_receive_buf,
+       .write_wakeup    = n_tty_write_wakeup
 };
 
index 27c1179ee52749a7062c597e71f506321eeb7287..f25facd97bb45a7af74e1268c45dec99f2cb04a0 100644 (file)
@@ -21,6 +21,7 @@ config SYNCLINK_CS
 config CARDMAN_4000
        tristate "Omnikey Cardman 4000 support"
        depends on PCMCIA
+       select BITREVERSE
        help
          Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
          reader.
index e91b43a014b09edf096ce80e8d40ec2f1fee4880..fee58e03dbe2bb30e5d8d715e9fab42be3b04e85 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
+#include <linux/bitrev.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -194,41 +195,17 @@ static inline unsigned char xinb(unsigned short port)
 }
 #endif
 
-#define        b_0000  15
-#define        b_0001  14
-#define        b_0010  13
-#define        b_0011  12
-#define        b_0100  11
-#define        b_0101  10
-#define        b_0110  9
-#define        b_0111  8
-#define        b_1000  7
-#define        b_1001  6
-#define        b_1010  5
-#define        b_1011  4
-#define        b_1100  3
-#define        b_1101  2
-#define        b_1110  1
-#define        b_1111  0
-
-static unsigned char irtab[16] = {
-       b_0000, b_1000, b_0100, b_1100,
-       b_0010, b_1010, b_0110, b_1110,
-       b_0001, b_1001, b_0101, b_1101,
-       b_0011, b_1011, b_0111, b_1111
-};
+static inline unsigned char invert_revert(unsigned char ch)
+{
+       return bitrev8(~ch);
+}
 
 static void str_invert_revert(unsigned char *b, int len)
 {
        int i;
 
        for (i = 0; i < len; i++)
-               b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
-}
-
-static unsigned char invert_revert(unsigned char ch)
-{
-       return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+               b[i] = invert_revert(b[i]);
 }
 
 #define        ATRLENCK(dev,pos) \
@@ -1114,7 +1091,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
        /*
         * wait for atr to become valid.
         * note: it is important to lock this code. if we dont, the monitor
-        * could be run between test_bit and the the call the sleep on the
+        * could be run between test_bit and the call to sleep on the
         * atr-queue.  if *then* the monitor detects atr valid, it will wake up
         * any process on the atr-queue, *but* since we have been interrupted,
         * we do not yet sleep on this queue. this would result in a missed
@@ -1881,8 +1858,11 @@ static int cm4000_probe(struct pcmcia_device *link)
        init_waitqueue_head(&dev->readq);
 
        ret = cm4000_config(link, i);
-       if (ret)
+       if (ret) {
+               dev_table[i] = NULL;
+               kfree(dev);
                return ret;
+       }
 
        class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
                            "cmm%d", i);
@@ -1907,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
        cm4000_release(link);
 
        dev_table[devno] = NULL;
-       kfree(dev);
+       kfree(dev);
 
        class_device_destroy(cmm_class, MKDEV(major, devno));
 
@@ -1956,12 +1936,14 @@ static int __init cmm_init(void)
        if (major < 0) {
                printk(KERN_WARNING MODULE_NAME
                        ": could not get major number\n");
+               class_destroy(cmm_class);
                return major;
        }
 
        rc = pcmcia_register_driver(&cm4000_driver);
        if (rc < 0) {
                unregister_chrdev(major, DEVICE_NAME);
+               class_destroy(cmm_class);
                return rc;
        }
 
index f2e4ec4fd407968b7322dac8664b5fdcb6fff9e0..af88181a17f477cd01e5a1f2644a9c8039619262 100644 (file)
@@ -636,8 +636,11 @@ static int reader_probe(struct pcmcia_device *link)
        setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
 
        ret = reader_config(link, i);
-       if (ret)
+       if (ret) {
+               dev_table[i] = NULL;
+               kfree(dev);
                return ret;
+       }
 
        class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
                            "cmx%d", i);
@@ -708,12 +711,14 @@ static int __init cm4040_init(void)
        if (major < 0) {
                printk(KERN_WARNING MODULE_NAME
                        ": could not get major number\n");
+               class_destroy(cmx_class);
                return major;
        }
 
        rc = pcmcia_register_driver(&reader_driver);
        if (rc < 0) {
                unregister_chrdev(major, DEVICE_NAME);
+               class_destroy(cmx_class);
                return rc;
        }
 
index 245f03195b7c6da9ce7f664e974664617b4baf33..8cc60b693460a2cbdbc9a1bca28c2a73724db162 100644 (file)
@@ -402,7 +402,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
                rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
                rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number  0x%x\n", rup);
 
-               if (Rup >= (unsigned short) MAX_RUP) {
+               if (Rup < (unsigned short) MAX_RUP) {
                        rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
                } else
                        rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
index 61a63da420c29ee02c1c9118c04a2454817245d9..a3fd7e7ba5a977556ccae27fcb4ca2bffa0c4eee 100644 (file)
@@ -1014,9 +1014,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*
         * Info->count is now 1; so it's safe to sleep now.
         */
-       info->session = process_session(current);
-       info->pgrp = process_group(current);
-
        if ((info->flags & ROCKET_INITIALIZED) == 0) {
                cp = &info->channel;
                sSetRxTrigger(cp, TRIG_1);
index 89b4d7b10d12584c630f17b95615b533a0182d04..b4c53dfa7951290f48be4b5e28e685d91a0b8558 100644 (file)
@@ -1158,8 +1158,6 @@ struct r_port {
        int xmit_head;
        int xmit_tail;
        int xmit_cnt;
-       int session;
-       int pgrp;
        int cd_status;
        int ignore_status_mask;
        int read_status_mask;
index 2a7736b5f2f73889643e8b797500eb1e2c34f31b..02b49bc000284028377f915dc39248ef71445d58 100644 (file)
@@ -1170,6 +1170,112 @@ static int ioctl(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
+/*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s get_params32\n", info->device_name));
+       tmp_params.mode            = (compat_ulong_t)info->params.mode;
+       tmp_params.loopback        = info->params.loopback;
+       tmp_params.flags           = info->params.flags;
+       tmp_params.encoding        = info->params.encoding;
+       tmp_params.clock_speed     = (compat_ulong_t)info->params.clock_speed;
+       tmp_params.addr_filter     = info->params.addr_filter;
+       tmp_params.crc_type        = info->params.crc_type;
+       tmp_params.preamble_length = info->params.preamble_length;
+       tmp_params.preamble        = info->params.preamble;
+       tmp_params.data_rate       = (compat_ulong_t)info->params.data_rate;
+       tmp_params.data_bits       = info->params.data_bits;
+       tmp_params.stop_bits       = info->params.stop_bits;
+       tmp_params.parity          = info->params.parity;
+       if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+       return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s set_params32\n", info->device_name));
+       if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+
+       spin_lock(&info->lock);
+       info->params.mode            = tmp_params.mode;
+       info->params.loopback        = tmp_params.loopback;
+       info->params.flags           = tmp_params.flags;
+       info->params.encoding        = tmp_params.encoding;
+       info->params.clock_speed     = tmp_params.clock_speed;
+       info->params.addr_filter     = tmp_params.addr_filter;
+       info->params.crc_type        = tmp_params.crc_type;
+       info->params.preamble_length = tmp_params.preamble_length;
+       info->params.preamble        = tmp_params.preamble;
+       info->params.data_rate       = tmp_params.data_rate;
+       info->params.data_bits       = tmp_params.data_bits;
+       info->params.stop_bits       = tmp_params.stop_bits;
+       info->params.parity          = tmp_params.parity;
+       spin_unlock(&info->lock);
+
+       change_params(info);
+
+       return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct slgt_info *info = tty->driver_data;
+       int rc = -ENOIOCTLCMD;
+
+       if (sanity_check(info, tty->name, "compat_ioctl"))
+               return -ENODEV;
+       DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+       switch (cmd) {
+
+       case MGSL_IOCSPARAMS32:
+               rc = set_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS32:
+               rc = get_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS:
+       case MGSL_IOCSPARAMS:
+       case MGSL_IOCGTXIDLE:
+       case MGSL_IOCGSTATS:
+       case MGSL_IOCWAITEVENT:
+       case MGSL_IOCGIF:
+       case MGSL_IOCSGPIO:
+       case MGSL_IOCGGPIO:
+       case MGSL_IOCWAITGPIO:
+       case TIOCGICOUNT:
+               rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+               break;
+
+       case MGSL_IOCSTXIDLE:
+       case MGSL_IOCTXENABLE:
+       case MGSL_IOCRXENABLE:
+       case MGSL_IOCTXABORT:
+       case TIOCMIWAIT:
+       case MGSL_IOCSIF:
+               rc = ioctl(tty, file, cmd, arg);
+               break;
+       }
+
+       DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+       return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
 /*
  * proc fs support
  */
@@ -3446,6 +3552,7 @@ static const struct tty_operations ops = {
        .chars_in_buffer = chars_in_buffer,
        .flush_buffer = flush_buffer,
        .ioctl = ioctl,
+       .compat_ioctl = slgt_compat_ioctl,
        .throttle = throttle,
        .unthrottle = unthrottle,
        .send_xchar = send_xchar,
index fe00c7dfb649bf054376aa30522cb6c1ed2098e7..dc4e1ff7f56fae2567a6deb3bb19a213a71c90c2 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "TPM devices"
+       depends on HAS_IOMEM
 
 config TCG_TPM
        tristate "TPM Hardware Support"
@@ -33,7 +34,7 @@ config TCG_NSC
        tristate "National Semiconductor TPM Interface"
        depends on TCG_TPM && PNPACPI
        ---help---
-         If you have a TPM security chip from National Semicondutor 
+         If you have a TPM security chip from National Semiconductor 
          say Yes and it will be accessible from within Linux.  To 
          compile this driver as a module, choose M here; the module 
          will be called tpm_nsc.
index 7710a6a77d971351cd053c2dc6dbb736383a2204..fe62c2170d01692fe3e05430aeba5374fc8c1742 100644 (file)
@@ -151,6 +151,12 @@ static int tty_open(struct inode *, struct file *);
 static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
              unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_tty(struct tty_struct *tty, int idx);
 static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
@@ -933,13 +939,6 @@ restart:
        if (ld == NULL)
                return -EINVAL;
 
-       /*
-        *      No more input please, we are switching. The new ldisc
-        *      will update this value in the ldisc open function
-        */
-
-       tty->receive_room = 0;
-
        /*
         *      Problem: What do we do if this blocks ?
         */
@@ -951,6 +950,13 @@ restart:
                return 0;
        }
 
+       /*
+        *      No more input please, we are switching. The new ldisc
+        *      will update this value in the ldisc open function
+        */
+
+       tty->receive_room = 0;
+
        o_ldisc = tty->ldisc;
        o_tty = tty->link;
 
@@ -1143,8 +1149,8 @@ static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
        return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
 }
 
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
-                            unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file * file,
+                             unsigned int cmd, unsigned long arg)
 {
        return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
@@ -1155,6 +1161,7 @@ static const struct file_operations tty_fops = {
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1167,6 +1174,7 @@ static const struct file_operations ptmx_fops = {
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = ptmx_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1179,6 +1187,7 @@ static const struct file_operations console_fops = {
        .write          = redirected_tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1189,7 +1198,8 @@ static const struct file_operations hung_up_tty_fops = {
        .read           = hung_up_tty_read,
        .write          = hung_up_tty_write,
        .poll           = hung_up_tty_poll,
-       .ioctl          = hung_up_tty_ioctl,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_ioctl,
        .release        = tty_release,
 };
 
@@ -1573,11 +1583,11 @@ void no_tty(void)
 
 
 /**
- *     stop_tty        -       propogate flow control
+ *     stop_tty        -       propagate flow control
  *     @tty: tty to stop
  *
  *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propogate the TIOCKPKT status. May be called
+ *     must also propagate the TIOCKPKT status. May be called
  *     on an already stopped device and will not re-call the driver
  *     method.
  *
@@ -1607,11 +1617,11 @@ void stop_tty(struct tty_struct *tty)
 EXPORT_SYMBOL(stop_tty);
 
 /**
- *     start_tty       -       propogate flow control
+ *     start_tty       -       propagate flow control
  *     @tty: tty to start
  *
  *     Start a tty that has been stopped if at all possible. Perform
- *     any neccessary wakeups and propogate the TIOCPKT status. If this
+ *     any neccessary wakeups and propagate the TIOCPKT status. If this
  *     is the tty was previous stopped and is being started then the
  *     driver start method is invoked and the line discipline woken.
  *
@@ -3357,6 +3367,32 @@ int tty_ioctl(struct inode * inode, struct file * file,
        return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file->private_data;
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->driver->compat_ioctl) {
+               retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->compat_ioctl)
+               retval = ld->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
 
 /*
  * This implements the "Secure Attention Key" ---  the idea is to
@@ -3689,6 +3725,7 @@ void tty_set_operations(struct tty_driver *driver,
        driver->write_room = op->write_room;
        driver->chars_in_buffer = op->chars_in_buffer;
        driver->ioctl = op->ioctl;
+       driver->compat_ioctl = op->compat_ioctl;
        driver->set_termios = op->set_termios;
        driver->throttle = op->throttle;
        driver->unthrottle = op->unthrottle;
index 60198a78974c614277b74fc44a48599a10fbc561..1cad32c62ed34493a220a703e0780400ad229f62 100644 (file)
@@ -2,9 +2,7 @@
 # Watchdog device configuration
 #
 
-menu "Watchdog Cards"
-
-config WATCHDOG
+menuconfig WATCHDOG
        bool "Watchdog Timer Support"
        ---help---
          If you say Y here (and to one of the following options) and create a
@@ -28,9 +26,10 @@ config WATCHDOG
 
          If unsure, say N.
 
+if WATCHDOG
+
 config WATCHDOG_NOWAYOUT
        bool "Disable watchdog shutdown on close"
-       depends on WATCHDOG
        help
          The default watchdog behaviour (which you get if you say N here) is
          to stop the timer if the process managing it closes the file
@@ -43,13 +42,11 @@ config WATCHDOG_NOWAYOUT
 #
 
 comment "Watchdog Device Drivers"
-       depends on WATCHDOG
 
 # Architecture Independent
 
 config SOFT_WATCHDOG
        tristate "Software watchdog"
-       depends on WATCHDOG
        help
          A software monitoring watchdog. This will fail to reboot your system
          from some situations that the hardware watchdog will recover
@@ -62,14 +59,14 @@ config SOFT_WATCHDOG
 
 config AT91RM9200_WATCHDOG
        tristate "AT91RM9200 watchdog"
-       depends on WATCHDOG && ARCH_AT91RM9200
+       depends on ARCH_AT91RM9200
        help
          Watchdog timer embedded into AT91RM9200 chips. This will reboot your
          system when the timeout is reached.
 
 config 21285_WATCHDOG
        tristate "DC21285 watchdog"
-       depends on WATCHDOG && FOOTBRIDGE
+       depends on FOOTBRIDGE
        help
          The Intel Footbridge chip contains a built-in watchdog circuit. Say Y
          here if you wish to use this. Alternatively say M to compile the
@@ -83,7 +80,7 @@ config 21285_WATCHDOG
 
 config 977_WATCHDOG
        tristate "NetWinder WB83C977 watchdog"
-       depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER
+       depends on FOOTBRIDGE && ARCH_NETWINDER
        help
          Say Y here to include support for the WB977 watchdog included in
          NetWinder machines. Alternatively say M to compile the driver as
@@ -93,7 +90,7 @@ config 977_WATCHDOG
 
 config IXP2000_WATCHDOG
        tristate "IXP2000 Watchdog"
-       depends on WATCHDOG && ARCH_IXP2000
+       depends on ARCH_IXP2000
        help
          Say Y here if to include support for the watchdog timer
          in the Intel IXP2000(2400, 2800, 2850) network processors.
@@ -104,7 +101,7 @@ config IXP2000_WATCHDOG
 
 config IXP4XX_WATCHDOG
        tristate "IXP4xx Watchdog"
-       depends on WATCHDOG && ARCH_IXP4XX
+       depends on ARCH_IXP4XX
        help
          Say Y here if to include support for the watchdog timer
          in the Intel IXP4xx network processors. This driver can
@@ -120,7 +117,7 @@ config IXP4XX_WATCHDOG
 
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
-       depends on WATCHDOG && ARCH_S3C2410
+       depends on ARCH_S3C2410
        help
          Watchdog timer block in the Samsung S3C2410 chips. This will
          reboot the system when the timer expires with the watchdog
@@ -136,7 +133,7 @@ config S3C2410_WATCHDOG
 
 config SA1100_WATCHDOG
        tristate "SA1100/PXA2xx watchdog"
-       depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA )
+       depends on ARCH_SA1100 || ARCH_PXA
        help
          Watchdog timer embedded into SA11x0 and PXA2xx chips. This will
          reboot your system when timeout is reached.
@@ -148,7 +145,7 @@ config SA1100_WATCHDOG
 
 config MPCORE_WATCHDOG
        tristate "MPcore watchdog"
-       depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS
+       depends on ARM_MPCORE_PLATFORM && LOCAL_TIMERS
        help
          Watchdog timer embedded into the MPcore system.
 
@@ -157,7 +154,7 @@ config MPCORE_WATCHDOG
 
 config EP93XX_WATCHDOG
        tristate "EP93xx Watchdog"
-       depends on WATCHDOG && ARCH_EP93XX
+       depends on ARCH_EP93XX
        help
          Say Y here if to include support for the watchdog timer
          embedded in the Cirrus Logic EP93xx family of devices.
@@ -167,14 +164,14 @@ config EP93XX_WATCHDOG
 
 config OMAP_WATCHDOG
        tristate "OMAP Watchdog"
-       depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
        help
          Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog.  Say 'Y' here to
          enable the OMAP1610/OMAP1710 watchdog timer.
 
 config PNX4008_WATCHDOG
        tristate "PNX4008 Watchdog"
-       depends on WATCHDOG && ARCH_PNX4008
+       depends on ARCH_PNX4008
        help
          Say Y here if to include support for the watchdog timer
          in the PNX4008 processor.
@@ -187,7 +184,7 @@ config PNX4008_WATCHDOG
 
 config ACQUIRE_WDT
        tristate "Acquire SBC Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on Single Board
          Computers produced by Acquire Inc (and others). This watchdog
@@ -201,7 +198,7 @@ config ACQUIRE_WDT
 
 config ADVANTECH_WDT
        tristate "Advantech SBC Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          If you are configuring a Linux kernel for the Advantech single-board
          computer, say `Y' here to support its built-in watchdog timer
@@ -210,7 +207,7 @@ config ADVANTECH_WDT
 
 config ALIM1535_WDT
        tristate "ALi M1535 PMU Watchdog Timer"
-       depends on WATCHDOG && X86 && PCI
+       depends on X86 && PCI
        ---help---
          This is the driver for the hardware watchdog on the ALi M1535 PMU.
 
@@ -221,7 +218,7 @@ config ALIM1535_WDT
 
 config ALIM7101_WDT
        tristate "ALi M7101 PMU Computer Watchdog"
-       depends on WATCHDOG && X86 && PCI
+       depends on X86 && PCI
        help
          This is the driver for the hardware watchdog on the ALi M7101 PMU
          as used in the x86 Cobalt servers.
@@ -233,7 +230,7 @@ config ALIM7101_WDT
 
 config SC520_WDT
        tristate "AMD Elan SC520 processor Watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          This is the driver for the hardware watchdog built in to the
          AMD "Elan" SC520 microcomputer commonly used in embedded systems.
@@ -246,7 +243,7 @@ config SC520_WDT
 
 config EUROTECH_WDT
        tristate "Eurotech CPU-1220/1410 Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          Enable support for the watchdog timer on the Eurotech CPU-1220 and
          CPU-1410 cards.  These are PC/104 SBCs. Spec sheets and product
@@ -254,7 +251,7 @@ config EUROTECH_WDT
 
 config IB700_WDT
        tristate "IB700 SBC Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the IB700 Single
          Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
@@ -270,7 +267,7 @@ config IB700_WDT
 
 config IBMASR
        tristate "IBM Automatic Server Restart"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          This is the driver for the IBM Automatic Server Restart watchdog
          timer built-in into some eServer xSeries machines.
@@ -280,7 +277,7 @@ config IBMASR
 
 config WAFER_WDT
        tristate "ICP Wafer 5823 Single Board Computer Watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          This is a driver for the hardware watchdog on the ICP Wafer 5823
          Single Board Computer (and probably other similar models).
@@ -290,7 +287,7 @@ config WAFER_WDT
 
 config I6300ESB_WDT
        tristate "Intel 6300ESB Timer/Watchdog"
-       depends on WATCHDOG && X86 && PCI
+       depends on X86 && PCI
        ---help---
          Hardware driver for the watchdog timer built into the Intel
          6300ESB controller hub.
@@ -298,31 +295,9 @@ config I6300ESB_WDT
          To compile this driver as a module, choose M here: the
          module will be called i6300esb.
 
-config I8XX_TCO
-       tristate "Intel i8xx TCO Timer/Watchdog"
-       depends on WATCHDOG && (X86 || IA64) && PCI
-       default n
-       ---help---
-         Hardware driver for the TCO timer built into the Intel 82801
-         I/O Controller Hub family.  The TCO (Total Cost of Ownership)
-         timer is a watchdog timer that will reboot the machine after
-         its second expiration. The expiration time can be configured
-         with the "heartbeat" parameter.
-
-         On some motherboards the driver may fail to reset the chipset's
-         NO_REBOOT flag which prevents the watchdog from rebooting the
-         machine. If this is the case you will get a kernel message like
-         "failed to reset NO_REBOOT flag, reboot disabled by hardware".
-
-         To compile this driver as a module, choose M here: the
-         module will be called i8xx_tco.
-
-         Note: This driver will be removed in the near future. Please
-         use the Intel TCO Timer/Watchdog driver.
-
 config ITCO_WDT
        tristate "Intel TCO Timer/Watchdog"
-       depends on WATCHDOG && (X86 || IA64) && PCI
+       depends on (X86 || IA64) && PCI
        ---help---
          Hardware driver for the intel TCO timer based watchdog devices.
          These drivers are included in the Intel 82801 I/O Controller
@@ -351,7 +326,7 @@ config ITCO_VENDOR_SUPPORT
 
 config SC1200_WDT
        tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          This is a driver for National Semiconductor PC87307/PC97307 hardware
          watchdog cards as found on the SC1200. This watchdog is mainly used
@@ -365,7 +340,7 @@ config SC1200_WDT
 
 config SCx200_WDT
        tristate "National Semiconductor SCx200 Watchdog"
-       depends on WATCHDOG && SCx200 && PCI
+       depends on SCx200 && PCI
        help
          Enable the built-in watchdog timer support on the National
          Semiconductor SCx200 processors.
@@ -374,7 +349,7 @@ config SCx200_WDT
 
 config PC87413_WDT
        tristate "NS PC87413 watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the PC87413 chipset
          This watchdog simply watches your kernel to make sure it doesn't
@@ -388,7 +363,7 @@ config PC87413_WDT
  
 config 60XX_WDT
        tristate "SBC-60XX Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        help
          This driver can be used with the watchdog timer found on some
          single board computers, namely the 6010 PII based computer.
@@ -402,7 +377,7 @@ config 60XX_WDT
 
 config SBC8360_WDT
        tristate "SBC8360 Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
 
          This is the driver for the hardware watchdog on the SBC8360 Single
@@ -415,7 +390,7 @@ config SBC8360_WDT
 
 config CPU5_WDT
        tristate "SMA CPU5 Watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          TBD.
          To compile this driver as a module, choose M here: the
@@ -423,7 +398,7 @@ config CPU5_WDT
 
 config SMSC37B787_WDT
        tristate "Winbond SMsC37B787 Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog component on the
          Winbond SMsC37B787 chipset as used on the NetRunner Mainboard
@@ -443,7 +418,7 @@ config SMSC37B787_WDT
 
 config W83627HF_WDT
        tristate "W83627HF Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the W83627HF chipset
          as used in Advantech PC-9578 and Tyan S2721-533 motherboards
@@ -458,7 +433,7 @@ config W83627HF_WDT
 
 config W83697HF_WDT
        tristate "W83697HF/W83697HG Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the W83697HF/HG
          chipset as used in Dedibox/VIA motherboards (and likely others).
@@ -473,7 +448,7 @@ config W83697HF_WDT
 
 config W83877F_WDT
        tristate "W83877F (EMACS) Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the W83877F chipset
          as used in EMACS PC-104 motherboards (and likely others).  This
@@ -488,7 +463,7 @@ config W83877F_WDT
 
 config W83977F_WDT
        tristate "W83977F (PCM-5335) Watchdog Timer"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the W83977F I/O chip
          as used in AAEON's PCM-5335 SBC (and likely others).  This
@@ -501,7 +476,7 @@ config W83977F_WDT
 
 config MACHZ_WDT
        tristate "ZF MachZ Watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          If you are using a ZF Micro MachZ processor, say Y here, otherwise
          N.  This is the driver for the watchdog timer built-in on that
@@ -514,7 +489,7 @@ config MACHZ_WDT
 
 config SBC_EPX_C3_WATCHDOG
        tristate "Winsystems SBC EPX-C3 watchdog"
-       depends on WATCHDOG && X86
+       depends on X86
        ---help---
          This is the driver for the built-in watchdog timer on the EPX-C3
          Single-board computer made by Winsystems, Inc.
@@ -537,19 +512,19 @@ config SBC_EPX_C3_WATCHDOG
 
 config 8xx_WDT
        tristate "MPC8xx Watchdog Timer"
-       depends on WATCHDOG && 8xx
+       depends on 8xx
 
 config 83xx_WDT
        tristate "MPC83xx Watchdog Timer"
-       depends on WATCHDOG && PPC_83xx
+       depends on PPC_83xx
 
 config MV64X60_WDT
        tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
-       depends on WATCHDOG && MV64X60
+       depends on MV64X60
 
 config BOOKE_WDT
        bool "PowerPC Book-E Watchdog Timer"
-       depends on WATCHDOG && (BOOKE || 4xx)
+       depends on BOOKE || 4xx
        ---help---
          Please see Documentation/watchdog/watchdog-api.txt for
          more information.
@@ -558,7 +533,7 @@ config BOOKE_WDT
 
 config WATCHDOG_RTAS
        tristate "RTAS watchdog"
-       depends on WATCHDOG && PPC_RTAS
+       depends on PPC_RTAS
        help
          This driver adds watchdog support for the RTAS watchdog.
 
@@ -569,16 +544,23 @@ config WATCHDOG_RTAS
 
 config INDYDOG
        tristate "Indy/I2 Hardware Watchdog"
-       depends on WATCHDOG && SGI_IP22
+       depends on SGI_IP22
        help
          Hardware driver for the Indy's/I2's watchdog. This is a
          watchdog timer that will reboot the machine after a 60 second
          timer expired and no process has written to /dev/watchdog during
          that time.
 
+config WDT_MTX1
+       tristate "MTX-1 Hardware Watchdog"
+       depends on MIPS_MTX1
+       help
+         Hardware driver for the MTX-1 boards. This is a watchdog timer that
+         will reboot the machine after a 100 seconds timer expired.
+
 config WDT_RM9K_GPI
        tristate "RM9000/GPI hardware watchdog"
-       depends on WATCHDOG && CPU_RM9000
+       depends on CPU_RM9000
        help
          Watchdog implementation using the GPI hardware found on
          PMC-Sierra RM9xxx CPUs.
@@ -590,7 +572,7 @@ config WDT_RM9K_GPI
 
 config ZVM_WATCHDOG
        tristate "z/VM Watchdog Timer"
-       depends on WATCHDOG && S390
+       depends on S390
        help
          IBM s/390 and zSeries machines running under z/VM 5.1 or later
          provide a virtual watchdog timer to their guest that cause a
@@ -604,7 +586,7 @@ config ZVM_WATCHDOG
 
 config SH_WDT
        tristate "SuperH Watchdog"
-       depends on WATCHDOG && SUPERH
+       depends on SUPERH
        help
          This driver adds watchdog support for the integrated watchdog in the
          SuperH processors. If you have one of these processors and wish
@@ -631,7 +613,7 @@ config SH_WDT_MMAP
 
 config WATCHDOG_CP1XXX
        tristate "CP1XXX Hardware Watchdog support"
-       depends on WATCHDOG && SPARC64 && PCI
+       depends on SPARC64 && PCI
        ---help---
          This is the driver for the hardware watchdog timers present on
          Sun Microsystems CompactPCI models CP1400 and CP1500.
@@ -645,7 +627,7 @@ config WATCHDOG_CP1XXX
 
 config WATCHDOG_RIO
        tristate "RIO Hardware Watchdog support"
-       depends on WATCHDOG && SPARC64 && PCI
+       depends on SPARC64 && PCI
        help
          Say Y here to support the hardware watchdog capability on Sun RIO
          machines.  The watchdog timeout period is normally one minute but
@@ -656,11 +638,11 @@ config WATCHDOG_RIO
 #
 
 comment "ISA-based Watchdog Cards"
-       depends on WATCHDOG && ISA
+       depends on ISA
 
 config PCWATCHDOG
        tristate "Berkshire Products ISA-PC Watchdog"
-       depends on WATCHDOG && ISA
+       depends on ISA
        ---help---
          This is the driver for the Berkshire Products ISA-PC Watchdog card.
          This card simply watches your kernel to make sure it doesn't freeze,
@@ -676,7 +658,7 @@ config PCWATCHDOG
 
 config MIXCOMWD
        tristate "Mixcom Watchdog"
-       depends on WATCHDOG && ISA
+       depends on ISA
        ---help---
          This is a driver for the Mixcom hardware watchdog cards.  This
          watchdog simply watches your kernel to make sure it doesn't freeze,
@@ -690,7 +672,7 @@ config MIXCOMWD
 
 config WDT
        tristate "WDT Watchdog timer"
-       depends on WATCHDOG && ISA
+       depends on ISA
        ---help---
          If you have a WDT500P or WDT501P watchdog board, say Y here,
          otherwise N. It is not possible to probe for this board, which means
@@ -720,11 +702,11 @@ config WDT_501
 #
 
 comment "PCI-based Watchdog Cards"
-       depends on WATCHDOG && PCI
+       depends on PCI
 
 config PCIPCWATCHDOG
        tristate "Berkshire Products PCI-PC Watchdog"
-       depends on WATCHDOG && PCI
+       depends on PCI
        ---help---
          This is the driver for the Berkshire Products PCI-PC Watchdog card.
          This card simply watches your kernel to make sure it doesn't freeze,
@@ -739,7 +721,7 @@ config PCIPCWATCHDOG
 
 config WDTPCI
        tristate "PCI-WDT500/501 Watchdog timer"
-       depends on WATCHDOG && PCI
+       depends on PCI
        ---help---
          If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
 
@@ -766,11 +748,11 @@ config WDT_501_PCI
 #
 
 comment "USB-based Watchdog Cards"
-       depends on WATCHDOG && USB
+       depends on USB
 
 config USBPCWATCHDOG
        tristate "Berkshire Products USB-PC Watchdog"
-       depends on WATCHDOG && USB
+       depends on USB
        ---help---
          This is the driver for the Berkshire Products USB-PC Watchdog card.
          This card simply watches your kernel to make sure it doesn't freeze,
@@ -783,4 +765,4 @@ config USBPCWATCHDOG
 
          Most people will say N.
 
-endmenu
+endif # WATCHDOG
index 2cd8ff8d10ac839b1e251c51225521dd89d76ef3..8bfc00cc7c2bc58a8b84ef9ac15ebb7c1df2dd60 100644 (file)
@@ -46,7 +46,6 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o
 obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
 obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -73,6 +72,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
 
 # MIPS Architecture
 obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
 obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
 
 # S390 Architecture
index bcd7e36ca0aa67b8f9e6e3c461d2b3f12912d0ab..d0d45a8b09f0a57c379028a4b4e62800c222e223 100644 (file)
@@ -220,17 +220,17 @@ static int __devinit cpu5wdt_init(void)
        if ( verbose )
                printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
 
-       if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
-               printk(KERN_ERR PFX "misc_register failed\n");
-               goto no_misc;
-       }
-
        if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
                printk(KERN_ERR PFX "request_region failed\n");
                err = -EBUSY;
                goto no_port;
        }
 
+       if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
+               printk(KERN_ERR PFX "misc_register failed\n");
+               goto no_misc;
+       }
+
        /* watchdog reboot? */
        val = inb(port + CPU5WDT_STATUS_REG);
        val = (val >> 2) & 1;
@@ -250,9 +250,9 @@ static int __devinit cpu5wdt_init(void)
 
        return 0;
 
-no_port:
-       misc_deregister(&cpu5wdt_misc);
 no_misc:
+       release_region(port, CPU5WDT_EXTENT);
+no_port:
        return err;
 }
 
index f70387f01b2b1880ffcbb26b9982d2ba68f55f48..b070324e27a6bf903cbe96410f123e24360932fd 100644 (file)
@@ -413,17 +413,10 @@ static int __init eurwdt_init(void)
 {
        int ret;
 
-       ret = misc_register(&eurwdt_miscdev);
-       if (ret) {
-               printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
-               WATCHDOG_MINOR);
-               goto out;
-       }
-
        ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
        if(ret) {
                printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
-               goto outmisc;
+               goto out;
        }
 
        if (!request_region(io, 2, "eurwdt")) {
@@ -438,6 +431,13 @@ static int __init eurwdt_init(void)
                goto outreg;
        }
 
+       ret = misc_register(&eurwdt_miscdev);
+       if (ret) {
+               printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
+               WATCHDOG_MINOR);
+               goto outreboot;
+       }
+
        eurwdt_unlock_chip();
 
        ret = 0;
@@ -448,14 +448,14 @@ static int __init eurwdt_init(void)
 out:
        return ret;
 
+outreboot:
+       unregister_reboot_notifier(&eurwdt_notifier);
+
 outreg:
        release_region(io, 2);
 
 outirq:
        free_irq(irq, NULL);
-
-outmisc:
-       misc_deregister(&eurwdt_miscdev);
        goto out;
 }
 
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
deleted file mode 100644 (file)
index a62ef48..0000000
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- *     i8xx_tco:       TCO timer driver for i8xx chipsets
- *
- *     (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- *                             http://www.kernelconcepts.de
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     Neither kernel concepts nor Nils Faerber admit liability nor provide
- *     warranty for any of this software. This material is provided
- *     "AS-IS" and at no charge.
- *
- *     (c) Copyright 2000      kernel concepts <nils@kernelconcepts.de>
- *                             developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *     TCO timer driver for i8xx chipsets
- *     based on softdog.c by Alan Cox <alan@redhat.com>
- *
- *     The TCO timer is implemented in the following I/O controller hubs:
- *     (See the intel documentation on http://developer.intel.com.)
- *     82801AA  (ICH)    : document number 290655-003, 290677-014,
- *     82801AB  (ICHO)   : document number 290655-003, 290677-014,
- *     82801BA  (ICH2)   : document number 290687-002, 298242-027,
- *     82801BAM (ICH2-M) : document number 290687-002, 298242-027,
- *     82801CA  (ICH3-S) : document number 290733-003, 290739-013,
- *     82801CAM (ICH3-M) : document number 290716-001, 290718-007,
- *     82801DB  (ICH4)   : document number 290744-001, 290745-020,
- *     82801DBM (ICH4-M) : document number 252337-001, 252663-005,
- *     82801E   (C-ICH)  : document number 273599-001, 273645-002,
- *     82801EB  (ICH5)   : document number 252516-001, 252517-003,
- *     82801ER  (ICH5R)  : document number 252516-001, 252517-003,
- *
- *  20000710 Nils Faerber
- *     Initial Version 0.01
- *  20000728 Nils Faerber
- *     0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
- *  20011214 Matt Domsch <Matt_Domsch@dell.com>
- *     0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- *          Didn't add timeout option as i810_margin already exists.
- *  20020224 Joel Becker, Wim Van Sebroeck
- *     0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
- *          add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
- *  20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
- *     0.05 Fix possible timer_alive race, add expect close support,
- *          clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
- *          WDIOC_SETOPTIONS), made i810tco_getdevice __init,
- *          removed boot_status, removed tco_timer_read,
- *          added support for 82801DB and 82801E chipset,
- *          added support for 82801EB and 8280ER chipset,
- *          general cleanup.
- *  20030921 Wim Van Sebroeck <wim@iguana.be>
- *     0.06 change i810_margin to heartbeat, use module_param,
- *          added notify system support, renamed module to i8xx_tco.
- *  20050128 Wim Van Sebroeck <wim@iguana.be>
- *     0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW
- *          chipsets. Also added support for the "undocumented" ICH7 chipset.
- *  20050807 Wim Van Sebroeck <wim@iguana.be>
- *     0.08 Make sure that the watchdog is only "armed" when started.
- *          (Kernel Bug 4251)
- *  20060416 Wim Van Sebroeck <wim@iguana.be>
- *     0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and
- *          ICH7 chipsets. (See Kernel Bug 6031 - other code will support these
- *          chipsets)
- */
-
-/*
- *     Includes, defines, variables, module parameters, ...
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "i8xx_tco.h"
-
-/* Module and version information */
-#define TCO_VERSION "0.09"
-#define TCO_MODULE_NAME "i8xx TCO timer"
-#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
-
-/* internal variables */
-static unsigned int ACPIBASE;
-static spinlock_t tco_lock;    /* Guards the hardware */
-static unsigned long timer_alive;
-static char tco_expect_close;
-static struct pci_dev *i8xx_tco_pci;
-
-/* module parameters */
-#define WATCHDOG_HEARTBEAT 30  /* 30 sec default heartbeat (2<heartbeat<39) */
-static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-/*
- * Some TCO specific functions
- */
-
-static inline unsigned char seconds_to_ticks(int seconds)
-{
-       /* the internal timer is stored as ticks which decrement
-        * every 0.6 seconds */
-       return (seconds * 10) / 6;
-}
-
-static int tco_timer_start (void)
-{
-       unsigned char val;
-
-       spin_lock(&tco_lock);
-
-       /* disable chipset's NO_REBOOT bit */
-       pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
-       val &= 0xfd;
-       pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
-
-       /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
-       val = inb (TCO1_CNT + 1);
-       val &= 0xf7;
-       outb (val, TCO1_CNT + 1);
-       val = inb (TCO1_CNT + 1);
-
-       spin_unlock(&tco_lock);
-
-       if (val & 0x08)
-               return -1;
-       return 0;
-}
-
-static int tco_timer_stop (void)
-{
-       unsigned char val, val1;
-
-       spin_lock(&tco_lock);
-       /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
-       val = inb (TCO1_CNT + 1);
-       val |= 0x08;
-       outb (val, TCO1_CNT + 1);
-       val = inb (TCO1_CNT + 1);
-
-       /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-       pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-       val1 |= 0x02;
-       pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
-       spin_unlock(&tco_lock);
-
-       if ((val & 0x08) == 0)
-               return -1;
-       return 0;
-}
-
-static int tco_timer_keepalive (void)
-{
-       spin_lock(&tco_lock);
-       /* Reload the timer by writing to the TCO Timer Reload register */
-       outb (0x01, TCO1_RLD);
-       spin_unlock(&tco_lock);
-       return 0;
-}
-
-static int tco_timer_set_heartbeat (int t)
-{
-       unsigned char val;
-       unsigned char tmrval;
-
-       tmrval = seconds_to_ticks(t);
-       /* from the specs: */
-       /* "Values of 0h-3h are ignored and should not be attempted" */
-       if (tmrval > 0x3f || tmrval < 0x04)
-               return -EINVAL;
-
-       /* Write new heartbeat to watchdog */
-       spin_lock(&tco_lock);
-       val = inb (TCO1_TMR);
-       val &= 0xc0;
-       val |= tmrval;
-       outb (val, TCO1_TMR);
-       val = inb (TCO1_TMR);
-       spin_unlock(&tco_lock);
-
-       if ((val & 0x3f) != tmrval)
-               return -EINVAL;
-
-       heartbeat = t;
-       return 0;
-}
-
-static int tco_timer_get_timeleft (int *time_left)
-{
-       unsigned char val;
-
-       spin_lock(&tco_lock);
-
-       /* read the TCO Timer */
-       val = inb (TCO1_RLD);
-       val &= 0x3f;
-
-       spin_unlock(&tco_lock);
-
-       *time_left = (int)((val * 6) / 10);
-
-       return 0;
-}
-
-/*
- *     /dev/watchdog handling
- */
-
-static int i8xx_tco_open (struct inode *inode, struct file *file)
-{
-       /* /dev/watchdog can only be opened once */
-       if (test_and_set_bit(0, &timer_alive))
-               return -EBUSY;
-
-       /*
-        *      Reload and activate timer
-        */
-       tco_timer_keepalive ();
-       tco_timer_start ();
-       return nonseekable_open(inode, file);
-}
-
-static int i8xx_tco_release (struct inode *inode, struct file *file)
-{
-       /*
-        *      Shut off the timer.
-        */
-       if (tco_expect_close == 42) {
-               tco_timer_stop ();
-       } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
-               tco_timer_keepalive ();
-       }
-       clear_bit(0, &timer_alive);
-       tco_expect_close = 0;
-       return 0;
-}
-
-static ssize_t i8xx_tco_write (struct file *file, const char __user *data,
-                             size_t len, loff_t * ppos)
-{
-       /* See if we got the magic character 'V' and reload the timer */
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       /* note: just in case someone wrote the magic character
-                        * five months ago... */
-                       tco_expect_close = 0;
-
-                       /* scan to see whether or not we got the magic character */
-                       for (i = 0; i != len; i++) {
-                               char c;
-                               if(get_user(c, data+i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       tco_expect_close = 42;
-                       }
-               }
-
-               /* someone wrote to us, we should reload the timer */
-               tco_timer_keepalive ();
-       }
-       return len;
-}
-
-static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       int new_options, retval = -EINVAL;
-       int new_heartbeat;
-       int time_left;
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       static struct watchdog_info ident = {
-               .options =              WDIOF_SETTIMEOUT |
-                                       WDIOF_KEEPALIVEPING |
-                                       WDIOF_MAGICCLOSE,
-               .firmware_version =     0,
-               .identity =             TCO_MODULE_NAME,
-       };
-
-       switch (cmd) {
-               case WDIOC_GETSUPPORT:
-                       return copy_to_user(argp, &ident,
-                               sizeof (ident)) ? -EFAULT : 0;
-
-               case WDIOC_GETSTATUS:
-               case WDIOC_GETBOOTSTATUS:
-                       return put_user (0, p);
-
-               case WDIOC_KEEPALIVE:
-                       tco_timer_keepalive ();
-                       return 0;
-
-               case WDIOC_SETOPTIONS:
-               {
-                       if (get_user (new_options, p))
-                               return -EFAULT;
-
-                       if (new_options & WDIOS_DISABLECARD) {
-                               tco_timer_stop ();
-                               retval = 0;
-                       }
-
-                       if (new_options & WDIOS_ENABLECARD) {
-                               tco_timer_keepalive ();
-                               tco_timer_start ();
-                               retval = 0;
-                       }
-
-                       return retval;
-               }
-
-               case WDIOC_SETTIMEOUT:
-               {
-                       if (get_user(new_heartbeat, p))
-                               return -EFAULT;
-
-                       if (tco_timer_set_heartbeat(new_heartbeat))
-                               return -EINVAL;
-
-                       tco_timer_keepalive ();
-                       /* Fall */
-               }
-
-               case WDIOC_GETTIMEOUT:
-                       return put_user(heartbeat, p);
-
-               case WDIOC_GETTIMELEFT:
-               {
-                       if (tco_timer_get_timeleft(&time_left))
-                               return -EINVAL;
-
-                       return put_user(time_left, p);
-               }
-
-               default:
-                       return -ENOTTY;
-       }
-}
-
-/*
- *     Notify system
- */
-
-static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
-{
-       if (code==SYS_DOWN || code==SYS_HALT) {
-               /* Turn the WDT off */
-               tco_timer_stop ();
-       }
-
-       return NOTIFY_DONE;
-}
-
-/*
- *     Kernel Interfaces
- */
-
-static const struct file_operations i8xx_tco_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .write =        i8xx_tco_write,
-       .ioctl =        i8xx_tco_ioctl,
-       .open =         i8xx_tco_open,
-       .release =      i8xx_tco_release,
-};
-
-static struct miscdevice i8xx_tco_miscdev = {
-       .minor =        WATCHDOG_MINOR,
-       .name =         "watchdog",
-       .fops =         &i8xx_tco_fops,
-};
-
-static struct notifier_block i8xx_tco_notifier = {
-       .notifier_call =        i8xx_tco_notify_sys,
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id i8xx_tco_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) },
-       { },                    /* End of list */
-};
-MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
-
-/*
- *     Init & exit routines
- */
-
-static unsigned char __init i8xx_tco_getdevice (void)
-{
-       struct pci_dev *dev = NULL;
-       u8 val1, val2;
-       u16 badr;
-       /*
-        *      Find the PCI device
-        */
-
-       for_each_pci_dev(dev)
-               if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
-                       i8xx_tco_pci = dev;
-                       break;
-               }
-
-       if (i8xx_tco_pci) {
-               /*
-                *      Find the ACPI base I/O address which is the base
-                *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
-                *      ACPIBASE is bits [15:7] from 0x40-0x43
-                */
-               pci_read_config_byte (i8xx_tco_pci, 0x40, &val1);
-               pci_read_config_byte (i8xx_tco_pci, 0x41, &val2);
-               badr = ((val2 << 1) | (val1 >> 7)) << 7;
-               ACPIBASE = badr;
-               /* Something's wrong here, ACPIBASE has to be set */
-               if (badr == 0x0001 || badr == 0x0000) {
-                       printk (KERN_ERR PFX "failed to get TCOBASE address\n");
-                       pci_dev_put(i8xx_tco_pci);
-                       return 0;
-               }
-
-               /* Check chipset's NO_REBOOT bit */
-               pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-               if (val1 & 0x02) {
-                       val1 &= 0xfd;
-                       pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-                       pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
-                       if (val1 & 0x02) {
-                               printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
-                               pci_dev_put(i8xx_tco_pci);
-                               return 0;       /* Cannot reset NO_REBOOT bit */
-                       }
-               }
-               /* Disable reboots untill the watchdog starts */
-               val1 |= 0x02;
-               pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
-               /* Set the TCO_EN bit in SMI_EN register */
-               if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
-                       printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                               SMI_EN + 1);
-                       pci_dev_put(i8xx_tco_pci);
-                       return 0;
-               }
-               val1 = inb (SMI_EN + 1);
-               val1 &= 0xdf;
-               outb (val1, SMI_EN + 1);
-               release_region (SMI_EN + 1, 1);
-               return 1;
-       }
-       return 0;
-}
-
-static int __init watchdog_init (void)
-{
-       int ret;
-
-       spin_lock_init(&tco_lock);
-
-       /* Check whether or not the hardware watchdog is there */
-       if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
-               return -ENODEV;
-
-       if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
-               printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
-                       TCOBASE);
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Clear out the (probably old) status */
-       outb (0, TCO1_STS);
-       outb (3, TCO2_STS);
-
-       /* Check that the heartbeat value is within it's range ; if not reset to the default */
-       if (tco_timer_set_heartbeat (heartbeat)) {
-               heartbeat = WATCHDOG_HEARTBEAT;
-               tco_timer_set_heartbeat (heartbeat);
-               printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
-                       heartbeat);
-       }
-
-       ret = register_reboot_notifier(&i8xx_tco_notifier);
-       if (ret != 0) {
-               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-                       ret);
-               goto unreg_region;
-       }
-
-       ret = misc_register(&i8xx_tco_miscdev);
-       if (ret != 0) {
-               printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-                       WATCHDOG_MINOR, ret);
-               goto unreg_notifier;
-       }
-
-       tco_timer_stop ();
-
-       printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
-               TCOBASE, heartbeat, nowayout);
-
-       return 0;
-
-unreg_notifier:
-       unregister_reboot_notifier(&i8xx_tco_notifier);
-unreg_region:
-       release_region (TCOBASE, 0x10);
-out:
-       pci_dev_put(i8xx_tco_pci);
-       return ret;
-}
-
-static void __exit watchdog_cleanup (void)
-{
-       /* Stop the timer before we leave */
-       if (!nowayout)
-               tco_timer_stop ();
-
-       /* Deregister */
-       misc_deregister (&i8xx_tco_miscdev);
-       unregister_reboot_notifier(&i8xx_tco_notifier);
-       release_region (TCOBASE, 0x10);
-
-       pci_dev_put(i8xx_tco_pci);
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
-
-MODULE_AUTHOR("Nils Faerber");
-MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h
deleted file mode 100644 (file)
index cc14eb8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *     i8xx_tco:       TCO timer driver for i8xx chipsets
- *
- *     (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- *                             http://www.kernelconcepts.de
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     Neither kernel concepts nor Nils Faerber admit liability nor provide
- *     warranty for any of this software. This material is provided
- *     "AS-IS" and at no charge.
- *
- *     (c) Copyright 2000      kernel concepts <nils@kernelconcepts.de>
- *                             developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *     TCO timer driver for i8xx chipsets
- *     based on softdog.c by Alan Cox <alan@redhat.com>
- *
- *     For history and the complete list of supported I/O Controller Hub's
- *     see i8xx_tco.c
- */
-
-
-/*
- * Some address definitions for the TCO
- */
-
-#define        TCOBASE         ACPIBASE + 0x60 /* TCO base address             */
-#define TCO1_RLD       TCOBASE + 0x00  /* TCO Timer Reload and Current Value */
-#define TCO1_TMR       TCOBASE + 0x01  /* TCO Timer Initial Value      */
-#define        TCO1_DAT_IN     TCOBASE + 0x02  /* TCO Data In Register         */
-#define        TCO1_DAT_OUT    TCOBASE + 0x03  /* TCO Data Out Register        */
-#define        TCO1_STS        TCOBASE + 0x04  /* TCO1 Status Register         */
-#define        TCO2_STS        TCOBASE + 0x06  /* TCO2 Status Register         */
-#define TCO1_CNT       TCOBASE + 0x08  /* TCO1 Control Register        */
-#define TCO2_CNT       TCOBASE + 0x0a  /* TCO2 Control Register        */
-
-#define        SMI_EN          ACPIBASE + 0x30 /* SMI Control and Enable Register */
index 8195f5023d853c23406f3cd0abe319b68e745d2c..94155f6136c2369a10135cc62b9aef1896755d66 100644 (file)
@@ -367,18 +367,17 @@ static int __init ibmasr_init(void)
        if (!asr_type)
                return -ENODEV;
 
+       rc = asr_get_base_address();
+       if (rc)
+               return rc;
+
        rc = misc_register(&asr_miscdev);
        if (rc < 0) {
+               release_region(asr_base, asr_length);
                printk(KERN_ERR PFX "failed to register misc device\n");
                return rc;
        }
 
-       rc = asr_get_base_address();
-       if (rc) {
-               misc_deregister(&asr_miscdev);
-               return rc;
-       }
-
        return 0;
 }
 
index 76c7fa37fa6c8abdb515bc93beedabbc057687b8..a0d27160c80e1f1e540c3cda4c80a0786dd03b5c 100644 (file)
@@ -440,13 +440,6 @@ static int __init zf_init(void)
        spin_lock_init(&zf_lock);
        spin_lock_init(&zf_port_lock);
 
-       ret = misc_register(&zf_miscdev);
-       if (ret){
-               printk(KERN_ERR "can't misc_register on minor=%d\n",
-                                                       WATCHDOG_MINOR);
-               goto out;
-       }
-
        if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
                printk(KERN_ERR "cannot reserve I/O ports at %d\n",
                                                        ZF_IOBASE);
@@ -461,16 +454,23 @@ static int __init zf_init(void)
                goto no_reboot;
        }
 
+       ret = misc_register(&zf_miscdev);
+       if (ret){
+               printk(KERN_ERR "can't misc_register on minor=%d\n",
+                                                       WATCHDOG_MINOR);
+               goto no_misc;
+       }
+
        zf_set_status(0);
        zf_set_control(0);
 
        return 0;
 
+no_misc:
+       unregister_reboot_notifier(&zf_notifier);
 no_reboot:
        release_region(ZF_IOBASE, 3);
 no_region:
-       misc_deregister(&zf_miscdev);
-out:
        return ret;
 }
 
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c
new file mode 100644 (file)
index 0000000..419ab44
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *      Driver for the MTX-1 Watchdog.
+ *
+ *      (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
+ *                              http://www.4g-systems.biz
+ *
+ *     (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
+ *
+ *      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.
+ *
+ *      Neither Michael Stickel nor 4G Systems admit liability nor provide
+ *      warranty for any of this software. This material is provided
+ *      "AS-IS" and at no charge.
+ *
+ *      (c) Copyright 2005    4G Systems <info@4g-systems.biz>
+ *
+ *      Release 0.01.
+ *      Author: Michael Stickel  michael.stickel@4g-systems.biz
+ *
+ *      Release 0.02.
+ *     Author: Florian Fainelli florian@openwrt.org
+ *             use the Linux watchdog/timer APIs
+ *
+ *      The Watchdog is configured to reset the MTX-1
+ *      if it is not triggered for 100 seconds.
+ *      It should not be triggered more often than 1.6 seconds.
+ *
+ *      A timer triggers the watchdog every 5 seconds, until
+ *      it is opened for the first time. After the first open
+ *      it MUST be triggered every 2..95 seconds.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/watchdog.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#define MTX1_WDT_INTERVAL      (5 * HZ)
+
+static int ticks = 100 * HZ;
+
+static struct {
+       struct completion stop;
+       volatile int running;
+       struct timer_list timer;
+       volatile int queue;
+       int default_ticks;
+       unsigned long inuse;
+} mtx1_wdt_device;
+
+static void mtx1_wdt_trigger(unsigned long unused)
+{
+       u32 tmp;
+
+       if (mtx1_wdt_device.running)
+               ticks--;
+       /*
+        * toggle GPIO2_15
+        */
+       tmp = au_readl(GPIO2_DIR);
+       tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
+       au_writel (tmp, GPIO2_DIR);
+
+       if (mtx1_wdt_device.queue && ticks)
+               mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
+       else {
+               complete(&mtx1_wdt_device.stop);
+       }
+}
+
+static void mtx1_wdt_reset(void)
+{
+       ticks = mtx1_wdt_device.default_ticks;
+}
+
+
+static void mtx1_wdt_start(void)
+{
+       if (!mtx1_wdt_device.queue) {
+               mtx1_wdt_device.queue = 1;
+               au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
+               mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
+       }
+       mtx1_wdt_device.running++;
+}
+
+static int mtx1_wdt_stop(void)
+{
+       if (mtx1_wdt_device.queue) {
+               mtx1_wdt_device.queue = 0;
+               au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
+       }
+
+       ticks = mtx1_wdt_device.default_ticks;
+
+       return 0;
+}
+
+/* Filesystem functions */
+
+static int mtx1_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &mtx1_wdt_device.inuse))
+               return -EBUSY;
+
+       return nonseekable_open(inode, file);
+}
+
+
+static int mtx1_wdt_release(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &mtx1_wdt_device.inuse);
+       return 0;
+}
+
+static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       unsigned int value;
+       static struct watchdog_info ident =
+       {
+               .options = WDIOF_CARDRESET,
+               .identity = "MTX-1 WDT",
+       };
+
+       switch(cmd) {
+               case WDIOC_KEEPALIVE:
+                       mtx1_wdt_reset();
+                       break;
+               case WDIOC_GETSTATUS:
+                       if ( copy_to_user(argp, &value, sizeof(int)) )
+                               return -EFAULT;
+                       break;
+               case WDIOC_GETSUPPORT:
+                       if ( copy_to_user(argp, &ident, sizeof(ident)) )
+                               return -EFAULT;
+                       break;
+               case WDIOC_SETOPTIONS:
+                       if ( copy_from_user(&value, argp, sizeof(int)) )
+                               return -EFAULT;
+                       switch(value) {
+                               case WDIOS_ENABLECARD:
+                                       mtx1_wdt_start();
+                                       break;
+                               case WDIOS_DISABLECARD:
+                                       return mtx1_wdt_stop();
+                               default:
+                                       return -EINVAL;
+                       }
+                       break;
+               default:
+                       return -ENOTTY;
+       }
+       return 0;
+}
+
+
+static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+       if (!count)
+               return -EIO;
+
+       mtx1_wdt_reset();
+       return count;
+}
+
+static struct file_operations mtx1_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .ioctl          = mtx1_wdt_ioctl,
+       .open           = mtx1_wdt_open,
+       .write          = mtx1_wdt_write,
+       .release        = mtx1_wdt_release
+};
+
+
+static struct miscdevice mtx1_wdt_misc = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &mtx1_wdt_fops
+};
+
+
+static int __init mtx1_wdt_init(void)
+{
+       int ret;
+
+       if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
+               printk(KERN_ERR " mtx-1_wdt : failed to register\n");
+               return ret;
+       }
+
+       init_completion(&mtx1_wdt_device.stop);
+       mtx1_wdt_device.queue = 0;
+
+       clear_bit(0, &mtx1_wdt_device.inuse);
+
+       setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
+
+       mtx1_wdt_device.default_ticks = ticks;
+
+       mtx1_wdt_start();
+
+       printk(KERN_INFO "MTX-1 Watchdog driver\n");
+
+       return 0;
+}
+
+static void __exit mtx1_wdt_exit(void)
+{
+       if (mtx1_wdt_device.queue) {
+               mtx1_wdt_device.queue = 0;
+               wait_for_completion(&mtx1_wdt_device.stop);
+       }
+       misc_deregister(&mtx1_wdt_misc);
+}
+
+module_init(mtx1_wdt_init);
+module_exit(mtx1_wdt_exit);
+
+MODULE_AUTHOR("Michael Stickel, Florian Fainelli");
+MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
+MODULE_LICENSE("GPL");
index 6e8b5705b5b78f94f77071217b01494c035f5b34..7b41434fac8cadbce0a893ef79e7d5a46207f989 100644 (file)
 #include <linux/jiffies.h>     /* For jiffies stuff */
 #include <linux/miscdevice.h>  /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
 #include <linux/watchdog.h>    /* For the watchdog specific items */
-#include <linux/notifier.h>    /* For notifier support */
-#include <linux/reboot.h>      /* For reboot_notifier stuff */
+#include <linux/reboot.h>      /* For kernel_power_off() */
 #include <linux/init.h>                /* For __init/__exit/... */
 #include <linux/fs.h>          /* For file operations */
+#include <linux/isa.h>         /* For isa devices */
 #include <linux/ioport.h>      /* For io-port access */
 #include <linux/spinlock.h>    /* For spin_lock/spin_unlock/... */
 
@@ -70,8 +70,8 @@
 #include <asm/io.h>            /* For inb/outb/... */
 
 /* Module and version information */
-#define WATCHDOG_VERSION "1.18"
-#define WATCHDOG_DATE "21 Jan 2007"
+#define WATCHDOG_VERSION "1.20"
+#define WATCHDOG_DATE "18 Feb 2007"
 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
 #define WATCHDOG_NAME "pcwd"
 #define PFX WATCHDOG_NAME ": "
 #define        PCWD_REVISION_A         1
 #define        PCWD_REVISION_C         2
 
+/*
+ * These are the auto-probe addresses available.
+ *
+ * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
+ * Revision A has an address range of 2 addresses, while Revision C has 4.
+ */
+#define PCWD_ISA_NR_CARDS      3
+static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
+
 /*
  * These are the defines that describe the control status bits for the
  * PCI-PC Watchdog card.
@@ -485,7 +494,7 @@ static int pcwd_get_status(int *status)
                if (control_status & WD_T110) {
                        *status |= WDIOF_OVERHEAT;
                        if (temp_panic) {
-                               printk (KERN_INFO PFX "Temperature overheat trip!\n");
+                               printk(KERN_INFO PFX "Temperature overheat trip!\n");
                                kernel_power_off();
                                /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
                        }
@@ -497,7 +506,7 @@ static int pcwd_get_status(int *status)
                if (control_status & WD_REVC_TTRP) {
                        *status |= WDIOF_OVERHEAT;
                        if (temp_panic) {
-                               printk (KERN_INFO PFX "Temperature overheat trip!\n");
+                               printk(KERN_INFO PFX "Temperature overheat trip!\n");
                                kernel_power_off();
                                /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
                        }
@@ -733,20 +742,6 @@ static int pcwd_temp_close(struct inode *inode, struct file *file)
        return 0;
 }
 
-/*
- *     Notify system
- */
-
-static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
-{
-       if (code==SYS_DOWN || code==SYS_HALT) {
-               /* Turn the WDT off */
-               pcwd_stop();
-       }
-
-       return NOTIFY_DONE;
-}
-
 /*
  *     Kernel Interfaces
  */
@@ -780,10 +775,6 @@ static struct miscdevice temp_miscdev = {
        .fops =         &pcwd_temp_fops,
 };
 
-static struct notifier_block pcwd_notifier = {
-       .notifier_call =        pcwd_notify_sys,
-};
-
 /*
  *     Init & exit routines
  */
@@ -803,10 +794,67 @@ static inline int get_revision(void)
        return r;
 }
 
-static int __devinit pcwatchdog_init(int base_addr)
+/*
+ *  The ISA cards have a heartbeat bit in one of the registers, which
+ *  register is card dependent.  The heartbeat bit is monitored, and if
+ *  found, is considered proof that a Berkshire card has been found.
+ *  The initial rate is once per second at board start up, then twice
+ *  per second for normal operation.
+ */
+static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
+{
+       int base_addr=pcwd_ioports[id];
+       int port0, last_port0;  /* Reg 0, in case it's REV A */
+       int port1, last_port1;  /* Register 1 for REV C cards */
+       int i;
+       int retval;
+
+       if (debug >= DEBUG)
+               printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
+                       id);
+
+       if (!request_region (base_addr, 4, "PCWD")) {
+               printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+               return 0;
+       }
+
+       retval = 0;
+
+       port0 = inb_p(base_addr);       /* For REV A boards */
+       port1 = inb_p(base_addr + 1);   /* For REV C boards */
+       if (port0 != 0xff || port1 != 0xff) {
+               /* Not an 'ff' from a floating bus, so must be a card! */
+               for (i = 0; i < 4; ++i) {
+
+                       msleep(500);
+
+                       last_port0 = port0;
+                       last_port1 = port1;
+
+                       port0 = inb_p(base_addr);
+                       port1 = inb_p(base_addr + 1);
+
+                       /* Has either hearbeat bit changed?  */
+                       if ((port0 ^ last_port0) & WD_HRTBT ||
+                           (port1 ^ last_port1) & WD_REVC_HRBT) {
+                               retval = 1;
+                               break;
+                       }
+               }
+       }
+       release_region (base_addr, 4);
+
+       return retval;
+}
+
+static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
 {
        int ret;
 
+       if (debug >= DEBUG)
+               printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
+                       id);
+
        cards_found++;
        if (cards_found == 1)
                printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
@@ -816,11 +864,13 @@ static int __devinit pcwatchdog_init(int base_addr)
                return -ENODEV;
        }
 
-       if (base_addr == 0x0000) {
+       if (pcwd_ioports[id] == 0x0000) {
                printk(KERN_ERR PFX "No I/O-Address for card detected\n");
                return -ENODEV;
        }
-       pcwd_private.io_addr = base_addr;
+       pcwd_private.io_addr = pcwd_ioports[id];
+
+       spin_lock_init(&pcwd_private.io_lock);
 
        /* Check card's revision */
        pcwd_private.revision = get_revision();
@@ -828,8 +878,8 @@ static int __devinit pcwatchdog_init(int base_addr)
        if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
                printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
                        pcwd_private.io_addr);
-               pcwd_private.io_addr = 0x0000;
-               return -EIO;
+               ret=-EIO;
+               goto error_request_region;
        }
 
        /* Initial variables */
@@ -865,24 +915,12 @@ static int __devinit pcwatchdog_init(int base_addr)
                        WATCHDOG_HEARTBEAT);
        }
 
-       ret = register_reboot_notifier(&pcwd_notifier);
-       if (ret) {
-               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-                       ret);
-               release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
-               pcwd_private.io_addr = 0x0000;
-               return ret;
-       }
-
        if (pcwd_private.supports_temp) {
                ret = misc_register(&temp_miscdev);
                if (ret) {
                        printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
                                TEMP_MINOR, ret);
-                       unregister_reboot_notifier(&pcwd_notifier);
-                       release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
-                       pcwd_private.io_addr = 0x0000;
-                       return ret;
+                       goto error_misc_register_temp;
                }
        }
 
@@ -890,22 +928,34 @@ static int __devinit pcwatchdog_init(int base_addr)
        if (ret) {
                printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
                        WATCHDOG_MINOR, ret);
-               if (pcwd_private.supports_temp)
-                       misc_deregister(&temp_miscdev);
-               unregister_reboot_notifier(&pcwd_notifier);
-               release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
-               pcwd_private.io_addr = 0x0000;
-               return ret;
+               goto error_misc_register_watchdog;
        }
 
        printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
+
+error_misc_register_watchdog:
+       if (pcwd_private.supports_temp)
+               misc_deregister(&temp_miscdev);
+error_misc_register_temp:
+       release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
+error_request_region:
+       pcwd_private.io_addr = 0x0000;
+       cards_found--;
+       return ret;
 }
 
-static void __devexit pcwatchdog_exit(void)
+static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
 {
+       if (debug >= DEBUG)
+               printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
+                       id);
+
+       if (!pcwd_private.io_addr)
+               return 1;
+
        /*  Disable the board  */
        if (!nowayout)
                pcwd_stop();
@@ -914,102 +964,50 @@ static void __devexit pcwatchdog_exit(void)
        misc_deregister(&pcwd_miscdev);
        if (pcwd_private.supports_temp)
                misc_deregister(&temp_miscdev);
-       unregister_reboot_notifier(&pcwd_notifier);
        release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
        pcwd_private.io_addr = 0x0000;
        cards_found--;
+
+       return 0;
 }
 
-/*
- *  The ISA cards have a heartbeat bit in one of the registers, which
- *  register is card dependent.  The heartbeat bit is monitored, and if
- *  found, is considered proof that a Berkshire card has been found.
- *  The initial rate is once per second at board start up, then twice
- *  per second for normal operation.
- */
-static int __init pcwd_checkcard(int base_addr)
+static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
 {
-       int port0, last_port0;  /* Reg 0, in case it's REV A */
-       int port1, last_port1;  /* Register 1 for REV C cards */
-       int i;
-       int retval;
-
-       if (!request_region (base_addr, 4, "PCWD")) {
-               printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
-               return 0;
-       }
-
-       retval = 0;
-
-       port0 = inb_p(base_addr);       /* For REV A boards */
-       port1 = inb_p(base_addr + 1);   /* For REV C boards */
-       if (port0 != 0xff || port1 != 0xff) {
-               /* Not an 'ff' from a floating bus, so must be a card! */
-               for (i = 0; i < 4; ++i) {
-
-                       msleep(500);
-
-                       last_port0 = port0;
-                       last_port1 = port1;
-
-                       port0 = inb_p(base_addr);
-                       port1 = inb_p(base_addr + 1);
-
-                       /* Has either hearbeat bit changed?  */
-                       if ((port0 ^ last_port0) & WD_HRTBT ||
-                           (port1 ^ last_port1) & WD_REVC_HRBT) {
-                               retval = 1;
-                               break;
-                       }
-               }
-       }
-       release_region (base_addr, 4);
+       if (debug >= DEBUG)
+               printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
+                       id);
 
-       return retval;
+       pcwd_stop();
 }
 
-/*
- * These are the auto-probe addresses available.
- *
- * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
- * Revision A has an address range of 2 addresses, while Revision C has 4.
- */
-static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
+static struct isa_driver pcwd_isa_driver = {
+       .match          = pcwd_isa_match,
+       .probe          = pcwd_isa_probe,
+       .remove         = __devexit_p(pcwd_isa_remove),
+       .shutdown       = pcwd_isa_shutdown,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = WATCHDOG_NAME,
+       },
+};
 
 static int __init pcwd_init_module(void)
 {
-       int i, found = 0;
-
-       spin_lock_init(&pcwd_private.io_lock);
-
-       for (i = 0; pcwd_ioports[i] != 0; i++) {
-               if (pcwd_checkcard(pcwd_ioports[i])) {
-                       if (!(pcwatchdog_init(pcwd_ioports[i])))
-                               found++;
-               }
-       }
-
-       if (!found) {
-               printk (KERN_INFO PFX "No card detected, or port not available\n");
-               return -ENODEV;
-       }
-
-       return 0;
+       return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS);
 }
 
 static void __exit pcwd_cleanup_module(void)
 {
-       if (pcwd_private.io_addr)
-               pcwatchdog_exit();
-
+       isa_unregister_driver(&pcwd_isa_driver);
        printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
 }
 
 module_init(pcwd_init_module);
 module_exit(pcwd_cleanup_module);
 
-MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
+MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, Wim Van Sebroeck <wim@iguana.be>");
 MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
+MODULE_VERSION(WATCHDOG_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS_MISCDEV(TEMP_MINOR);
index 31037f9c9ffe8b7a2b41e79f512bfeb3eadf202b..1e7a6719d5baabc42527ae38d24849d85616f78b 100644 (file)
@@ -146,7 +146,7 @@ struct usb_pcwd_private {
        atomic_t                cmd_received;           /* true if we received a report after a command */
 
        int                     exists;                 /* Wether or not the device exists */
-       struct semaphore        sem;                    /* locks this structure */
+       struct mutex            mtx;                    /* locks this structure */
 };
 static struct usb_pcwd_private *usb_pcwd_device;
 
@@ -635,7 +635,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
 
        usb_pcwd_device = usb_pcwd;
 
-       init_MUTEX (&usb_pcwd->sem);
+       mutex_init(&usb_pcwd->mtx);
        usb_pcwd->udev = udev;
        usb_pcwd->interface = interface;
        usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
@@ -763,7 +763,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
        usb_pcwd = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
 
-       down (&usb_pcwd->sem);
+       mutex_lock(&usb_pcwd->mtx);
 
        /* Stop the timer before we leave */
        if (!nowayout)
@@ -777,7 +777,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
        misc_deregister(&usb_pcwd_temperature_miscdev);
        unregister_reboot_notifier(&usb_pcwd_notifier);
 
-       up (&usb_pcwd->sem);
+       mutex_unlock(&usb_pcwd->mtx);
 
        /* Delete the USB PCWD device */
        usb_pcwd_delete(usb_pcwd);
index dff6cb5dc9a7a0700c6dc09f2110736505701b06..20fa29ca7404655ade0c16d8d04bcef29cfd7d13 100644 (file)
@@ -379,14 +379,14 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        DBG("probe: mapped wdt_base=%p\n", wdt_base);
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res == NULL) {
+       wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (wdt_irq == NULL) {
                printk(KERN_INFO PFX "failed to get irq resource\n");
                ret = -ENOENT;
                goto err_map;
        }
 
-       ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
+       ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
        if (ret != 0) {
                printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
                goto err_map;
index 67ae42685e752f94d5feb19c7c4684467fa296af..285d85289532da3aadab9c7b0f1e73373fee1d84 100644 (file)
@@ -333,18 +333,17 @@ static int __init sbc8360_init(void)
        int res;
        unsigned long int mseconds = 60000;
 
-       spin_lock_init(&sbc8360_lock);
-       res = misc_register(&sbc8360_miscdev);
-       if (res) {
-               printk(KERN_ERR PFX "failed to register misc device\n");
-               goto out_nomisc;
+       if (timeout < 0 || timeout > 63) {
+               printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+               res = -EINVAL;
+               goto out;
        }
 
        if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
                printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
                       SBC8360_ENABLE);
                res = -EIO;
-               goto out_noenablereg;
+               goto out;
        }
        if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
                printk(KERN_ERR PFX
@@ -360,10 +359,11 @@ static int __init sbc8360_init(void)
                goto out_noreboot;
        }
 
-       if (timeout < 0 || timeout > 63) {
-               printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
-               res = -EINVAL;
-               goto out_noreboot;
+       spin_lock_init(&sbc8360_lock);
+       res = misc_register(&sbc8360_miscdev);
+       if (res) {
+               printk(KERN_ERR PFX "failed to register misc device\n");
+               goto out_nomisc;
        }
 
        wd_margin = wd_times[timeout][0];
@@ -383,13 +383,13 @@ static int __init sbc8360_init(void)
 
        return 0;
 
+      out_nomisc:
+       unregister_reboot_notifier(&sbc8360_notifier);
       out_noreboot:
-       release_region(SBC8360_ENABLE, 1);
        release_region(SBC8360_BASETIME, 1);
-      out_noenablereg:
       out_nobasetimereg:
-       misc_deregister(&sbc8360_miscdev);
-      out_nomisc:
+       release_region(SBC8360_ENABLE, 1);
+      out:
        return res;
 }
 
index 337ee42c90dd757644913cd5a42330f3c20330cc..b46e7f47d70594f0410b8de7ece91df56eaf8ea2 100644 (file)
@@ -1,5 +1,8 @@
 /*
- *     w83627hf WDT driver
+ *     w83627hf/thf WDT driver
+ *
+ *     (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ *             added support for W83627THF.
  *
  *     (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
  *
@@ -39,7 +42,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define WATCHDOG_NAME "w83627hf WDT"
+#define WATCHDOG_NAME "w83627hf/thf WDT"
 #define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 
@@ -50,7 +53,7 @@ static spinlock_t io_lock;
 /* You must set this - there is no sane way to probe for this board. */
 static int wdt_io = 0x2E;
 module_param(wdt_io, int, 0);
-MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)");
+MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
 
 static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
 module_param(timeout, int, 0);
@@ -71,9 +74,19 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
 static void
 w83627hf_select_wd_register(void)
 {
+       unsigned char c;
        outb_p(0x87, WDT_EFER); /* Enter extended function mode */
        outb_p(0x87, WDT_EFER); /* Again according to manual */
 
+       outb(0x20, WDT_EFER);   /* check chip version   */
+       c = inb(WDT_EFDR);
+       if (c == 0x82) {        /* W83627THF            */
+               outb_p(0x2b, WDT_EFER); /* select GPIO3 */
+               c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
+               outb_p(0x2b, WDT_EFER);
+               outb_p(c, WDT_EFDR);    /* set GPIO3 to WDT0 */
+       }
+
        outb_p(0x07, WDT_EFER); /* point to logical device number reg */
        outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
        outb_p(0x30, WDT_EFER); /* select CR30 */
@@ -311,7 +324,7 @@ wdt_init(void)
 
        spin_lock_init(&io_lock);
 
-       printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
+       printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n");
 
        if (wdt_set_heartbeat(timeout)) {
                wdt_set_heartbeat(WATCHDOG_TIMEOUT);
@@ -367,5 +380,5 @@ module_exit(wdt_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
-MODULE_DESCRIPTION("w83627hf WDT driver");
+MODULE_DESCRIPTION("w83627hf/thf WDT driver");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 893dbaf386fbf41e755239f9538332fbdbd73681..eb37fba9b7efccf163badc70450aee38873b60d3 100644 (file)
@@ -1685,9 +1685,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
        if (sys_dev) {
                switch (action) {
                case CPU_ONLINE:
+               case CPU_ONLINE_FROZEN:
                        cpufreq_add_dev(sys_dev);
                        break;
                case CPU_DOWN_PREPARE:
+               case CPU_DOWN_PREPARE_FROZEN:
                        if (unlikely(lock_policy_rwsem_write(cpu)))
                                BUG();
 
@@ -1699,6 +1701,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                        __cpufreq_remove_dev(sys_dev);
                        break;
                case CPU_DOWN_FAILED:
+               case CPU_DOWN_FAILED_FROZEN:
                        cpufreq_add_dev(sys_dev);
                        break;
                }
index d1c7cac9316cc4e7729f8445c9ba8ebc07d858b7..d2f0cbd8b8f3f294ef7a1f834d52bbfcb2bf02c3 100644 (file)
@@ -313,9 +313,11 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cpufreq_update_policy(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                cpufreq_stats_free_table(cpu);
                break;
        }
index f21fe66c9eefd4590adc9ee2b9dc63bd6ead0493..e678a33ea672658d64f891b8c021b6f5c2da7255 100644 (file)
@@ -51,9 +51,31 @@ config CRYPTO_DEV_GEODE
        default m
        help
          Say 'Y' here to use the AMD Geode LX processor on-board AES
-         engine for the CryptoAPI AES alogrithm.
+         engine for the CryptoAPI AES algorithm.
 
          To compile this driver as a module, choose M here: the module
          will be called geode-aes.
 
+config ZCRYPT
+       tristate "Support for PCI-attached cryptographic adapters"
+       depends on S390
+       select ZCRYPT_MONOLITHIC if ZCRYPT="y"
+       default "m"
+       help
+         Select this option if you want to use a PCI-attached cryptographic
+         adapter like:
+         + PCI Cryptographic Accelerator (PCICA)
+         + PCI Cryptographic Coprocessor (PCICC)
+         + PCI-X Cryptographic Coprocessor (PCIXCC)
+         + Crypto Express2 Coprocessor (CEX2C)
+         + Crypto Express2 Accelerator (CEX2A)
+
+config ZCRYPT_MONOLITHIC
+       bool "Monolithic zcrypt module"
+       depends on ZCRYPT="m"
+       help
+         Select this option if you want to have a single module z90crypt.ko
+         that contains all parts of the crypto device driver (ap bus,
+         request router and all the card drivers).
+
 endmenu
index 30d021d1a07c8670687e05abb3238772b7aec181..72be6c63edfc01767d503eaa57ba9c40e0219498 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "DMA Engine support"
+       depends on !S390
 
 config DMA_ENGINE
        bool "Support for DMA engines"
index 4f0898400c6de212334d63be47f79c3bb07b3806..807c402df0495801fc98a53f2a1ff824cc595c4b 100644 (file)
@@ -7,6 +7,7 @@
 #
 
 menu 'EDAC - error detection and reporting (RAS) (EXPERIMENTAL)'
+       depends on HAS_IOMEM
 
 config EDAC
        tristate "EDAC core system error reporting (EXPERIMENTAL)"
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
new file mode 100644 (file)
index 0000000..5932c72
--- /dev/null
@@ -0,0 +1,61 @@
+# -*- shell-script -*-
+
+comment "An alternative FireWire stack is available with EXPERIMENTAL=y"
+       depends on EXPERIMENTAL=n
+
+config FIREWIRE
+       tristate "IEEE 1394 (FireWire) support (JUJU alternative stack, experimental)"
+       depends on EXPERIMENTAL
+       select CRC_ITU_T
+       help
+         IEEE 1394 describes a high performance serial bus, which is also
+         known as FireWire(tm) or i.Link(tm) and is used for connecting all
+         sorts of devices (most notably digital video cameras) to your
+         computer.
+
+         If you have FireWire hardware and want to use it, say Y here.  This
+         is the core support only, you will also need to select a driver for
+         your IEEE 1394 adapter.
+
+         To compile this driver as a module, say M here: the module will be
+         called fw-core.
+
+         This is the "JUJU" FireWire stack, an alternative implementation
+         designed for robustness and simplicity.  You can build either this
+         stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
+         or both.
+
+config FIREWIRE_OHCI
+       tristate "Support for OHCI FireWire host controllers"
+       depends on PCI && FIREWIRE
+       help
+         Enable this driver if you have a FireWire controller based
+         on the OHCI specification.  For all practical purposes, this
+         is the only chipset in use, so say Y here.
+
+         To compile this driver as a module, say M here:  The module will be
+         called fw-ohci.
+
+         If you also build ohci1394 of the classic IEEE 1394 driver stack,
+         blacklist either ohci1394 or fw-ohci to let hotplug load the desired
+         driver.
+
+config FIREWIRE_SBP2
+       tristate "Support for storage devices (SBP-2 protocol driver)"
+       depends on FIREWIRE && SCSI
+       help
+         This option enables you to use SBP-2 devices connected to a
+         FireWire bus.  SBP-2 devices include storage devices like
+         harddisks and DVD drives, also some other FireWire devices
+         like scanners.
+
+         To compile this driver as a module, say M here:  The module will be
+         called fw-sbp2.
+
+         You should also enable support for disks, CD-ROMs, etc. in the SCSI
+         configuration section.
+
+         If you also build sbp2 of the classic IEEE 1394 driver stack,
+         blacklist either sbp2 or fw-sbp2 to let hotplug load the desired
+         driver.
+
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
new file mode 100644 (file)
index 0000000..fc7d59d
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the Linux IEEE 1394 implementation
+#
+
+fw-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \
+       fw-device.o fw-cdev.o
+
+obj-$(CONFIG_FIREWIRE) += fw-core.o
+obj-$(CONFIG_FIREWIRE_OHCI) += fw-ohci.o
+obj-$(CONFIG_FIREWIRE_SBP2) += fw-sbp2.o
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
new file mode 100644 (file)
index 0000000..636151a
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2005-2007  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/crc-itu-t.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+int fw_compute_block_crc(u32 *block)
+{
+       __be32 be32_block[256];
+       int i, length;
+
+       length = (*block >> 16) & 0xff;
+       for (i = 0; i < length; i++)
+               be32_block[i] = cpu_to_be32(block[i + 1]);
+       *block |= crc_itu_t(0, (u8 *) be32_block, length * 4);
+
+       return length;
+}
+
+static DEFINE_MUTEX(card_mutex);
+static LIST_HEAD(card_list);
+
+static LIST_HEAD(descriptor_list);
+static int descriptor_count;
+
+#define BIB_CRC(v)             ((v) <<  0)
+#define BIB_CRC_LENGTH(v)      ((v) << 16)
+#define BIB_INFO_LENGTH(v)     ((v) << 24)
+
+#define BIB_LINK_SPEED(v)      ((v) <<  0)
+#define BIB_GENERATION(v)      ((v) <<  4)
+#define BIB_MAX_ROM(v)         ((v) <<  8)
+#define BIB_MAX_RECEIVE(v)     ((v) << 12)
+#define BIB_CYC_CLK_ACC(v)     ((v) << 16)
+#define BIB_PMC                        ((1) << 27)
+#define BIB_BMC                        ((1) << 28)
+#define BIB_ISC                        ((1) << 29)
+#define BIB_CMC                        ((1) << 30)
+#define BIB_IMC                        ((1) << 31)
+
+static u32 *
+generate_config_rom(struct fw_card *card, size_t *config_rom_length)
+{
+       struct fw_descriptor *desc;
+       static u32 config_rom[256];
+       int i, j, length;
+
+       /*
+        * Initialize contents of config rom buffer.  On the OHCI
+        * controller, block reads to the config rom accesses the host
+        * memory, but quadlet read access the hardware bus info block
+        * registers.  That's just crack, but it means we should make
+        * sure the contents of bus info block in host memory mathces
+        * the version stored in the OHCI registers.
+        */
+
+       memset(config_rom, 0, sizeof(config_rom));
+       config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0);
+       config_rom[1] = 0x31333934;
+
+       config_rom[2] =
+               BIB_LINK_SPEED(card->link_speed) |
+               BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
+               BIB_MAX_ROM(2) |
+               BIB_MAX_RECEIVE(card->max_receive) |
+               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC;
+       config_rom[3] = card->guid >> 32;
+       config_rom[4] = card->guid;
+
+       /* Generate root directory. */
+       i = 5;
+       config_rom[i++] = 0;
+       config_rom[i++] = 0x0c0083c0; /* node capabilities */
+       j = i + descriptor_count;
+
+       /* Generate root directory entries for descriptors. */
+       list_for_each_entry (desc, &descriptor_list, link) {
+               if (desc->immediate > 0)
+                       config_rom[i++] = desc->immediate;
+               config_rom[i] = desc->key | (j - i);
+               i++;
+               j += desc->length;
+       }
+
+       /* Update root directory length. */
+       config_rom[5] = (i - 5 - 1) << 16;
+
+       /* End of root directory, now copy in descriptors. */
+       list_for_each_entry (desc, &descriptor_list, link) {
+               memcpy(&config_rom[i], desc->data, desc->length * 4);
+               i += desc->length;
+       }
+
+       /* Calculate CRCs for all blocks in the config rom.  This
+        * assumes that CRC length and info length are identical for
+        * the bus info block, which is always the case for this
+        * implementation. */
+       for (i = 0; i < j; i += length + 1)
+               length = fw_compute_block_crc(config_rom + i);
+
+       *config_rom_length = j;
+
+       return config_rom;
+}
+
+static void
+update_config_roms(void)
+{
+       struct fw_card *card;
+       u32 *config_rom;
+       size_t length;
+
+       list_for_each_entry (card, &card_list, link) {
+               config_rom = generate_config_rom(card, &length);
+               card->driver->set_config_rom(card, config_rom, length);
+       }
+}
+
+int
+fw_core_add_descriptor(struct fw_descriptor *desc)
+{
+       size_t i;
+
+       /*
+        * Check descriptor is valid; the length of all blocks in the
+        * descriptor has to add up to exactly the length of the
+        * block.
+        */
+       i = 0;
+       while (i < desc->length)
+               i += (desc->data[i] >> 16) + 1;
+
+       if (i != desc->length)
+               return -EINVAL;
+
+       mutex_lock(&card_mutex);
+
+       list_add_tail(&desc->link, &descriptor_list);
+       descriptor_count++;
+       if (desc->immediate > 0)
+               descriptor_count++;
+       update_config_roms();
+
+       mutex_unlock(&card_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(fw_core_add_descriptor);
+
+void
+fw_core_remove_descriptor(struct fw_descriptor *desc)
+{
+       mutex_lock(&card_mutex);
+
+       list_del(&desc->link);
+       descriptor_count--;
+       if (desc->immediate > 0)
+               descriptor_count--;
+       update_config_roms();
+
+       mutex_unlock(&card_mutex);
+}
+EXPORT_SYMBOL(fw_core_remove_descriptor);
+
+static const char gap_count_table[] = {
+       63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
+};
+
+struct bm_data {
+       struct fw_transaction t;
+       struct {
+               __be32 arg;
+               __be32 data;
+       } lock;
+       u32 old;
+       int rcode;
+       struct completion done;
+};
+
+static void
+complete_bm_lock(struct fw_card *card, int rcode,
+                void *payload, size_t length, void *data)
+{
+       struct bm_data *bmd = data;
+
+       if (rcode == RCODE_COMPLETE)
+               bmd->old = be32_to_cpu(*(__be32 *) payload);
+       bmd->rcode = rcode;
+       complete(&bmd->done);
+}
+
+static void
+fw_card_bm_work(struct work_struct *work)
+{
+       struct fw_card *card = container_of(work, struct fw_card, work.work);
+       struct fw_device *root;
+       struct bm_data bmd;
+       unsigned long flags;
+       int root_id, new_root_id, irm_id, gap_count, generation, grace;
+       int do_reset = 0;
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       generation = card->generation;
+       root = card->root_node->data;
+       root_id = card->root_node->node_id;
+       grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
+
+       if (card->bm_generation + 1 == generation ||
+           (card->bm_generation != generation && grace)) {
+               /*
+                * This first step is to figure out who is IRM and
+                * then try to become bus manager.  If the IRM is not
+                * well defined (e.g. does not have an active link
+                * layer or does not responds to our lock request, we
+                * will have to do a little vigilante bus management.
+                * In that case, we do a goto into the gap count logic
+                * so that when we do the reset, we still optimize the
+                * gap count.  That could well save a reset in the
+                * next generation.
+                */
+
+               irm_id = card->irm_node->node_id;
+               if (!card->irm_node->link_on) {
+                       new_root_id = card->local_node->node_id;
+                       fw_notify("IRM has link off, making local node (%02x) root.\n",
+                                 new_root_id);
+                       goto pick_me;
+               }
+
+               bmd.lock.arg = cpu_to_be32(0x3f);
+               bmd.lock.data = cpu_to_be32(card->local_node->node_id);
+
+               spin_unlock_irqrestore(&card->lock, flags);
+
+               init_completion(&bmd.done);
+               fw_send_request(card, &bmd.t, TCODE_LOCK_COMPARE_SWAP,
+                               irm_id, generation,
+                               SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
+                               &bmd.lock, sizeof(bmd.lock),
+                               complete_bm_lock, &bmd);
+               wait_for_completion(&bmd.done);
+
+               if (bmd.rcode == RCODE_GENERATION) {
+                       /*
+                        * Another bus reset happened. Just return,
+                        * the BM work has been rescheduled.
+                        */
+                       return;
+               }
+
+               if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f)
+                       /* Somebody else is BM, let them do the work. */
+                       return;
+
+               spin_lock_irqsave(&card->lock, flags);
+               if (bmd.rcode != RCODE_COMPLETE) {
+                       /*
+                        * The lock request failed, maybe the IRM
+                        * isn't really IRM capable after all. Let's
+                        * do a bus reset and pick the local node as
+                        * root, and thus, IRM.
+                        */
+                       new_root_id = card->local_node->node_id;
+                       fw_notify("BM lock failed, making local node (%02x) root.\n",
+                                 new_root_id);
+                       goto pick_me;
+               }
+       } else if (card->bm_generation != generation) {
+               /*
+                * OK, we weren't BM in the last generation, and it's
+                * less than 100ms since last bus reset. Reschedule
+                * this task 100ms from now.
+                */
+               spin_unlock_irqrestore(&card->lock, flags);
+               schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10));
+               return;
+       }
+
+       /*
+        * We're bus manager for this generation, so next step is to
+        * make sure we have an active cycle master and do gap count
+        * optimization.
+        */
+       card->bm_generation = generation;
+
+       if (root == NULL) {
+               /*
+                * Either link_on is false, or we failed to read the
+                * config rom.  In either case, pick another root.
+                */
+               new_root_id = card->local_node->node_id;
+       } else if (atomic_read(&root->state) != FW_DEVICE_RUNNING) {
+               /*
+                * If we haven't probed this device yet, bail out now
+                * and let's try again once that's done.
+                */
+               spin_unlock_irqrestore(&card->lock, flags);
+               return;
+       } else if (root->config_rom[2] & BIB_CMC) {
+               /*
+                * FIXME: I suppose we should set the cmstr bit in the
+                * STATE_CLEAR register of this node, as described in
+                * 1394-1995, 8.4.2.6.  Also, send out a force root
+                * packet for this node.
+                */
+               new_root_id = root_id;
+       } else {
+               /*
+                * Current root has an active link layer and we
+                * successfully read the config rom, but it's not
+                * cycle master capable.
+                */
+               new_root_id = card->local_node->node_id;
+       }
+
+ pick_me:
+       /* Now figure out what gap count to set. */
+       if (card->topology_type == FW_TOPOLOGY_A &&
+           card->root_node->max_hops < ARRAY_SIZE(gap_count_table))
+               gap_count = gap_count_table[card->root_node->max_hops];
+       else
+               gap_count = 63;
+
+       /*
+        * Finally, figure out if we should do a reset or not.  If we've
+        * done less that 5 resets with the same physical topology and we
+        * have either a new root or a new gap count setting, let's do it.
+        */
+
+       if (card->bm_retries++ < 5 &&
+           (card->gap_count != gap_count || new_root_id != root_id))
+               do_reset = 1;
+
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (do_reset) {
+               fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
+                         card->index, new_root_id, gap_count);
+               fw_send_phy_config(card, new_root_id, generation, gap_count);
+               fw_core_initiate_bus_reset(card, 1);
+       }
+}
+
+static void
+flush_timer_callback(unsigned long data)
+{
+       struct fw_card *card = (struct fw_card *)data;
+
+       fw_flush_transactions(card);
+}
+
+void
+fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
+                  struct device *device)
+{
+       static atomic_t index = ATOMIC_INIT(-1);
+
+       kref_init(&card->kref);
+       card->index = atomic_inc_return(&index);
+       card->driver = driver;
+       card->device = device;
+       card->current_tlabel = 0;
+       card->tlabel_mask = 0;
+       card->color = 0;
+
+       INIT_LIST_HEAD(&card->transaction_list);
+       spin_lock_init(&card->lock);
+       setup_timer(&card->flush_timer,
+                   flush_timer_callback, (unsigned long)card);
+
+       card->local_node = NULL;
+
+       INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
+}
+EXPORT_SYMBOL(fw_card_initialize);
+
+int
+fw_card_add(struct fw_card *card,
+           u32 max_receive, u32 link_speed, u64 guid)
+{
+       u32 *config_rom;
+       size_t length;
+
+       card->max_receive = max_receive;
+       card->link_speed = link_speed;
+       card->guid = guid;
+
+       /* Activate link_on bit and contender bit in our self ID packets.*/
+       if (card->driver->update_phy_reg(card, 4, 0,
+                                        PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
+               return -EIO;
+
+       /*
+        * The subsystem grabs a reference when the card is added and
+        * drops it when the driver calls fw_core_remove_card.
+        */
+       fw_card_get(card);
+
+       mutex_lock(&card_mutex);
+       config_rom = generate_config_rom(card, &length);
+       list_add_tail(&card->link, &card_list);
+       mutex_unlock(&card_mutex);
+
+       return card->driver->enable(card, config_rom, length);
+}
+EXPORT_SYMBOL(fw_card_add);
+
+
+/*
+ * The next few functions implements a dummy driver that use once a
+ * card driver shuts down an fw_card.  This allows the driver to
+ * cleanly unload, as all IO to the card will be handled by the dummy
+ * driver instead of calling into the (possibly) unloaded module.  The
+ * dummy driver just fails all IO.
+ */
+
+static int
+dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
+{
+       BUG();
+       return -1;
+}
+
+static int
+dummy_update_phy_reg(struct fw_card *card, int address,
+                    int clear_bits, int set_bits)
+{
+       return -ENODEV;
+}
+
+static int
+dummy_set_config_rom(struct fw_card *card,
+                    u32 *config_rom, size_t length)
+{
+       /*
+        * We take the card out of card_list before setting the dummy
+        * driver, so this should never get called.
+        */
+       BUG();
+       return -1;
+}
+
+static void
+dummy_send_request(struct fw_card *card, struct fw_packet *packet)
+{
+       packet->callback(packet, card, -ENODEV);
+}
+
+static void
+dummy_send_response(struct fw_card *card, struct fw_packet *packet)
+{
+       packet->callback(packet, card, -ENODEV);
+}
+
+static int
+dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
+{
+       return -ENOENT;
+}
+
+static int
+dummy_enable_phys_dma(struct fw_card *card,
+                     int node_id, int generation)
+{
+       return -ENODEV;
+}
+
+static struct fw_card_driver dummy_driver = {
+       .name            = "dummy",
+       .enable          = dummy_enable,
+       .update_phy_reg  = dummy_update_phy_reg,
+       .set_config_rom  = dummy_set_config_rom,
+       .send_request    = dummy_send_request,
+       .cancel_packet   = dummy_cancel_packet,
+       .send_response   = dummy_send_response,
+       .enable_phys_dma = dummy_enable_phys_dma,
+};
+
+void
+fw_core_remove_card(struct fw_card *card)
+{
+       card->driver->update_phy_reg(card, 4,
+                                    PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
+       fw_core_initiate_bus_reset(card, 1);
+
+       mutex_lock(&card_mutex);
+       list_del(&card->link);
+       mutex_unlock(&card_mutex);
+
+       /* Set up the dummy driver. */
+       card->driver = &dummy_driver;
+
+       fw_flush_transactions(card);
+
+       fw_destroy_nodes(card);
+
+       fw_card_put(card);
+}
+EXPORT_SYMBOL(fw_core_remove_card);
+
+struct fw_card *
+fw_card_get(struct fw_card *card)
+{
+       kref_get(&card->kref);
+
+       return card;
+}
+EXPORT_SYMBOL(fw_card_get);
+
+static void
+release_card(struct kref *kref)
+{
+       struct fw_card *card = container_of(kref, struct fw_card, kref);
+
+       kfree(card);
+}
+
+/*
+ * An assumption for fw_card_put() is that the card driver allocates
+ * the fw_card struct with kalloc and that it has been shut down
+ * before the last ref is dropped.
+ */
+void
+fw_card_put(struct fw_card *card)
+{
+       kref_put(&card->kref, release_card);
+}
+EXPORT_SYMBOL(fw_card_put);
+
+int
+fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
+{
+       int reg = short_reset ? 5 : 1;
+       int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
+
+       return card->driver->update_phy_reg(card, reg, 0, bit);
+}
+EXPORT_SYMBOL(fw_core_initiate_bus_reset);
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
new file mode 100644 (file)
index 0000000..0fa5bd5
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * Char device for device raw access
+ *
+ * Copyright (C) 2005-2007  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/compat.h>
+#include <linux/firewire-cdev.h>
+#include <asm/uaccess.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+struct client;
+struct client_resource {
+       struct list_head link;
+       void (*release)(struct client *client, struct client_resource *r);
+       u32 handle;
+};
+
+/*
+ * dequeue_event() just kfree()'s the event, so the event has to be
+ * the first field in the struct.
+ */
+
+struct event {
+       struct { void *data; size_t size; } v[2];
+       struct list_head link;
+};
+
+struct bus_reset {
+       struct event event;
+       struct fw_cdev_event_bus_reset reset;
+};
+
+struct response {
+       struct event event;
+       struct fw_transaction transaction;
+       struct client *client;
+       struct client_resource resource;
+       struct fw_cdev_event_response response;
+};
+
+struct iso_interrupt {
+       struct event event;
+       struct fw_cdev_event_iso_interrupt interrupt;
+};
+
+struct client {
+       u32 version;
+       struct fw_device *device;
+       spinlock_t lock;
+       u32 resource_handle;
+       struct list_head resource_list;
+       struct list_head event_list;
+       wait_queue_head_t wait;
+       u64 bus_reset_closure;
+
+       struct fw_iso_context *iso_context;
+       u64 iso_closure;
+       struct fw_iso_buffer buffer;
+       unsigned long vm_start;
+
+       struct list_head link;
+};
+
+static inline void __user *
+u64_to_uptr(__u64 value)
+{
+       return (void __user *)(unsigned long)value;
+}
+
+static inline __u64
+uptr_to_u64(void __user *ptr)
+{
+       return (__u64)(unsigned long)ptr;
+}
+
+static int fw_device_op_open(struct inode *inode, struct file *file)
+{
+       struct fw_device *device;
+       struct client *client;
+       unsigned long flags;
+
+       device = fw_device_from_devt(inode->i_rdev);
+       if (device == NULL)
+               return -ENODEV;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return -ENOMEM;
+
+       client->device = fw_device_get(device);
+       INIT_LIST_HEAD(&client->event_list);
+       INIT_LIST_HEAD(&client->resource_list);
+       spin_lock_init(&client->lock);
+       init_waitqueue_head(&client->wait);
+
+       file->private_data = client;
+
+       spin_lock_irqsave(&device->card->lock, flags);
+       list_add_tail(&client->link, &device->client_list);
+       spin_unlock_irqrestore(&device->card->lock, flags);
+
+       return 0;
+}
+
+static void queue_event(struct client *client, struct event *event,
+                       void *data0, size_t size0, void *data1, size_t size1)
+{
+       unsigned long flags;
+
+       event->v[0].data = data0;
+       event->v[0].size = size0;
+       event->v[1].data = data1;
+       event->v[1].size = size1;
+
+       spin_lock_irqsave(&client->lock, flags);
+
+       list_add_tail(&event->link, &client->event_list);
+       wake_up_interruptible(&client->wait);
+
+       spin_unlock_irqrestore(&client->lock, flags);
+}
+
+static int
+dequeue_event(struct client *client, char __user *buffer, size_t count)
+{
+       unsigned long flags;
+       struct event *event;
+       size_t size, total;
+       int i, retval;
+
+       retval = wait_event_interruptible(client->wait,
+                                         !list_empty(&client->event_list) ||
+                                         fw_device_is_shutdown(client->device));
+       if (retval < 0)
+               return retval;
+
+       if (list_empty(&client->event_list) &&
+                      fw_device_is_shutdown(client->device))
+               return -ENODEV;
+
+       spin_lock_irqsave(&client->lock, flags);
+       event = container_of(client->event_list.next, struct event, link);
+       list_del(&event->link);
+       spin_unlock_irqrestore(&client->lock, flags);
+
+       total = 0;
+       for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) {
+               size = min(event->v[i].size, count - total);
+               if (copy_to_user(buffer + total, event->v[i].data, size)) {
+                       retval = -EFAULT;
+                       goto out;
+               }
+               total += size;
+       }
+       retval = total;
+
+ out:
+       kfree(event);
+
+       return retval;
+}
+
+static ssize_t
+fw_device_op_read(struct file *file,
+                 char __user *buffer, size_t count, loff_t *offset)
+{
+       struct client *client = file->private_data;
+
+       return dequeue_event(client, buffer, count);
+}
+
+static void
+fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
+                    struct client *client)
+{
+       struct fw_card *card = client->device->card;
+
+       event->closure       = client->bus_reset_closure;
+       event->type          = FW_CDEV_EVENT_BUS_RESET;
+       event->node_id       = client->device->node_id;
+       event->local_node_id = card->local_node->node_id;
+       event->bm_node_id    = 0; /* FIXME: We don't track the BM. */
+       event->irm_node_id   = card->irm_node->node_id;
+       event->root_node_id  = card->root_node->node_id;
+       event->generation    = card->generation;
+}
+
+static void
+for_each_client(struct fw_device *device,
+               void (*callback)(struct client *client))
+{
+       struct fw_card *card = device->card;
+       struct client *c;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       list_for_each_entry(c, &device->client_list, link)
+               callback(c);
+
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void
+queue_bus_reset_event(struct client *client)
+{
+       struct bus_reset *bus_reset;
+
+       bus_reset = kzalloc(sizeof(*bus_reset), GFP_ATOMIC);
+       if (bus_reset == NULL) {
+               fw_notify("Out of memory when allocating bus reset event\n");
+               return;
+       }
+
+       fill_bus_reset_event(&bus_reset->reset, client);
+
+       queue_event(client, &bus_reset->event,
+                   &bus_reset->reset, sizeof(bus_reset->reset), NULL, 0);
+}
+
+void fw_device_cdev_update(struct fw_device *device)
+{
+       for_each_client(device, queue_bus_reset_event);
+}
+
+static void wake_up_client(struct client *client)
+{
+       wake_up_interruptible(&client->wait);
+}
+
+void fw_device_cdev_remove(struct fw_device *device)
+{
+       for_each_client(device, wake_up_client);
+}
+
+static int ioctl_get_info(struct client *client, void *buffer)
+{
+       struct fw_cdev_get_info *get_info = buffer;
+       struct fw_cdev_event_bus_reset bus_reset;
+
+       client->version = get_info->version;
+       get_info->version = FW_CDEV_VERSION;
+
+       if (get_info->rom != 0) {
+               void __user *uptr = u64_to_uptr(get_info->rom);
+               size_t want = get_info->rom_length;
+               size_t have = client->device->config_rom_length * 4;
+
+               if (copy_to_user(uptr, client->device->config_rom,
+                                min(want, have)))
+                       return -EFAULT;
+       }
+       get_info->rom_length = client->device->config_rom_length * 4;
+
+       client->bus_reset_closure = get_info->bus_reset_closure;
+       if (get_info->bus_reset != 0) {
+               void __user *uptr = u64_to_uptr(get_info->bus_reset);
+
+               fill_bus_reset_event(&bus_reset, client);
+               if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
+                       return -EFAULT;
+       }
+
+       get_info->card = client->device->card->index;
+
+       return 0;
+}
+
+static void
+add_client_resource(struct client *client, struct client_resource *resource)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&client->lock, flags);
+       list_add_tail(&resource->link, &client->resource_list);
+       resource->handle = client->resource_handle++;
+       spin_unlock_irqrestore(&client->lock, flags);
+}
+
+static int
+release_client_resource(struct client *client, u32 handle,
+                       struct client_resource **resource)
+{
+       struct client_resource *r;
+       unsigned long flags;
+
+       spin_lock_irqsave(&client->lock, flags);
+       list_for_each_entry(r, &client->resource_list, link) {
+               if (r->handle == handle) {
+                       list_del(&r->link);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&client->lock, flags);
+
+       if (&r->link == &client->resource_list)
+               return -EINVAL;
+
+       if (resource)
+               *resource = r;
+       else
+               r->release(client, r);
+
+       return 0;
+}
+
+static void
+release_transaction(struct client *client, struct client_resource *resource)
+{
+       struct response *response =
+               container_of(resource, struct response, resource);
+
+       fw_cancel_transaction(client->device->card, &response->transaction);
+}
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+                    void *payload, size_t length, void *data)
+{
+       struct response *response = data;
+       struct client *client = response->client;
+       unsigned long flags;
+
+       if (length < response->response.length)
+               response->response.length = length;
+       if (rcode == RCODE_COMPLETE)
+               memcpy(response->response.data, payload,
+                      response->response.length);
+
+       spin_lock_irqsave(&client->lock, flags);
+       list_del(&response->resource.link);
+       spin_unlock_irqrestore(&client->lock, flags);
+
+       response->response.type   = FW_CDEV_EVENT_RESPONSE;
+       response->response.rcode  = rcode;
+       queue_event(client, &response->event,
+                   &response->response, sizeof(response->response),
+                   response->response.data, response->response.length);
+}
+
+static ssize_t ioctl_send_request(struct client *client, void *buffer)
+{
+       struct fw_device *device = client->device;
+       struct fw_cdev_send_request *request = buffer;
+       struct response *response;
+
+       /* What is the biggest size we'll accept, really? */
+       if (request->length > 4096)
+               return -EINVAL;
+
+       response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL);
+       if (response == NULL)
+               return -ENOMEM;
+
+       response->client = client;
+       response->response.length = request->length;
+       response->response.closure = request->closure;
+
+       if (request->data &&
+           copy_from_user(response->response.data,
+                          u64_to_uptr(request->data), request->length)) {
+               kfree(response);
+               return -EFAULT;
+       }
+
+       response->resource.release = release_transaction;
+       add_client_resource(client, &response->resource);
+
+       fw_send_request(device->card, &response->transaction,
+                       request->tcode & 0x1f,
+                       device->node->node_id,
+                       request->generation,
+                       device->node->max_speed,
+                       request->offset,
+                       response->response.data, request->length,
+                       complete_transaction, response);
+
+       if (request->data)
+               return sizeof(request) + request->length;
+       else
+               return sizeof(request);
+}
+
+struct address_handler {
+       struct fw_address_handler handler;
+       __u64 closure;
+       struct client *client;
+       struct client_resource resource;
+};
+
+struct request {
+       struct fw_request *request;
+       void *data;
+       size_t length;
+       struct client_resource resource;
+};
+
+struct request_event {
+       struct event event;
+       struct fw_cdev_event_request request;
+};
+
+static void
+release_request(struct client *client, struct client_resource *resource)
+{
+       struct request *request =
+               container_of(resource, struct request, resource);
+
+       fw_send_response(client->device->card, request->request,
+                        RCODE_CONFLICT_ERROR);
+       kfree(request);
+}
+
+static void
+handle_request(struct fw_card *card, struct fw_request *r,
+              int tcode, int destination, int source,
+              int generation, int speed,
+              unsigned long long offset,
+              void *payload, size_t length, void *callback_data)
+{
+       struct address_handler *handler = callback_data;
+       struct request *request;
+       struct request_event *e;
+       struct client *client = handler->client;
+
+       request = kmalloc(sizeof(*request), GFP_ATOMIC);
+       e = kmalloc(sizeof(*e), GFP_ATOMIC);
+       if (request == NULL || e == NULL) {
+               kfree(request);
+               kfree(e);
+               fw_send_response(card, r, RCODE_CONFLICT_ERROR);
+               return;
+       }
+
+       request->request = r;
+       request->data    = payload;
+       request->length  = length;
+
+       request->resource.release = release_request;
+       add_client_resource(client, &request->resource);
+
+       e->request.type    = FW_CDEV_EVENT_REQUEST;
+       e->request.tcode   = tcode;
+       e->request.offset  = offset;
+       e->request.length  = length;
+       e->request.handle  = request->resource.handle;
+       e->request.closure = handler->closure;
+
+       queue_event(client, &e->event,
+                   &e->request, sizeof(e->request), payload, length);
+}
+
+static void
+release_address_handler(struct client *client,
+                       struct client_resource *resource)
+{
+       struct address_handler *handler =
+               container_of(resource, struct address_handler, resource);
+
+       fw_core_remove_address_handler(&handler->handler);
+       kfree(handler);
+}
+
+static int ioctl_allocate(struct client *client, void *buffer)
+{
+       struct fw_cdev_allocate *request = buffer;
+       struct address_handler *handler;
+       struct fw_address_region region;
+
+       handler = kmalloc(sizeof(*handler), GFP_KERNEL);
+       if (handler == NULL)
+               return -ENOMEM;
+
+       region.start = request->offset;
+       region.end = request->offset + request->length;
+       handler->handler.length = request->length;
+       handler->handler.address_callback = handle_request;
+       handler->handler.callback_data = handler;
+       handler->closure = request->closure;
+       handler->client = client;
+
+       if (fw_core_add_address_handler(&handler->handler, &region) < 0) {
+               kfree(handler);
+               return -EBUSY;
+       }
+
+       handler->resource.release = release_address_handler;
+       add_client_resource(client, &handler->resource);
+       request->handle = handler->resource.handle;
+
+       return 0;
+}
+
+static int ioctl_deallocate(struct client *client, void *buffer)
+{
+       struct fw_cdev_deallocate *request = buffer;
+
+       return release_client_resource(client, request->handle, NULL);
+}
+
+static int ioctl_send_response(struct client *client, void *buffer)
+{
+       struct fw_cdev_send_response *request = buffer;
+       struct client_resource *resource;
+       struct request *r;
+
+       if (release_client_resource(client, request->handle, &resource) < 0)
+               return -EINVAL;
+       r = container_of(resource, struct request, resource);
+       if (request->length < r->length)
+               r->length = request->length;
+       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
+               return -EFAULT;
+
+       fw_send_response(client->device->card, r->request, request->rcode);
+       kfree(r);
+
+       return 0;
+}
+
+static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
+{
+       struct fw_cdev_initiate_bus_reset *request = buffer;
+       int short_reset;
+
+       short_reset = (request->type == FW_CDEV_SHORT_RESET);
+
+       return fw_core_initiate_bus_reset(client->device->card, short_reset);
+}
+
+struct descriptor {
+       struct fw_descriptor d;
+       struct client_resource resource;
+       u32 data[0];
+};
+
+static void release_descriptor(struct client *client,
+                              struct client_resource *resource)
+{
+       struct descriptor *descriptor =
+               container_of(resource, struct descriptor, resource);
+
+       fw_core_remove_descriptor(&descriptor->d);
+       kfree(descriptor);
+}
+
+static int ioctl_add_descriptor(struct client *client, void *buffer)
+{
+       struct fw_cdev_add_descriptor *request = buffer;
+       struct descriptor *descriptor;
+       int retval;
+
+       if (request->length > 256)
+               return -EINVAL;
+
+       descriptor =
+               kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL);
+       if (descriptor == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(descriptor->data,
+                          u64_to_uptr(request->data), request->length * 4)) {
+               kfree(descriptor);
+               return -EFAULT;
+       }
+
+       descriptor->d.length = request->length;
+       descriptor->d.immediate = request->immediate;
+       descriptor->d.key = request->key;
+       descriptor->d.data = descriptor->data;
+
+       retval = fw_core_add_descriptor(&descriptor->d);
+       if (retval < 0) {
+               kfree(descriptor);
+               return retval;
+       }
+
+       descriptor->resource.release = release_descriptor;
+       add_client_resource(client, &descriptor->resource);
+       request->handle = descriptor->resource.handle;
+
+       return 0;
+}
+
+static int ioctl_remove_descriptor(struct client *client, void *buffer)
+{
+       struct fw_cdev_remove_descriptor *request = buffer;
+
+       return release_client_resource(client, request->handle, NULL);
+}
+
+static void
+iso_callback(struct fw_iso_context *context, u32 cycle,
+            size_t header_length, void *header, void *data)
+{
+       struct client *client = data;
+       struct iso_interrupt *interrupt;
+
+       interrupt = kzalloc(sizeof(*interrupt) + header_length, GFP_ATOMIC);
+       if (interrupt == NULL)
+               return;
+
+       interrupt->interrupt.type      = FW_CDEV_EVENT_ISO_INTERRUPT;
+       interrupt->interrupt.closure   = client->iso_closure;
+       interrupt->interrupt.cycle     = cycle;
+       interrupt->interrupt.header_length = header_length;
+       memcpy(interrupt->interrupt.header, header, header_length);
+       queue_event(client, &interrupt->event,
+                   &interrupt->interrupt,
+                   sizeof(interrupt->interrupt) + header_length, NULL, 0);
+}
+
+static int ioctl_create_iso_context(struct client *client, void *buffer)
+{
+       struct fw_cdev_create_iso_context *request = buffer;
+
+       if (request->channel > 63)
+               return -EINVAL;
+
+       switch (request->type) {
+       case FW_ISO_CONTEXT_RECEIVE:
+               if (request->header_size < 4 || (request->header_size & 3))
+                       return -EINVAL;
+
+               break;
+
+       case FW_ISO_CONTEXT_TRANSMIT:
+               if (request->speed > SCODE_3200)
+                       return -EINVAL;
+
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       client->iso_closure = request->closure;
+       client->iso_context = fw_iso_context_create(client->device->card,
+                                                   request->type,
+                                                   request->channel,
+                                                   request->speed,
+                                                   request->header_size,
+                                                   iso_callback, client);
+       if (IS_ERR(client->iso_context))
+               return PTR_ERR(client->iso_context);
+
+       /* We only support one context at this time. */
+       request->handle = 0;
+
+       return 0;
+}
+
+static int ioctl_queue_iso(struct client *client, void *buffer)
+{
+       struct fw_cdev_queue_iso *request = buffer;
+       struct fw_cdev_iso_packet __user *p, *end, *next;
+       struct fw_iso_context *ctx = client->iso_context;
+       unsigned long payload, buffer_end, header_length;
+       int count;
+       struct {
+               struct fw_iso_packet packet;
+               u8 header[256];
+       } u;
+
+       if (ctx == NULL || request->handle != 0)
+               return -EINVAL;
+
+       /*
+        * If the user passes a non-NULL data pointer, has mmap()'ed
+        * the iso buffer, and the pointer points inside the buffer,
+        * we setup the payload pointers accordingly.  Otherwise we
+        * set them both to 0, which will still let packets with
+        * payload_length == 0 through.  In other words, if no packets
+        * use the indirect payload, the iso buffer need not be mapped
+        * and the request->data pointer is ignored.
+        */
+
+       payload = (unsigned long)request->data - client->vm_start;
+       buffer_end = client->buffer.page_count << PAGE_SHIFT;
+       if (request->data == 0 || client->buffer.pages == NULL ||
+           payload >= buffer_end) {
+               payload = 0;
+               buffer_end = 0;
+       }
+
+       if (!access_ok(VERIFY_READ, request->packets, request->size))
+               return -EFAULT;
+
+       p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+       end = (void __user *)p + request->size;
+       count = 0;
+       while (p < end) {
+               if (__copy_from_user(&u.packet, p, sizeof(*p)))
+                       return -EFAULT;
+
+               if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
+                       header_length = u.packet.header_length;
+               } else {
+                       /*
+                        * We require that header_length is a multiple of
+                        * the fixed header size, ctx->header_size.
+                        */
+                       if (ctx->header_size == 0) {
+                               if (u.packet.header_length > 0)
+                                       return -EINVAL;
+                       } else if (u.packet.header_length % ctx->header_size != 0) {
+                               return -EINVAL;
+                       }
+                       header_length = 0;
+               }
+
+               next = (struct fw_cdev_iso_packet __user *)
+                       &p->header[header_length / 4];
+               if (next > end)
+                       return -EINVAL;
+               if (__copy_from_user
+                   (u.packet.header, p->header, header_length))
+                       return -EFAULT;
+               if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT &&
+                   u.packet.header_length + u.packet.payload_length > 0)
+                       return -EINVAL;
+               if (payload + u.packet.payload_length > buffer_end)
+                       return -EINVAL;
+
+               if (fw_iso_context_queue(ctx, &u.packet,
+                                        &client->buffer, payload))
+                       break;
+
+               p = next;
+               payload += u.packet.payload_length;
+               count++;
+       }
+
+       request->size    -= uptr_to_u64(p) - request->packets;
+       request->packets  = uptr_to_u64(p);
+       request->data     = client->vm_start + payload;
+
+       return count;
+}
+
+static int ioctl_start_iso(struct client *client, void *buffer)
+{
+       struct fw_cdev_start_iso *request = buffer;
+
+       if (request->handle != 0)
+               return -EINVAL;
+       if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
+               if (request->tags == 0 || request->tags > 15)
+                       return -EINVAL;
+
+               if (request->sync > 15)
+                       return -EINVAL;
+       }
+
+       return fw_iso_context_start(client->iso_context, request->cycle,
+                                   request->sync, request->tags);
+}
+
+static int ioctl_stop_iso(struct client *client, void *buffer)
+{
+       struct fw_cdev_stop_iso *request = buffer;
+
+       if (request->handle != 0)
+               return -EINVAL;
+
+       return fw_iso_context_stop(client->iso_context);
+}
+
+static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
+       ioctl_get_info,
+       ioctl_send_request,
+       ioctl_allocate,
+       ioctl_deallocate,
+       ioctl_send_response,
+       ioctl_initiate_bus_reset,
+       ioctl_add_descriptor,
+       ioctl_remove_descriptor,
+       ioctl_create_iso_context,
+       ioctl_queue_iso,
+       ioctl_start_iso,
+       ioctl_stop_iso,
+};
+
+static int
+dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
+{
+       char buffer[256];
+       int retval;
+
+       if (_IOC_TYPE(cmd) != '#' ||
+           _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
+               return -EINVAL;
+
+       if (_IOC_DIR(cmd) & _IOC_WRITE) {
+               if (_IOC_SIZE(cmd) > sizeof(buffer) ||
+                   copy_from_user(buffer, arg, _IOC_SIZE(cmd)))
+                       return -EFAULT;
+       }
+
+       retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
+       if (retval < 0)
+               return retval;
+
+       if (_IOC_DIR(cmd) & _IOC_READ) {
+               if (_IOC_SIZE(cmd) > sizeof(buffer) ||
+                   copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static long
+fw_device_op_ioctl(struct file *file,
+                  unsigned int cmd, unsigned long arg)
+{
+       struct client *client = file->private_data;
+
+       return dispatch_ioctl(client, cmd, (void __user *) arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long
+fw_device_op_compat_ioctl(struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       struct client *client = file->private_data;
+
+       return dispatch_ioctl(client, cmd, compat_ptr(arg));
+}
+#endif
+
+static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct client *client = file->private_data;
+       enum dma_data_direction direction;
+       unsigned long size;
+       int page_count, retval;
+
+       /* FIXME: We could support multiple buffers, but we don't. */
+       if (client->buffer.pages != NULL)
+               return -EBUSY;
+
+       if (!(vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+
+       if (vma->vm_start & ~PAGE_MASK)
+               return -EINVAL;
+
+       client->vm_start = vma->vm_start;
+       size = vma->vm_end - vma->vm_start;
+       page_count = size >> PAGE_SHIFT;
+       if (size & ~PAGE_MASK)
+               return -EINVAL;
+
+       if (vma->vm_flags & VM_WRITE)
+               direction = DMA_TO_DEVICE;
+       else
+               direction = DMA_FROM_DEVICE;
+
+       retval = fw_iso_buffer_init(&client->buffer, client->device->card,
+                                   page_count, direction);
+       if (retval < 0)
+               return retval;
+
+       retval = fw_iso_buffer_map(&client->buffer, vma);
+       if (retval < 0)
+               fw_iso_buffer_destroy(&client->buffer, client->device->card);
+
+       return retval;
+}
+
+static int fw_device_op_release(struct inode *inode, struct file *file)
+{
+       struct client *client = file->private_data;
+       struct event *e, *next_e;
+       struct client_resource *r, *next_r;
+       unsigned long flags;
+
+       if (client->buffer.pages)
+               fw_iso_buffer_destroy(&client->buffer, client->device->card);
+
+       if (client->iso_context)
+               fw_iso_context_destroy(client->iso_context);
+
+       list_for_each_entry_safe(r, next_r, &client->resource_list, link)
+               r->release(client, r);
+
+       /*
+        * FIXME: We should wait for the async tasklets to stop
+        * running before freeing the memory.
+        */
+
+       list_for_each_entry_safe(e, next_e, &client->event_list, link)
+               kfree(e);
+
+       spin_lock_irqsave(&client->device->card->lock, flags);
+       list_del(&client->link);
+       spin_unlock_irqrestore(&client->device->card->lock, flags);
+
+       fw_device_put(client->device);
+       kfree(client);
+
+       return 0;
+}
+
+static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
+{
+       struct client *client = file->private_data;
+       unsigned int mask = 0;
+
+       poll_wait(file, &client->wait, pt);
+
+       if (fw_device_is_shutdown(client->device))
+               mask |= POLLHUP | POLLERR;
+       if (!list_empty(&client->event_list))
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+const struct file_operations fw_device_ops = {
+       .owner          = THIS_MODULE,
+       .open           = fw_device_op_open,
+       .read           = fw_device_op_read,
+       .unlocked_ioctl = fw_device_op_ioctl,
+       .poll           = fw_device_op_poll,
+       .release        = fw_device_op_release,
+       .mmap           = fw_device_op_mmap,
+
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = fw_device_op_compat_ioctl,
+#endif
+};
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
new file mode 100644 (file)
index 0000000..c1ce465
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Device probing and sysfs code.
+ *
+ * Copyright (C) 2005-2006  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/module.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/rwsem.h>
+#include <asm/semaphore.h>
+#include <linux/ctype.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
+{
+       ci->p = p + 1;
+       ci->end = ci->p + (p[0] >> 16);
+}
+EXPORT_SYMBOL(fw_csr_iterator_init);
+
+int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
+{
+       *key = *ci->p >> 24;
+       *value = *ci->p & 0xffffff;
+
+       return ci->p++ < ci->end;
+}
+EXPORT_SYMBOL(fw_csr_iterator_next);
+
+static int is_fw_unit(struct device *dev);
+
+static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
+{
+       struct fw_csr_iterator ci;
+       int key, value, match;
+
+       match = 0;
+       fw_csr_iterator_init(&ci, directory);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (key == CSR_VENDOR && value == id->vendor)
+                       match |= FW_MATCH_VENDOR;
+               if (key == CSR_MODEL && value == id->model)
+                       match |= FW_MATCH_MODEL;
+               if (key == CSR_SPECIFIER_ID && value == id->specifier_id)
+                       match |= FW_MATCH_SPECIFIER_ID;
+               if (key == CSR_VERSION && value == id->version)
+                       match |= FW_MATCH_VERSION;
+       }
+
+       return (match & id->match_flags) == id->match_flags;
+}
+
+static int fw_unit_match(struct device *dev, struct device_driver *drv)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       struct fw_driver *driver = fw_driver(drv);
+       int i;
+
+       /* We only allow binding to fw_units. */
+       if (!is_fw_unit(dev))
+               return 0;
+
+       for (i = 0; driver->id_table[i].match_flags != 0; i++) {
+               if (match_unit_directory(unit->directory, &driver->id_table[i]))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct fw_csr_iterator ci;
+
+       int key, value;
+       int vendor = 0;
+       int model = 0;
+       int specifier_id = 0;
+       int version = 0;
+
+       fw_csr_iterator_init(&ci, &device->config_rom[5]);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               switch (key) {
+               case CSR_VENDOR:
+                       vendor = value;
+                       break;
+               case CSR_MODEL:
+                       model = value;
+                       break;
+               }
+       }
+
+       fw_csr_iterator_init(&ci, unit->directory);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               switch (key) {
+               case CSR_SPECIFIER_ID:
+                       specifier_id = value;
+                       break;
+               case CSR_VERSION:
+                       version = value;
+                       break;
+               }
+       }
+
+       return snprintf(buffer, buffer_size,
+                       "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+                       vendor, model, specifier_id, version);
+}
+
+static int
+fw_unit_uevent(struct device *dev, char **envp, int num_envp,
+              char *buffer, int buffer_size)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       char modalias[64];
+       int length = 0;
+       int i = 0;
+
+       get_modalias(unit, modalias, sizeof(modalias));
+
+       if (add_uevent_var(envp, num_envp, &i,
+                          buffer, buffer_size, &length,
+                          "MODALIAS=%s", modalias))
+               return -ENOMEM;
+
+       envp[i] = NULL;
+
+       return 0;
+}
+
+struct bus_type fw_bus_type = {
+       .name = "firewire",
+       .match = fw_unit_match,
+};
+EXPORT_SYMBOL(fw_bus_type);
+
+struct fw_device *fw_device_get(struct fw_device *device)
+{
+       get_device(&device->device);
+
+       return device;
+}
+
+void fw_device_put(struct fw_device *device)
+{
+       put_device(&device->device);
+}
+
+static void fw_device_release(struct device *dev)
+{
+       struct fw_device *device = fw_device(dev);
+       unsigned long flags;
+
+       /*
+        * Take the card lock so we don't set this to NULL while a
+        * FW_NODE_UPDATED callback is being handled.
+        */
+       spin_lock_irqsave(&device->card->lock, flags);
+       device->node->data = NULL;
+       spin_unlock_irqrestore(&device->card->lock, flags);
+
+       fw_node_put(device->node);
+       fw_card_put(device->card);
+       kfree(device->config_rom);
+       kfree(device);
+}
+
+int fw_device_enable_phys_dma(struct fw_device *device)
+{
+       return device->card->driver->enable_phys_dma(device->card,
+                                                    device->node_id,
+                                                    device->generation);
+}
+EXPORT_SYMBOL(fw_device_enable_phys_dma);
+
+struct config_rom_attribute {
+       struct device_attribute attr;
+       u32 key;
+};
+
+static ssize_t
+show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+       struct config_rom_attribute *attr =
+               container_of(dattr, struct config_rom_attribute, attr);
+       struct fw_csr_iterator ci;
+       u32 *dir;
+       int key, value;
+
+       if (is_fw_unit(dev))
+               dir = fw_unit(dev)->directory;
+       else
+               dir = fw_device(dev)->config_rom + 5;
+
+       fw_csr_iterator_init(&ci, dir);
+       while (fw_csr_iterator_next(&ci, &key, &value))
+               if (attr->key == key)
+                       return snprintf(buf, buf ? PAGE_SIZE : 0,
+                                       "0x%06x\n", value);
+
+       return -ENOENT;
+}
+
+#define IMMEDIATE_ATTR(name, key)                              \
+       { __ATTR(name, S_IRUGO, show_immediate, NULL), key }
+
+static ssize_t
+show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+       struct config_rom_attribute *attr =
+               container_of(dattr, struct config_rom_attribute, attr);
+       struct fw_csr_iterator ci;
+       u32 *dir, *block = NULL, *p, *end;
+       int length, key, value, last_key = 0;
+       char *b;
+
+       if (is_fw_unit(dev))
+               dir = fw_unit(dev)->directory;
+       else
+               dir = fw_device(dev)->config_rom + 5;
+
+       fw_csr_iterator_init(&ci, dir);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (attr->key == last_key &&
+                   key == (CSR_DESCRIPTOR | CSR_LEAF))
+                       block = ci.p - 1 + value;
+               last_key = key;
+       }
+
+       if (block == NULL)
+               return -ENOENT;
+
+       length = min(block[0] >> 16, 256U);
+       if (length < 3)
+               return -ENOENT;
+
+       if (block[1] != 0 || block[2] != 0)
+               /* Unknown encoding. */
+               return -ENOENT;
+
+       if (buf == NULL)
+               return length * 4;
+
+       b = buf;
+       end = &block[length + 1];
+       for (p = &block[3]; p < end; p++, b += 4)
+               * (u32 *) b = (__force u32) __cpu_to_be32(*p);
+
+       /* Strip trailing whitespace and add newline. */
+       while (b--, (isspace(*b) || *b == '\0') && b > buf);
+       strcpy(b + 1, "\n");
+
+       return b + 2 - buf;
+}
+
+#define TEXT_LEAF_ATTR(name, key)                              \
+       { __ATTR(name, S_IRUGO, show_text_leaf, NULL), key }
+
+static struct config_rom_attribute config_rom_attributes[] = {
+       IMMEDIATE_ATTR(vendor, CSR_VENDOR),
+       IMMEDIATE_ATTR(hardware_version, CSR_HARDWARE_VERSION),
+       IMMEDIATE_ATTR(specifier_id, CSR_SPECIFIER_ID),
+       IMMEDIATE_ATTR(version, CSR_VERSION),
+       IMMEDIATE_ATTR(model, CSR_MODEL),
+       TEXT_LEAF_ATTR(vendor_name, CSR_VENDOR),
+       TEXT_LEAF_ATTR(model_name, CSR_MODEL),
+       TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION),
+};
+
+static void
+init_fw_attribute_group(struct device *dev,
+                       struct device_attribute *attrs,
+                       struct fw_attribute_group *group)
+{
+       struct device_attribute *attr;
+       int i, j;
+
+       for (j = 0; attrs[j].attr.name != NULL; j++)
+               group->attrs[j] = &attrs[j].attr;
+
+       for (i = 0; i < ARRAY_SIZE(config_rom_attributes); i++) {
+               attr = &config_rom_attributes[i].attr;
+               if (attr->show(dev, attr, NULL) < 0)
+                       continue;
+               group->attrs[j++] = &attr->attr;
+       }
+
+       BUG_ON(j >= ARRAY_SIZE(group->attrs));
+       group->attrs[j++] = NULL;
+       group->groups[0] = &group->group;
+       group->groups[1] = NULL;
+       group->group.attrs = group->attrs;
+       dev->groups = group->groups;
+}
+
+static ssize_t
+modalias_show(struct device *dev,
+             struct device_attribute *attr, char *buf)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       int length;
+
+       length = get_modalias(unit, buf, PAGE_SIZE);
+       strcpy(buf + length, "\n");
+
+       return length + 1;
+}
+
+static ssize_t
+rom_index_show(struct device *dev,
+              struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev->parent);
+       struct fw_unit *unit = fw_unit(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       (int)(unit->directory - device->config_rom));
+}
+
+static struct device_attribute fw_unit_attributes[] = {
+       __ATTR_RO(modalias),
+       __ATTR_RO(rom_index),
+       __ATTR_NULL,
+};
+
+static ssize_t
+config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev);
+
+       memcpy(buf, device->config_rom, device->config_rom_length * 4);
+
+       return device->config_rom_length * 4;
+}
+
+static ssize_t
+guid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev);
+       u64 guid;
+
+       guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
+
+       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+                       (unsigned long long)guid);
+}
+
+static struct device_attribute fw_device_attributes[] = {
+       __ATTR_RO(config_rom),
+       __ATTR_RO(guid),
+       __ATTR_NULL,
+};
+
+struct read_quadlet_callback_data {
+       struct completion done;
+       int rcode;
+       u32 data;
+};
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+                    void *payload, size_t length, void *data)
+{
+       struct read_quadlet_callback_data *callback_data = data;
+
+       if (rcode == RCODE_COMPLETE)
+               callback_data->data = be32_to_cpu(*(__be32 *)payload);
+       callback_data->rcode = rcode;
+       complete(&callback_data->done);
+}
+
+static int read_rom(struct fw_device *device, int index, u32 * data)
+{
+       struct read_quadlet_callback_data callback_data;
+       struct fw_transaction t;
+       u64 offset;
+
+       init_completion(&callback_data.done);
+
+       offset = 0xfffff0000400ULL + index * 4;
+       fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST,
+                       device->node_id,
+                       device->generation, SCODE_100,
+                       offset, NULL, 4, complete_transaction, &callback_data);
+
+       wait_for_completion(&callback_data.done);
+
+       *data = callback_data.data;
+
+       return callback_data.rcode;
+}
+
+static int read_bus_info_block(struct fw_device *device)
+{
+       static u32 rom[256];
+       u32 stack[16], sp, key;
+       int i, end, length;
+
+       /* First read the bus info block. */
+       for (i = 0; i < 5; i++) {
+               if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+                       return -1;
+               /*
+                * As per IEEE1212 7.2, during power-up, devices can
+                * reply with a 0 for the first quadlet of the config
+                * rom to indicate that they are booting (for example,
+                * if the firmware is on the disk of a external
+                * harddisk).  In that case we just fail, and the
+                * retry mechanism will try again later.
+                */
+               if (i == 0 && rom[i] == 0)
+                       return -1;
+       }
+
+       /*
+        * Now parse the config rom.  The config rom is a recursive
+        * directory structure so we parse it using a stack of
+        * references to the blocks that make up the structure.  We
+        * push a reference to the root directory on the stack to
+        * start things off.
+        */
+       length = i;
+       sp = 0;
+       stack[sp++] = 0xc0000005;
+       while (sp > 0) {
+               /*
+                * Pop the next block reference of the stack.  The
+                * lower 24 bits is the offset into the config rom,
+                * the upper 8 bits are the type of the reference the
+                * block.
+                */
+               key = stack[--sp];
+               i = key & 0xffffff;
+               if (i >= ARRAY_SIZE(rom))
+                       /*
+                        * The reference points outside the standard
+                        * config rom area, something's fishy.
+                        */
+                       return -1;
+
+               /* Read header quadlet for the block to get the length. */
+               if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+                       return -1;
+               end = i + (rom[i] >> 16) + 1;
+               i++;
+               if (end > ARRAY_SIZE(rom))
+                       /*
+                        * This block extends outside standard config
+                        * area (and the array we're reading it
+                        * into).  That's broken, so ignore this
+                        * device.
+                        */
+                       return -1;
+
+               /*
+                * Now read in the block.  If this is a directory
+                * block, check the entries as we read them to see if
+                * it references another block, and push it in that case.
+                */
+               while (i < end) {
+                       if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+                               return -1;
+                       if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
+                           sp < ARRAY_SIZE(stack))
+                               stack[sp++] = i + rom[i];
+                       i++;
+               }
+               if (length < i)
+                       length = i;
+       }
+
+       device->config_rom = kmalloc(length * 4, GFP_KERNEL);
+       if (device->config_rom == NULL)
+               return -1;
+       memcpy(device->config_rom, rom, length * 4);
+       device->config_rom_length = length;
+
+       return 0;
+}
+
+static void fw_unit_release(struct device *dev)
+{
+       struct fw_unit *unit = fw_unit(dev);
+
+       kfree(unit);
+}
+
+static struct device_type fw_unit_type = {
+       .uevent         = fw_unit_uevent,
+       .release        = fw_unit_release,
+};
+
+static int is_fw_unit(struct device *dev)
+{
+       return dev->type == &fw_unit_type;
+}
+
+static void create_units(struct fw_device *device)
+{
+       struct fw_csr_iterator ci;
+       struct fw_unit *unit;
+       int key, value, i;
+
+       i = 0;
+       fw_csr_iterator_init(&ci, &device->config_rom[5]);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (key != (CSR_UNIT | CSR_DIRECTORY))
+                       continue;
+
+               /*
+                * Get the address of the unit directory and try to
+                * match the drivers id_tables against it.
+                */
+               unit = kzalloc(sizeof(*unit), GFP_KERNEL);
+               if (unit == NULL) {
+                       fw_error("failed to allocate memory for unit\n");
+                       continue;
+               }
+
+               unit->directory = ci.p + value - 1;
+               unit->device.bus = &fw_bus_type;
+               unit->device.type = &fw_unit_type;
+               unit->device.parent = &device->device;
+               snprintf(unit->device.bus_id, sizeof(unit->device.bus_id),
+                        "%s.%d", device->device.bus_id, i++);
+
+               init_fw_attribute_group(&unit->device,
+                                       fw_unit_attributes,
+                                       &unit->attribute_group);
+               if (device_register(&unit->device) < 0)
+                       goto skip_unit;
+
+               continue;
+
+       skip_unit:
+               kfree(unit);
+       }
+}
+
+static int shutdown_unit(struct device *device, void *data)
+{
+       device_unregister(device);
+
+       return 0;
+}
+
+static DECLARE_RWSEM(idr_rwsem);
+static DEFINE_IDR(fw_device_idr);
+int fw_cdev_major;
+
+struct fw_device *fw_device_from_devt(dev_t devt)
+{
+       struct fw_device *device;
+
+       down_read(&idr_rwsem);
+       device = idr_find(&fw_device_idr, MINOR(devt));
+       up_read(&idr_rwsem);
+
+       return device;
+}
+
+static void fw_device_shutdown(struct work_struct *work)
+{
+       struct fw_device *device =
+               container_of(work, struct fw_device, work.work);
+       int minor = MINOR(device->device.devt);
+
+       down_write(&idr_rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&idr_rwsem);
+
+       fw_device_cdev_remove(device);
+       device_for_each_child(&device->device, NULL, shutdown_unit);
+       device_unregister(&device->device);
+}
+
+static struct device_type fw_device_type = {
+       .release        = fw_device_release,
+};
+
+/*
+ * These defines control the retry behavior for reading the config
+ * rom.  It shouldn't be necessary to tweak these; if the device
+ * doesn't respond to a config rom read within 10 seconds, it's not
+ * going to respond at all.  As for the initial delay, a lot of
+ * devices will be able to respond within half a second after bus
+ * reset.  On the other hand, it's not really worth being more
+ * aggressive than that, since it scales pretty well; if 10 devices
+ * are plugged in, they're all getting read within one second.
+ */
+
+#define MAX_RETRIES    10
+#define RETRY_DELAY    (3 * HZ)
+#define INITIAL_DELAY  (HZ / 2)
+
+static void fw_device_init(struct work_struct *work)
+{
+       struct fw_device *device =
+               container_of(work, struct fw_device, work.work);
+       int minor, err;
+
+       /*
+        * All failure paths here set node->data to NULL, so that we
+        * don't try to do device_for_each_child() on a kfree()'d
+        * device.
+        */
+
+       if (read_bus_info_block(device) < 0) {
+               if (device->config_rom_retries < MAX_RETRIES) {
+                       device->config_rom_retries++;
+                       schedule_delayed_work(&device->work, RETRY_DELAY);
+               } else {
+                       fw_notify("giving up on config rom for node id %x\n",
+                                 device->node_id);
+                       if (device->node == device->card->root_node)
+                               schedule_delayed_work(&device->card->work, 0);
+                       fw_device_release(&device->device);
+               }
+               return;
+       }
+
+       err = -ENOMEM;
+       down_write(&idr_rwsem);
+       if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
+               err = idr_get_new(&fw_device_idr, device, &minor);
+       up_write(&idr_rwsem);
+       if (err < 0)
+               goto error;
+
+       device->device.bus = &fw_bus_type;
+       device->device.type = &fw_device_type;
+       device->device.parent = device->card->device;
+       device->device.devt = MKDEV(fw_cdev_major, minor);
+       snprintf(device->device.bus_id, sizeof(device->device.bus_id),
+                "fw%d", minor);
+
+       init_fw_attribute_group(&device->device,
+                               fw_device_attributes,
+                               &device->attribute_group);
+       if (device_add(&device->device)) {
+               fw_error("Failed to add device.\n");
+               goto error_with_cdev;
+       }
+
+       create_units(device);
+
+       /*
+        * Transition the device to running state.  If it got pulled
+        * out from under us while we did the intialization work, we
+        * have to shut down the device again here.  Normally, though,
+        * fw_node_event will be responsible for shutting it down when
+        * necessary.  We have to use the atomic cmpxchg here to avoid
+        * racing with the FW_NODE_DESTROYED case in
+        * fw_node_event().
+        */
+       if (atomic_cmpxchg(&device->state,
+                   FW_DEVICE_INITIALIZING,
+                   FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
+               fw_device_shutdown(&device->work.work);
+       else
+               fw_notify("created new fw device %s (%d config rom retries)\n",
+                         device->device.bus_id, device->config_rom_retries);
+
+       /*
+        * Reschedule the IRM work if we just finished reading the
+        * root node config rom.  If this races with a bus reset we
+        * just end up running the IRM work a couple of extra times -
+        * pretty harmless.
+        */
+       if (device->node == device->card->root_node)
+               schedule_delayed_work(&device->card->work, 0);
+
+       return;
+
+ error_with_cdev:
+       down_write(&idr_rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&idr_rwsem);
+ error:
+       put_device(&device->device);
+}
+
+static int update_unit(struct device *dev, void *data)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       struct fw_driver *driver = (struct fw_driver *)dev->driver;
+
+       if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
+               down(&dev->sem);
+               driver->update(unit);
+               up(&dev->sem);
+       }
+
+       return 0;
+}
+
+static void fw_device_update(struct work_struct *work)
+{
+       struct fw_device *device =
+               container_of(work, struct fw_device, work.work);
+
+       fw_device_cdev_update(device);
+       device_for_each_child(&device->device, NULL, update_unit);
+}
+
+void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
+{
+       struct fw_device *device;
+
+       switch (event) {
+       case FW_NODE_CREATED:
+       case FW_NODE_LINK_ON:
+               if (!node->link_on)
+                       break;
+
+               device = kzalloc(sizeof(*device), GFP_ATOMIC);
+               if (device == NULL)
+                       break;
+
+               /*
+                * Do minimal intialization of the device here, the
+                * rest will happen in fw_device_init().  We need the
+                * card and node so we can read the config rom and we
+                * need to do device_initialize() now so
+                * device_for_each_child() in FW_NODE_UPDATED is
+                * doesn't freak out.
+                */
+               device_initialize(&device->device);
+               atomic_set(&device->state, FW_DEVICE_INITIALIZING);
+               device->card = fw_card_get(card);
+               device->node = fw_node_get(node);
+               device->node_id = node->node_id;
+               device->generation = card->generation;
+               INIT_LIST_HEAD(&device->client_list);
+
+               /*
+                * Set the node data to point back to this device so
+                * FW_NODE_UPDATED callbacks can update the node_id
+                * and generation for the device.
+                */
+               node->data = device;
+
+               /*
+                * Many devices are slow to respond after bus resets,
+                * especially if they are bus powered and go through
+                * power-up after getting plugged in.  We schedule the
+                * first config rom scan half a second after bus reset.
+                */
+               INIT_DELAYED_WORK(&device->work, fw_device_init);
+               schedule_delayed_work(&device->work, INITIAL_DELAY);
+               break;
+
+       case FW_NODE_UPDATED:
+               if (!node->link_on || node->data == NULL)
+                       break;
+
+               device = node->data;
+               device->node_id = node->node_id;
+               device->generation = card->generation;
+               if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
+                       PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+                       schedule_delayed_work(&device->work, 0);
+               }
+               break;
+
+       case FW_NODE_DESTROYED:
+       case FW_NODE_LINK_OFF:
+               if (!node->data)
+                       break;
+
+               /*
+                * Destroy the device associated with the node.  There
+                * are two cases here: either the device is fully
+                * initialized (FW_DEVICE_RUNNING) or we're in the
+                * process of reading its config rom
+                * (FW_DEVICE_INITIALIZING).  If it is fully
+                * initialized we can reuse device->work to schedule a
+                * full fw_device_shutdown().  If not, there's work
+                * scheduled to read it's config rom, and we just put
+                * the device in shutdown state to have that code fail
+                * to create the device.
+                */
+               device = node->data;
+               if (atomic_xchg(&device->state,
+                               FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {
+                       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+                       schedule_delayed_work(&device->work, 0);
+               }
+               break;
+       }
+}
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
new file mode 100644 (file)
index 0000000..0ba9d64
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2006  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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.
+ */
+
+#ifndef __fw_device_h
+#define __fw_device_h
+
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <asm/atomic.h>
+
+enum fw_device_state {
+       FW_DEVICE_INITIALIZING,
+       FW_DEVICE_RUNNING,
+       FW_DEVICE_SHUTDOWN,
+};
+
+struct fw_attribute_group {
+       struct attribute_group *groups[2];
+       struct attribute_group group;
+       struct attribute *attrs[11];
+};
+
+struct fw_device {
+       atomic_t state;
+       struct fw_node *node;
+       int node_id;
+       int generation;
+       struct fw_card *card;
+       struct device device;
+       struct list_head link;
+       struct list_head client_list;
+       u32 *config_rom;
+       size_t config_rom_length;
+       int config_rom_retries;
+       struct delayed_work work;
+       struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_device *
+fw_device(struct device *dev)
+{
+       return container_of(dev, struct fw_device, device);
+}
+
+static inline int
+fw_device_is_shutdown(struct fw_device *device)
+{
+       return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
+}
+
+struct fw_device *fw_device_get(struct fw_device *device);
+void fw_device_put(struct fw_device *device);
+int fw_device_enable_phys_dma(struct fw_device *device);
+
+void fw_device_cdev_update(struct fw_device *device);
+void fw_device_cdev_remove(struct fw_device *device);
+
+struct fw_device *fw_device_from_devt(dev_t devt);
+extern int fw_cdev_major;
+
+struct fw_unit {
+       struct device device;
+       u32 *directory;
+       struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_unit *
+fw_unit(struct device *dev)
+{
+       return container_of(dev, struct fw_unit, device);
+}
+
+#define CSR_OFFSET     0x40
+#define CSR_LEAF       0x80
+#define CSR_DIRECTORY  0xc0
+
+#define CSR_DESCRIPTOR         0x01
+#define CSR_VENDOR             0x03
+#define CSR_HARDWARE_VERSION   0x04
+#define CSR_NODE_CAPABILITIES  0x0c
+#define CSR_UNIT               0x11
+#define CSR_SPECIFIER_ID       0x12
+#define CSR_VERSION            0x13
+#define CSR_DEPENDENT_INFO     0x14
+#define CSR_MODEL              0x17
+#define CSR_INSTANCE           0x18
+
+#define SBP2_COMMAND_SET_SPECIFIER     0x38
+#define SBP2_COMMAND_SET               0x39
+#define SBP2_COMMAND_SET_REVISION      0x3b
+#define SBP2_FIRMWARE_REVISION         0x3c
+
+struct fw_csr_iterator {
+       u32 *p;
+       u32 *end;
+};
+
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
+int fw_csr_iterator_next(struct fw_csr_iterator *ci,
+                        int *key, int *value);
+
+#define FW_MATCH_VENDOR                0x0001
+#define FW_MATCH_MODEL         0x0002
+#define FW_MATCH_SPECIFIER_ID  0x0004
+#define FW_MATCH_VERSION       0x0008
+
+struct fw_device_id {
+       u32 match_flags;
+       u32 vendor;
+       u32 model;
+       u32 specifier_id;
+       u32 version;
+       void *driver_data;
+};
+
+struct fw_driver {
+       struct device_driver driver;
+       /* Called when the parent device sits through a bus reset. */
+       void (*update) (struct fw_unit *unit);
+       const struct fw_device_id *id_table;
+};
+
+static inline struct fw_driver *
+fw_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct fw_driver, driver);
+}
+
+extern const struct file_operations fw_device_ops;
+
+#endif /* __fw_device_h */
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c
new file mode 100644 (file)
index 0000000..2b640e9
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Isochronous IO functionality
+ *
+ * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+int
+fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+                  int page_count, enum dma_data_direction direction)
+{
+       int i, j, retval = -ENOMEM;
+       dma_addr_t address;
+
+       buffer->page_count = page_count;
+       buffer->direction = direction;
+
+       buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
+                               GFP_KERNEL);
+       if (buffer->pages == NULL)
+               goto out;
+
+       for (i = 0; i < buffer->page_count; i++) {
+               buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+               if (buffer->pages[i] == NULL)
+                       goto out_pages;
+
+               address = dma_map_page(card->device, buffer->pages[i],
+                                      0, PAGE_SIZE, direction);
+               if (dma_mapping_error(address)) {
+                       __free_page(buffer->pages[i]);
+                       goto out_pages;
+               }
+               set_page_private(buffer->pages[i], address);
+       }
+
+       return 0;
+
+ out_pages:
+       for (j = 0; j < i; j++) {
+               address = page_private(buffer->pages[j]);
+               dma_unmap_page(card->device, address,
+                              PAGE_SIZE, DMA_TO_DEVICE);
+               __free_page(buffer->pages[j]);
+       }
+       kfree(buffer->pages);
+ out:
+       buffer->pages = NULL;
+       return retval;
+}
+
+int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
+{
+       unsigned long uaddr;
+       int i, retval;
+
+       uaddr = vma->vm_start;
+       for (i = 0; i < buffer->page_count; i++) {
+               retval = vm_insert_page(vma, uaddr, buffer->pages[i]);
+               if (retval)
+                       return retval;
+               uaddr += PAGE_SIZE;
+       }
+
+       return 0;
+}
+
+void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
+                          struct fw_card *card)
+{
+       int i;
+       dma_addr_t address;
+
+       for (i = 0; i < buffer->page_count; i++) {
+               address = page_private(buffer->pages[i]);
+               dma_unmap_page(card->device, address,
+                              PAGE_SIZE, DMA_TO_DEVICE);
+               __free_page(buffer->pages[i]);
+       }
+
+       kfree(buffer->pages);
+       buffer->pages = NULL;
+}
+
+struct fw_iso_context *
+fw_iso_context_create(struct fw_card *card, int type,
+                     int channel, int speed, size_t header_size,
+                     fw_iso_callback_t callback, void *callback_data)
+{
+       struct fw_iso_context *ctx;
+
+       ctx = card->driver->allocate_iso_context(card, type, header_size);
+       if (IS_ERR(ctx))
+               return ctx;
+
+       ctx->card = card;
+       ctx->type = type;
+       ctx->channel = channel;
+       ctx->speed = speed;
+       ctx->header_size = header_size;
+       ctx->callback = callback;
+       ctx->callback_data = callback_data;
+
+       return ctx;
+}
+EXPORT_SYMBOL(fw_iso_context_create);
+
+void fw_iso_context_destroy(struct fw_iso_context *ctx)
+{
+       struct fw_card *card = ctx->card;
+
+       card->driver->free_iso_context(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_destroy);
+
+int
+fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags)
+{
+       return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
+}
+EXPORT_SYMBOL(fw_iso_context_start);
+
+int
+fw_iso_context_queue(struct fw_iso_context *ctx,
+                    struct fw_iso_packet *packet,
+                    struct fw_iso_buffer *buffer,
+                    unsigned long payload)
+{
+       struct fw_card *card = ctx->card;
+
+       return card->driver->queue_iso(ctx, packet, buffer, payload);
+}
+EXPORT_SYMBOL(fw_iso_context_queue);
+
+int
+fw_iso_context_stop(struct fw_iso_context *ctx)
+{
+       return ctx->card->driver->stop_iso(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_stop);
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
new file mode 100644 (file)
index 0000000..1f5c704
--- /dev/null
@@ -0,0 +1,1943 @@
+/*
+ * Driver for OHCI 1394 controllers
+ *
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "fw-transaction.h"
+#include "fw-ohci.h"
+
+#define DESCRIPTOR_OUTPUT_MORE         0
+#define DESCRIPTOR_OUTPUT_LAST         (1 << 12)
+#define DESCRIPTOR_INPUT_MORE          (2 << 12)
+#define DESCRIPTOR_INPUT_LAST          (3 << 12)
+#define DESCRIPTOR_STATUS              (1 << 11)
+#define DESCRIPTOR_KEY_IMMEDIATE       (2 << 8)
+#define DESCRIPTOR_PING                        (1 << 7)
+#define DESCRIPTOR_YY                  (1 << 6)
+#define DESCRIPTOR_NO_IRQ              (0 << 4)
+#define DESCRIPTOR_IRQ_ERROR           (1 << 4)
+#define DESCRIPTOR_IRQ_ALWAYS          (3 << 4)
+#define DESCRIPTOR_BRANCH_ALWAYS       (3 << 2)
+#define DESCRIPTOR_WAIT                        (3 << 0)
+
+struct descriptor {
+       __le16 req_count;
+       __le16 control;
+       __le32 data_address;
+       __le32 branch_address;
+       __le16 res_count;
+       __le16 transfer_status;
+} __attribute__((aligned(16)));
+
+struct db_descriptor {
+       __le16 first_size;
+       __le16 control;
+       __le16 second_req_count;
+       __le16 first_req_count;
+       __le32 branch_address;
+       __le16 second_res_count;
+       __le16 first_res_count;
+       __le32 reserved0;
+       __le32 first_buffer;
+       __le32 second_buffer;
+       __le32 reserved1;
+} __attribute__((aligned(16)));
+
+#define CONTROL_SET(regs)      (regs)
+#define CONTROL_CLEAR(regs)    ((regs) + 4)
+#define COMMAND_PTR(regs)      ((regs) + 12)
+#define CONTEXT_MATCH(regs)    ((regs) + 16)
+
+struct ar_buffer {
+       struct descriptor descriptor;
+       struct ar_buffer *next;
+       __le32 data[0];
+};
+
+struct ar_context {
+       struct fw_ohci *ohci;
+       struct ar_buffer *current_buffer;
+       struct ar_buffer *last_buffer;
+       void *pointer;
+       u32 regs;
+       struct tasklet_struct tasklet;
+};
+
+struct context;
+
+typedef int (*descriptor_callback_t)(struct context *ctx,
+                                    struct descriptor *d,
+                                    struct descriptor *last);
+struct context {
+       struct fw_ohci *ohci;
+       u32 regs;
+
+       struct descriptor *buffer;
+       dma_addr_t buffer_bus;
+       size_t buffer_size;
+       struct descriptor *head_descriptor;
+       struct descriptor *tail_descriptor;
+       struct descriptor *tail_descriptor_last;
+       struct descriptor *prev_descriptor;
+
+       descriptor_callback_t callback;
+
+       struct tasklet_struct tasklet;
+};
+
+#define IT_HEADER_SY(v)          ((v) <<  0)
+#define IT_HEADER_TCODE(v)       ((v) <<  4)
+#define IT_HEADER_CHANNEL(v)     ((v) <<  8)
+#define IT_HEADER_TAG(v)         ((v) << 14)
+#define IT_HEADER_SPEED(v)       ((v) << 16)
+#define IT_HEADER_DATA_LENGTH(v) ((v) << 16)
+
+struct iso_context {
+       struct fw_iso_context base;
+       struct context context;
+       void *header;
+       size_t header_length;
+};
+
+#define CONFIG_ROM_SIZE 1024
+
+struct fw_ohci {
+       struct fw_card card;
+
+       u32 version;
+       __iomem char *registers;
+       dma_addr_t self_id_bus;
+       __le32 *self_id_cpu;
+       struct tasklet_struct bus_reset_tasklet;
+       int node_id;
+       int generation;
+       int request_generation;
+       u32 bus_seconds;
+
+       /*
+        * Spinlock for accessing fw_ohci data.  Never call out of
+        * this driver with this lock held.
+        */
+       spinlock_t lock;
+       u32 self_id_buffer[512];
+
+       /* Config rom buffers */
+       __be32 *config_rom;
+       dma_addr_t config_rom_bus;
+       __be32 *next_config_rom;
+       dma_addr_t next_config_rom_bus;
+       u32 next_header;
+
+       struct ar_context ar_request_ctx;
+       struct ar_context ar_response_ctx;
+       struct context at_request_ctx;
+       struct context at_response_ctx;
+
+       u32 it_context_mask;
+       struct iso_context *it_context_list;
+       u32 ir_context_mask;
+       struct iso_context *ir_context_list;
+};
+
+static inline struct fw_ohci *fw_ohci(struct fw_card *card)
+{
+       return container_of(card, struct fw_ohci, card);
+}
+
+#define IT_CONTEXT_CYCLE_MATCH_ENABLE  0x80000000
+#define IR_CONTEXT_BUFFER_FILL         0x80000000
+#define IR_CONTEXT_ISOCH_HEADER                0x40000000
+#define IR_CONTEXT_CYCLE_MATCH_ENABLE  0x20000000
+#define IR_CONTEXT_MULTI_CHANNEL_MODE  0x10000000
+#define IR_CONTEXT_DUAL_BUFFER_MODE    0x08000000
+
+#define CONTEXT_RUN    0x8000
+#define CONTEXT_WAKE   0x1000
+#define CONTEXT_DEAD   0x0800
+#define CONTEXT_ACTIVE 0x0400
+
+#define OHCI1394_MAX_AT_REQ_RETRIES    0x2
+#define OHCI1394_MAX_AT_RESP_RETRIES   0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
+#define FW_OHCI_MAJOR                  240
+#define OHCI1394_REGISTER_SIZE         0x800
+#define OHCI_LOOP_COUNT                        500
+#define OHCI1394_PCI_HCI_Control       0x40
+#define SELF_ID_BUF_SIZE               0x800
+#define OHCI_TCODE_PHY_PACKET          0x0e
+#define OHCI_VERSION_1_1               0x010010
+#define ISO_BUFFER_SIZE                        (64 * 1024)
+#define AT_BUFFER_SIZE                 4096
+
+static char ohci_driver_name[] = KBUILD_MODNAME;
+
+static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data)
+{
+       writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct fw_ohci *ohci, int offset)
+{
+       return readl(ohci->registers + offset);
+}
+
+static inline void flush_writes(const struct fw_ohci *ohci)
+{
+       /* Do a dummy read to flush writes. */
+       reg_read(ohci, OHCI1394_Version);
+}
+
+static int
+ohci_update_phy_reg(struct fw_card *card, int addr,
+                   int clear_bits, int set_bits)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       u32 val, old;
+
+       reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+       msleep(2);
+       val = reg_read(ohci, OHCI1394_PhyControl);
+       if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
+               fw_error("failed to set phy reg bits.\n");
+               return -EBUSY;
+       }
+
+       old = OHCI1394_PhyControl_ReadData(val);
+       old = (old & ~clear_bits) | set_bits;
+       reg_write(ohci, OHCI1394_PhyControl,
+                 OHCI1394_PhyControl_Write(addr, old));
+
+       return 0;
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+       struct device *dev = ctx->ohci->card.device;
+       struct ar_buffer *ab;
+       dma_addr_t ab_bus;
+       size_t offset;
+
+       ab = (struct ar_buffer *) __get_free_page(GFP_ATOMIC);
+       if (ab == NULL)
+               return -ENOMEM;
+
+       ab_bus = dma_map_single(dev, ab, PAGE_SIZE, DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(ab_bus)) {
+               free_page((unsigned long) ab);
+               return -ENOMEM;
+       }
+
+       memset(&ab->descriptor, 0, sizeof(ab->descriptor));
+       ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
+                                                   DESCRIPTOR_STATUS |
+                                                   DESCRIPTOR_BRANCH_ALWAYS);
+       offset = offsetof(struct ar_buffer, data);
+       ab->descriptor.req_count      = cpu_to_le16(PAGE_SIZE - offset);
+       ab->descriptor.data_address   = cpu_to_le32(ab_bus + offset);
+       ab->descriptor.res_count      = cpu_to_le16(PAGE_SIZE - offset);
+       ab->descriptor.branch_address = 0;
+
+       dma_sync_single_for_device(dev, ab_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+       ctx->last_buffer->descriptor.branch_address = ab_bus | 1;
+       ctx->last_buffer->next = ab;
+       ctx->last_buffer = ab;
+
+       reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+       flush_writes(ctx->ohci);
+
+       return 0;
+}
+
+static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
+{
+       struct fw_ohci *ohci = ctx->ohci;
+       struct fw_packet p;
+       u32 status, length, tcode;
+
+       p.header[0] = le32_to_cpu(buffer[0]);
+       p.header[1] = le32_to_cpu(buffer[1]);
+       p.header[2] = le32_to_cpu(buffer[2]);
+
+       tcode = (p.header[0] >> 4) & 0x0f;
+       switch (tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_READ_QUADLET_RESPONSE:
+               p.header[3] = (__force __u32) buffer[3];
+               p.header_length = 16;
+               p.payload_length = 0;
+               break;
+
+       case TCODE_READ_BLOCK_REQUEST :
+               p.header[3] = le32_to_cpu(buffer[3]);
+               p.header_length = 16;
+               p.payload_length = 0;
+               break;
+
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_READ_BLOCK_RESPONSE:
+       case TCODE_LOCK_REQUEST:
+       case TCODE_LOCK_RESPONSE:
+               p.header[3] = le32_to_cpu(buffer[3]);
+               p.header_length = 16;
+               p.payload_length = p.header[3] >> 16;
+               break;
+
+       case TCODE_WRITE_RESPONSE:
+       case TCODE_READ_QUADLET_REQUEST:
+       case OHCI_TCODE_PHY_PACKET:
+               p.header_length = 12;
+               p.payload_length = 0;
+               break;
+       }
+
+       p.payload = (void *) buffer + p.header_length;
+
+       /* FIXME: What to do about evt_* errors? */
+       length = (p.header_length + p.payload_length + 3) / 4;
+       status = le32_to_cpu(buffer[length]);
+
+       p.ack        = ((status >> 16) & 0x1f) - 16;
+       p.speed      = (status >> 21) & 0x7;
+       p.timestamp  = status & 0xffff;
+       p.generation = ohci->request_generation;
+
+       /*
+        * The OHCI bus reset handler synthesizes a phy packet with
+        * the new generation number when a bus reset happens (see
+        * section 8.4.2.3).  This helps us determine when a request
+        * was received and make sure we send the response in the same
+        * generation.  We only need this for requests; for responses
+        * we use the unique tlabel for finding the matching
+        * request.
+        */
+
+       if (p.ack + 16 == 0x09)
+               ohci->request_generation = (buffer[2] >> 16) & 0xff;
+       else if (ctx == &ohci->ar_request_ctx)
+               fw_core_handle_request(&ohci->card, &p);
+       else
+               fw_core_handle_response(&ohci->card, &p);
+
+       return buffer + length + 1;
+}
+
+static void ar_context_tasklet(unsigned long data)
+{
+       struct ar_context *ctx = (struct ar_context *)data;
+       struct fw_ohci *ohci = ctx->ohci;
+       struct ar_buffer *ab;
+       struct descriptor *d;
+       void *buffer, *end;
+
+       ab = ctx->current_buffer;
+       d = &ab->descriptor;
+
+       if (d->res_count == 0) {
+               size_t size, rest, offset;
+
+               /*
+                * This descriptor is finished and we may have a
+                * packet split across this and the next buffer. We
+                * reuse the page for reassembling the split packet.
+                */
+
+               offset = offsetof(struct ar_buffer, data);
+               dma_unmap_single(ohci->card.device,
+                                ab->descriptor.data_address - offset,
+                                PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+               buffer = ab;
+               ab = ab->next;
+               d = &ab->descriptor;
+               size = buffer + PAGE_SIZE - ctx->pointer;
+               rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+               memmove(buffer, ctx->pointer, size);
+               memcpy(buffer + size, ab->data, rest);
+               ctx->current_buffer = ab;
+               ctx->pointer = (void *) ab->data + rest;
+               end = buffer + size + rest;
+
+               while (buffer < end)
+                       buffer = handle_ar_packet(ctx, buffer);
+
+               free_page((unsigned long)buffer);
+               ar_context_add_page(ctx);
+       } else {
+               buffer = ctx->pointer;
+               ctx->pointer = end =
+                       (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+
+               while (buffer < end)
+                       buffer = handle_ar_packet(ctx, buffer);
+       }
+}
+
+static int
+ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs)
+{
+       struct ar_buffer ab;
+
+       ctx->regs        = regs;
+       ctx->ohci        = ohci;
+       ctx->last_buffer = &ab;
+       tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx);
+
+       ar_context_add_page(ctx);
+       ar_context_add_page(ctx);
+       ctx->current_buffer = ab.next;
+       ctx->pointer = ctx->current_buffer->data;
+
+       reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab.descriptor.branch_address);
+       reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN);
+       flush_writes(ctx->ohci);
+
+       return 0;
+}
+
+static void context_tasklet(unsigned long data)
+{
+       struct context *ctx = (struct context *) data;
+       struct fw_ohci *ohci = ctx->ohci;
+       struct descriptor *d, *last;
+       u32 address;
+       int z;
+
+       dma_sync_single_for_cpu(ohci->card.device, ctx->buffer_bus,
+                               ctx->buffer_size, DMA_TO_DEVICE);
+
+       d    = ctx->tail_descriptor;
+       last = ctx->tail_descriptor_last;
+
+       while (last->branch_address != 0) {
+               address = le32_to_cpu(last->branch_address);
+               z = address & 0xf;
+               d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d);
+               last = (z == 2) ? d : d + z - 1;
+
+               if (!ctx->callback(ctx, d, last))
+                       break;
+
+               ctx->tail_descriptor      = d;
+               ctx->tail_descriptor_last = last;
+       }
+}
+
+static int
+context_init(struct context *ctx, struct fw_ohci *ohci,
+            size_t buffer_size, u32 regs,
+            descriptor_callback_t callback)
+{
+       ctx->ohci = ohci;
+       ctx->regs = regs;
+       ctx->buffer_size = buffer_size;
+       ctx->buffer = kmalloc(buffer_size, GFP_KERNEL);
+       if (ctx->buffer == NULL)
+               return -ENOMEM;
+
+       tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx);
+       ctx->callback = callback;
+
+       ctx->buffer_bus =
+               dma_map_single(ohci->card.device, ctx->buffer,
+                              buffer_size, DMA_TO_DEVICE);
+       if (dma_mapping_error(ctx->buffer_bus)) {
+               kfree(ctx->buffer);
+               return -ENOMEM;
+       }
+
+       ctx->head_descriptor      = ctx->buffer;
+       ctx->prev_descriptor      = ctx->buffer;
+       ctx->tail_descriptor      = ctx->buffer;
+       ctx->tail_descriptor_last = ctx->buffer;
+
+       /*
+        * We put a dummy descriptor in the buffer that has a NULL
+        * branch address and looks like it's been sent.  That way we
+        * have a descriptor to append DMA programs to.  Also, the
+        * ring buffer invariant is that it always has at least one
+        * element so that head == tail means buffer full.
+        */
+
+       memset(ctx->head_descriptor, 0, sizeof(*ctx->head_descriptor));
+       ctx->head_descriptor->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST);
+       ctx->head_descriptor->transfer_status = cpu_to_le16(0x8011);
+       ctx->head_descriptor++;
+
+       return 0;
+}
+
+static void
+context_release(struct context *ctx)
+{
+       struct fw_card *card = &ctx->ohci->card;
+
+       dma_unmap_single(card->device, ctx->buffer_bus,
+                        ctx->buffer_size, DMA_TO_DEVICE);
+       kfree(ctx->buffer);
+}
+
+static struct descriptor *
+context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus)
+{
+       struct descriptor *d, *tail, *end;
+
+       d = ctx->head_descriptor;
+       tail = ctx->tail_descriptor;
+       end = ctx->buffer + ctx->buffer_size / sizeof(*d);
+
+       if (d + z <= tail) {
+               goto has_space;
+       } else if (d > tail && d + z <= end) {
+               goto has_space;
+       } else if (d > tail && ctx->buffer + z <= tail) {
+               d = ctx->buffer;
+               goto has_space;
+       }
+
+       return NULL;
+
+ has_space:
+       memset(d, 0, z * sizeof(*d));
+       *d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+
+       return d;
+}
+
+static void context_run(struct context *ctx, u32 extra)
+{
+       struct fw_ohci *ohci = ctx->ohci;
+
+       reg_write(ohci, COMMAND_PTR(ctx->regs),
+                 le32_to_cpu(ctx->tail_descriptor_last->branch_address));
+       reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
+       reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
+       flush_writes(ohci);
+}
+
+static void context_append(struct context *ctx,
+                          struct descriptor *d, int z, int extra)
+{
+       dma_addr_t d_bus;
+
+       d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+
+       ctx->head_descriptor = d + z + extra;
+       ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z);
+       ctx->prev_descriptor = z == 2 ? d : d + z - 1;
+
+       dma_sync_single_for_device(ctx->ohci->card.device, ctx->buffer_bus,
+                                  ctx->buffer_size, DMA_TO_DEVICE);
+
+       reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+       flush_writes(ctx->ohci);
+}
+
+static void context_stop(struct context *ctx)
+{
+       u32 reg;
+       int i;
+
+       reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+       flush_writes(ctx->ohci);
+
+       for (i = 0; i < 10; i++) {
+               reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
+               if ((reg & CONTEXT_ACTIVE) == 0)
+                       break;
+
+               fw_notify("context_stop: still active (0x%08x)\n", reg);
+               msleep(1);
+       }
+}
+
+struct driver_data {
+       struct fw_packet *packet;
+};
+
+/*
+ * This function apppends a packet to the DMA queue for transmission.
+ * Must always be called with the ochi->lock held to ensure proper
+ * generation handling and locking around packet queue manipulation.
+ */
+static int
+at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
+{
+       struct fw_ohci *ohci = ctx->ohci;
+       dma_addr_t d_bus, payload_bus;
+       struct driver_data *driver_data;
+       struct descriptor *d, *last;
+       __le32 *header;
+       int z, tcode;
+       u32 reg;
+
+       d = context_get_descriptors(ctx, 4, &d_bus);
+       if (d == NULL) {
+               packet->ack = RCODE_SEND_ERROR;
+               return -1;
+       }
+
+       d[0].control   = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
+       d[0].res_count = cpu_to_le16(packet->timestamp);
+
+       /*
+        * The DMA format for asyncronous link packets is different
+        * from the IEEE1394 layout, so shift the fields around
+        * accordingly.  If header_length is 8, it's a PHY packet, to
+        * which we need to prepend an extra quadlet.
+        */
+
+       header = (__le32 *) &d[1];
+       if (packet->header_length > 8) {
+               header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
+                                       (packet->speed << 16));
+               header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
+                                       (packet->header[0] & 0xffff0000));
+               header[2] = cpu_to_le32(packet->header[2]);
+
+               tcode = (packet->header[0] >> 4) & 0x0f;
+               if (TCODE_IS_BLOCK_PACKET(tcode))
+                       header[3] = cpu_to_le32(packet->header[3]);
+               else
+                       header[3] = (__force __le32) packet->header[3];
+
+               d[0].req_count = cpu_to_le16(packet->header_length);
+       } else {
+               header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
+                                       (packet->speed << 16));
+               header[1] = cpu_to_le32(packet->header[0]);
+               header[2] = cpu_to_le32(packet->header[1]);
+               d[0].req_count = cpu_to_le16(12);
+       }
+
+       driver_data = (struct driver_data *) &d[3];
+       driver_data->packet = packet;
+       packet->driver_data = driver_data;
+       
+       if (packet->payload_length > 0) {
+               payload_bus =
+                       dma_map_single(ohci->card.device, packet->payload,
+                                      packet->payload_length, DMA_TO_DEVICE);
+               if (dma_mapping_error(payload_bus)) {
+                       packet->ack = RCODE_SEND_ERROR;
+                       return -1;
+               }
+
+               d[2].req_count    = cpu_to_le16(packet->payload_length);
+               d[2].data_address = cpu_to_le32(payload_bus);
+               last = &d[2];
+               z = 3;
+       } else {
+               last = &d[0];
+               z = 2;
+       }
+
+       last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST |
+                                    DESCRIPTOR_IRQ_ALWAYS |
+                                    DESCRIPTOR_BRANCH_ALWAYS);
+
+       /* FIXME: Document how the locking works. */
+       if (ohci->generation != packet->generation) {
+               packet->ack = RCODE_GENERATION;
+               return -1;
+       }
+
+       context_append(ctx, d, z, 4 - z);
+
+       /* If the context isn't already running, start it up. */
+       reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
+       if ((reg & CONTEXT_RUN) == 0)
+               context_run(ctx, 0);
+
+       return 0;
+}
+
+static int handle_at_packet(struct context *context,
+                           struct descriptor *d,
+                           struct descriptor *last)
+{
+       struct driver_data *driver_data;
+       struct fw_packet *packet;
+       struct fw_ohci *ohci = context->ohci;
+       dma_addr_t payload_bus;
+       int evt;
+
+       if (last->transfer_status == 0)
+               /* This descriptor isn't done yet, stop iteration. */
+               return 0;
+
+       driver_data = (struct driver_data *) &d[3];
+       packet = driver_data->packet;
+       if (packet == NULL)
+               /* This packet was cancelled, just continue. */
+               return 1;
+
+       payload_bus = le32_to_cpu(last->data_address);
+       if (payload_bus != 0)
+               dma_unmap_single(ohci->card.device, payload_bus,
+                                packet->payload_length, DMA_TO_DEVICE);
+
+       evt = le16_to_cpu(last->transfer_status) & 0x1f;
+       packet->timestamp = le16_to_cpu(last->res_count);
+
+       switch (evt) {
+       case OHCI1394_evt_timeout:
+               /* Async response transmit timed out. */
+               packet->ack = RCODE_CANCELLED;
+               break;
+
+       case OHCI1394_evt_flushed:
+               /*
+                * The packet was flushed should give same error as
+                * when we try to use a stale generation count.
+                */
+               packet->ack = RCODE_GENERATION;
+               break;
+
+       case OHCI1394_evt_missing_ack:
+               /*
+                * Using a valid (current) generation count, but the
+                * node is not on the bus or not sending acks.
+                */
+               packet->ack = RCODE_NO_ACK;
+               break;
+
+       case ACK_COMPLETE + 0x10:
+       case ACK_PENDING + 0x10:
+       case ACK_BUSY_X + 0x10:
+       case ACK_BUSY_A + 0x10:
+       case ACK_BUSY_B + 0x10:
+       case ACK_DATA_ERROR + 0x10:
+       case ACK_TYPE_ERROR + 0x10:
+               packet->ack = evt - 0x10;
+               break;
+
+       default:
+               packet->ack = RCODE_SEND_ERROR;
+               break;
+       }
+
+       packet->callback(packet, &ohci->card, packet->ack);
+
+       return 1;
+}
+
+#define HEADER_GET_DESTINATION(q)      (((q) >> 16) & 0xffff)
+#define HEADER_GET_TCODE(q)            (((q) >> 4) & 0x0f)
+#define HEADER_GET_OFFSET_HIGH(q)      (((q) >> 0) & 0xffff)
+#define HEADER_GET_DATA_LENGTH(q)      (((q) >> 16) & 0xffff)
+#define HEADER_GET_EXTENDED_TCODE(q)   (((q) >> 0) & 0xffff)
+
+static void
+handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+{
+       struct fw_packet response;
+       int tcode, length, i;
+
+       tcode = HEADER_GET_TCODE(packet->header[0]);
+       if (TCODE_IS_BLOCK_PACKET(tcode))
+               length = HEADER_GET_DATA_LENGTH(packet->header[3]);
+       else
+               length = 4;
+
+       i = csr - CSR_CONFIG_ROM;
+       if (i + length > CONFIG_ROM_SIZE) {
+               fw_fill_response(&response, packet->header,
+                                RCODE_ADDRESS_ERROR, NULL, 0);
+       } else if (!TCODE_IS_READ_REQUEST(tcode)) {
+               fw_fill_response(&response, packet->header,
+                                RCODE_TYPE_ERROR, NULL, 0);
+       } else {
+               fw_fill_response(&response, packet->header, RCODE_COMPLETE,
+                                (void *) ohci->config_rom + i, length);
+       }
+
+       fw_core_handle_response(&ohci->card, &response);
+}
+
+static void
+handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+{
+       struct fw_packet response;
+       int tcode, length, ext_tcode, sel;
+       __be32 *payload, lock_old;
+       u32 lock_arg, lock_data;
+
+       tcode = HEADER_GET_TCODE(packet->header[0]);
+       length = HEADER_GET_DATA_LENGTH(packet->header[3]);
+       payload = packet->payload;
+       ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]);
+
+       if (tcode == TCODE_LOCK_REQUEST &&
+           ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) {
+               lock_arg = be32_to_cpu(payload[0]);
+               lock_data = be32_to_cpu(payload[1]);
+       } else if (tcode == TCODE_READ_QUADLET_REQUEST) {
+               lock_arg = 0;
+               lock_data = 0;
+       } else {
+               fw_fill_response(&response, packet->header,
+                                RCODE_TYPE_ERROR, NULL, 0);
+               goto out;
+       }
+
+       sel = (csr - CSR_BUS_MANAGER_ID) / 4;
+       reg_write(ohci, OHCI1394_CSRData, lock_data);
+       reg_write(ohci, OHCI1394_CSRCompareData, lock_arg);
+       reg_write(ohci, OHCI1394_CSRControl, sel);
+
+       if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
+               lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData));
+       else
+               fw_notify("swap not done yet\n");
+
+       fw_fill_response(&response, packet->header,
+                        RCODE_COMPLETE, &lock_old, sizeof(lock_old));
+ out:
+       fw_core_handle_response(&ohci->card, &response);
+}
+
+static void
+handle_local_request(struct context *ctx, struct fw_packet *packet)
+{
+       u64 offset;
+       u32 csr;
+
+       if (ctx == &ctx->ohci->at_request_ctx) {
+               packet->ack = ACK_PENDING;
+               packet->callback(packet, &ctx->ohci->card, packet->ack);
+       }
+
+       offset =
+               ((unsigned long long)
+                HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) |
+               packet->header[2];
+       csr = offset - CSR_REGISTER_BASE;
+
+       /* Handle config rom reads. */
+       if (csr >= CSR_CONFIG_ROM && csr < CSR_CONFIG_ROM_END)
+               handle_local_rom(ctx->ohci, packet, csr);
+       else switch (csr) {
+       case CSR_BUS_MANAGER_ID:
+       case CSR_BANDWIDTH_AVAILABLE:
+       case CSR_CHANNELS_AVAILABLE_HI:
+       case CSR_CHANNELS_AVAILABLE_LO:
+               handle_local_lock(ctx->ohci, packet, csr);
+               break;
+       default:
+               if (ctx == &ctx->ohci->at_request_ctx)
+                       fw_core_handle_request(&ctx->ohci->card, packet);
+               else
+                       fw_core_handle_response(&ctx->ohci->card, packet);
+               break;
+       }
+
+       if (ctx == &ctx->ohci->at_response_ctx) {
+               packet->ack = ACK_COMPLETE;
+               packet->callback(packet, &ctx->ohci->card, packet->ack);
+       }
+}
+
+static void
+at_context_transmit(struct context *ctx, struct fw_packet *packet)
+{
+       unsigned long flags;
+       int retval;
+
+       spin_lock_irqsave(&ctx->ohci->lock, flags);
+
+       if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id &&
+           ctx->ohci->generation == packet->generation) {
+               spin_unlock_irqrestore(&ctx->ohci->lock, flags);
+               handle_local_request(ctx, packet);
+               return;
+       }
+
+       retval = at_context_queue_packet(ctx, packet);
+       spin_unlock_irqrestore(&ctx->ohci->lock, flags);
+
+       if (retval < 0)
+               packet->callback(packet, &ctx->ohci->card, packet->ack);
+       
+}
+
+static void bus_reset_tasklet(unsigned long data)
+{
+       struct fw_ohci *ohci = (struct fw_ohci *)data;
+       int self_id_count, i, j, reg;
+       int generation, new_generation;
+       unsigned long flags;
+
+       reg = reg_read(ohci, OHCI1394_NodeID);
+       if (!(reg & OHCI1394_NodeID_idValid)) {
+               fw_error("node ID not valid, new bus reset in progress\n");
+               return;
+       }
+       ohci->node_id = reg & 0xffff;
+
+       /*
+        * The count in the SelfIDCount register is the number of
+        * bytes in the self ID receive buffer.  Since we also receive
+        * the inverted quadlets and a header quadlet, we shift one
+        * bit extra to get the actual number of self IDs.
+        */
+
+       self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff;
+       generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
+
+       for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
+               if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1])
+                       fw_error("inconsistent self IDs\n");
+               ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]);
+       }
+
+       /*
+        * Check the consistency of the self IDs we just read.  The
+        * problem we face is that a new bus reset can start while we
+        * read out the self IDs from the DMA buffer. If this happens,
+        * the DMA buffer will be overwritten with new self IDs and we
+        * will read out inconsistent data.  The OHCI specification
+        * (section 11.2) recommends a technique similar to
+        * linux/seqlock.h, where we remember the generation of the
+        * self IDs in the buffer before reading them out and compare
+        * it to the current generation after reading them out.  If
+        * the two generations match we know we have a consistent set
+        * of self IDs.
+        */
+
+       new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff;
+       if (new_generation != generation) {
+               fw_notify("recursive bus reset detected, "
+                         "discarding self ids\n");
+               return;
+       }
+
+       /* FIXME: Document how the locking works. */
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       ohci->generation = generation;
+       context_stop(&ohci->at_request_ctx);
+       context_stop(&ohci->at_response_ctx);
+       reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+
+       /*
+        * This next bit is unrelated to the AT context stuff but we
+        * have to do it under the spinlock also.  If a new config rom
+        * was set up before this reset, the old one is now no longer
+        * in use and we can free it. Update the config rom pointers
+        * to point to the current config rom and clear the
+        * next_config_rom pointer so a new udpate can take place.
+        */
+
+       if (ohci->next_config_rom != NULL) {
+               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                 ohci->config_rom, ohci->config_rom_bus);
+               ohci->config_rom      = ohci->next_config_rom;
+               ohci->config_rom_bus  = ohci->next_config_rom_bus;
+               ohci->next_config_rom = NULL;
+
+               /*
+                * Restore config_rom image and manually update
+                * config_rom registers.  Writing the header quadlet
+                * will indicate that the config rom is ready, so we
+                * do that last.
+                */
+               reg_write(ohci, OHCI1394_BusOptions,
+                         be32_to_cpu(ohci->config_rom[2]));
+               ohci->config_rom[0] = cpu_to_be32(ohci->next_header);
+               reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header);
+       }
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
+                                self_id_count, ohci->self_id_buffer);
+}
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+       struct fw_ohci *ohci = data;
+       u32 event, iso_event, cycle_time;
+       int i;
+
+       event = reg_read(ohci, OHCI1394_IntEventClear);
+
+       if (!event)
+               return IRQ_NONE;
+
+       reg_write(ohci, OHCI1394_IntEventClear, event);
+
+       if (event & OHCI1394_selfIDComplete)
+               tasklet_schedule(&ohci->bus_reset_tasklet);
+
+       if (event & OHCI1394_RQPkt)
+               tasklet_schedule(&ohci->ar_request_ctx.tasklet);
+
+       if (event & OHCI1394_RSPkt)
+               tasklet_schedule(&ohci->ar_response_ctx.tasklet);
+
+       if (event & OHCI1394_reqTxComplete)
+               tasklet_schedule(&ohci->at_request_ctx.tasklet);
+
+       if (event & OHCI1394_respTxComplete)
+               tasklet_schedule(&ohci->at_response_ctx.tasklet);
+
+       iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
+       reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
+
+       while (iso_event) {
+               i = ffs(iso_event) - 1;
+               tasklet_schedule(&ohci->ir_context_list[i].context.tasklet);
+               iso_event &= ~(1 << i);
+       }
+
+       iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
+       reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
+
+       while (iso_event) {
+               i = ffs(iso_event) - 1;
+               tasklet_schedule(&ohci->it_context_list[i].context.tasklet);
+               iso_event &= ~(1 << i);
+       }
+
+       if (event & OHCI1394_cycle64Seconds) {
+               cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+               if ((cycle_time & 0x80000000) == 0)
+                       ohci->bus_seconds++;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       struct pci_dev *dev = to_pci_dev(card->device);
+
+       /*
+        * When the link is not yet enabled, the atomic config rom
+        * update mechanism described below in ohci_set_config_rom()
+        * is not active.  We have to update ConfigRomHeader and
+        * BusOptions manually, and the write to ConfigROMmap takes
+        * effect immediately.  We tie this to the enabling of the
+        * link, so we have a valid config rom before enabling - the
+        * OHCI requires that ConfigROMhdr and BusOptions have valid
+        * values before enabling.
+        *
+        * However, when the ConfigROMmap is written, some controllers
+        * always read back quadlets 0 and 2 from the config rom to
+        * the ConfigRomHeader and BusOptions registers on bus reset.
+        * They shouldn't do that in this initial case where the link
+        * isn't enabled.  This means we have to use the same
+        * workaround here, setting the bus header to 0 and then write
+        * the right values in the bus reset tasklet.
+        */
+
+       ohci->next_config_rom =
+               dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                  &ohci->next_config_rom_bus, GFP_KERNEL);
+       if (ohci->next_config_rom == NULL)
+               return -ENOMEM;
+
+       memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
+       fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+
+       ohci->next_header = config_rom[0];
+       ohci->next_config_rom[0] = 0;
+       reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
+       reg_write(ohci, OHCI1394_BusOptions, config_rom[2]);
+       reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
+
+       reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+       if (request_irq(dev->irq, irq_handler,
+                       IRQF_SHARED, ohci_driver_name, ohci)) {
+               fw_error("Failed to allocate shared interrupt %d.\n",
+                        dev->irq);
+               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                 ohci->config_rom, ohci->config_rom_bus);
+               return -EIO;
+       }
+
+       reg_write(ohci, OHCI1394_HCControlSet,
+                 OHCI1394_HCControl_linkEnable |
+                 OHCI1394_HCControl_BIBimageValid);
+       flush_writes(ohci);
+
+       /*
+        * We are ready to go, initiate bus reset to finish the
+        * initialization.
+        */
+
+       fw_core_initiate_bus_reset(&ohci->card, 1);
+
+       return 0;
+}
+
+static int
+ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
+{
+       struct fw_ohci *ohci;
+       unsigned long flags;
+       int retval = 0;
+       __be32 *next_config_rom;
+       dma_addr_t next_config_rom_bus;
+
+       ohci = fw_ohci(card);
+
+       /*
+        * When the OHCI controller is enabled, the config rom update
+        * mechanism is a bit tricky, but easy enough to use.  See
+        * section 5.5.6 in the OHCI specification.
+        *
+        * The OHCI controller caches the new config rom address in a
+        * shadow register (ConfigROMmapNext) and needs a bus reset
+        * for the changes to take place.  When the bus reset is
+        * detected, the controller loads the new values for the
+        * ConfigRomHeader and BusOptions registers from the specified
+        * config rom and loads ConfigROMmap from the ConfigROMmapNext
+        * shadow register. All automatically and atomically.
+        *
+        * Now, there's a twist to this story.  The automatic load of
+        * ConfigRomHeader and BusOptions doesn't honor the
+        * noByteSwapData bit, so with a be32 config rom, the
+        * controller will load be32 values in to these registers
+        * during the atomic update, even on litte endian
+        * architectures.  The workaround we use is to put a 0 in the
+        * header quadlet; 0 is endian agnostic and means that the
+        * config rom isn't ready yet.  In the bus reset tasklet we
+        * then set up the real values for the two registers.
+        *
+        * We use ohci->lock to avoid racing with the code that sets
+        * ohci->next_config_rom to NULL (see bus_reset_tasklet).
+        */
+
+       next_config_rom =
+               dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                  &next_config_rom_bus, GFP_KERNEL);
+       if (next_config_rom == NULL)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       if (ohci->next_config_rom == NULL) {
+               ohci->next_config_rom = next_config_rom;
+               ohci->next_config_rom_bus = next_config_rom_bus;
+
+               memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
+               fw_memcpy_to_be32(ohci->next_config_rom, config_rom,
+                                 length * 4);
+
+               ohci->next_header = config_rom[0];
+               ohci->next_config_rom[0] = 0;
+
+               reg_write(ohci, OHCI1394_ConfigROMmap,
+                         ohci->next_config_rom_bus);
+       } else {
+               dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+                                 next_config_rom, next_config_rom_bus);
+               retval = -EBUSY;
+       }
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       /*
+        * Now initiate a bus reset to have the changes take
+        * effect. We clean up the old config rom memory and DMA
+        * mappings in the bus reset tasklet, since the OHCI
+        * controller could need to access it before the bus reset
+        * takes effect.
+        */
+       if (retval == 0)
+               fw_core_initiate_bus_reset(&ohci->card, 1);
+
+       return retval;
+}
+
+static void ohci_send_request(struct fw_card *card, struct fw_packet *packet)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+
+       at_context_transmit(&ohci->at_request_ctx, packet);
+}
+
+static void ohci_send_response(struct fw_card *card, struct fw_packet *packet)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+
+       at_context_transmit(&ohci->at_response_ctx, packet);
+}
+
+static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       struct context *ctx = &ohci->at_request_ctx;
+       struct driver_data *driver_data = packet->driver_data;
+       int retval = -ENOENT;
+
+       tasklet_disable(&ctx->tasklet);
+
+       if (packet->ack != 0)
+               goto out;
+
+       driver_data->packet = NULL;
+       packet->ack = RCODE_CANCELLED;
+       packet->callback(packet, &ohci->card, packet->ack);
+       retval = 0;
+
+ out:
+       tasklet_enable(&ctx->tasklet);
+
+       return retval;
+}
+
+static int
+ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       unsigned long flags;
+       int n, retval = 0;
+
+       /*
+        * FIXME:  Make sure this bitmask is cleared when we clear the busReset
+        * interrupt bit.  Clear physReqResourceAllBuses on bus reset.
+        */
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       if (ohci->generation != generation) {
+               retval = -ESTALE;
+               goto out;
+       }
+
+       /*
+        * Note, if the node ID contains a non-local bus ID, physical DMA is
+        * enabled for _all_ nodes on remote buses.
+        */
+
+       n = (node_id & 0xffc0) == LOCAL_BUS ? node_id & 0x3f : 63;
+       if (n < 32)
+               reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 1 << n);
+       else
+               reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 1 << (n - 32));
+
+       flush_writes(ohci);
+ out:
+       spin_unlock_irqrestore(&ohci->lock, flags);
+       return retval;
+}
+
+static u64
+ohci_get_bus_time(struct fw_card *card)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       u32 cycle_time;
+       u64 bus_time;
+
+       cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+       bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time;
+
+       return bus_time;
+}
+
+static int handle_ir_dualbuffer_packet(struct context *context,
+                                      struct descriptor *d,
+                                      struct descriptor *last)
+{
+       struct iso_context *ctx =
+               container_of(context, struct iso_context, context);
+       struct db_descriptor *db = (struct db_descriptor *) d;
+       __le32 *ir_header;
+       size_t header_length;
+       void *p, *end;
+       int i;
+
+       if (db->first_res_count > 0 && db->second_res_count > 0)
+               /* This descriptor isn't done yet, stop iteration. */
+               return 0;
+
+       header_length = le16_to_cpu(db->first_req_count) -
+               le16_to_cpu(db->first_res_count);
+
+       i = ctx->header_length;
+       p = db + 1;
+       end = p + header_length;
+       while (p < end && i + ctx->base.header_size <= PAGE_SIZE) {
+               /*
+                * The iso header is byteswapped to little endian by
+                * the controller, but the remaining header quadlets
+                * are big endian.  We want to present all the headers
+                * as big endian, so we have to swap the first
+                * quadlet.
+                */
+               *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
+               memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
+               i += ctx->base.header_size;
+               p += ctx->base.header_size + 4;
+       }
+
+       ctx->header_length = i;
+
+       if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) {
+               ir_header = (__le32 *) (db + 1);
+               ctx->base.callback(&ctx->base,
+                                  le32_to_cpu(ir_header[0]) & 0xffff,
+                                  ctx->header_length, ctx->header,
+                                  ctx->base.callback_data);
+               ctx->header_length = 0;
+       }
+
+       return 1;
+}
+
+static int handle_it_packet(struct context *context,
+                           struct descriptor *d,
+                           struct descriptor *last)
+{
+       struct iso_context *ctx =
+               container_of(context, struct iso_context, context);
+
+       if (last->transfer_status == 0)
+               /* This descriptor isn't done yet, stop iteration. */
+               return 0;
+
+       if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
+               ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
+                                  0, NULL, ctx->base.callback_data);
+
+       return 1;
+}
+
+static struct fw_iso_context *
+ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       struct iso_context *ctx, *list;
+       descriptor_callback_t callback;
+       u32 *mask, regs;
+       unsigned long flags;
+       int index, retval = -ENOMEM;
+
+       if (type == FW_ISO_CONTEXT_TRANSMIT) {
+               mask = &ohci->it_context_mask;
+               list = ohci->it_context_list;
+               callback = handle_it_packet;
+       } else {
+               mask = &ohci->ir_context_mask;
+               list = ohci->ir_context_list;
+               callback = handle_ir_dualbuffer_packet;
+       }
+
+       /* FIXME: We need a fallback for pre 1.1 OHCI. */
+       if (callback == handle_ir_dualbuffer_packet &&
+           ohci->version < OHCI_VERSION_1_1)
+               return ERR_PTR(-EINVAL);
+
+       spin_lock_irqsave(&ohci->lock, flags);
+       index = ffs(*mask) - 1;
+       if (index >= 0)
+               *mask &= ~(1 << index);
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       if (index < 0)
+               return ERR_PTR(-EBUSY);
+
+       if (type == FW_ISO_CONTEXT_TRANSMIT)
+               regs = OHCI1394_IsoXmitContextBase(index);
+       else
+               regs = OHCI1394_IsoRcvContextBase(index);
+
+       ctx = &list[index];
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->header_length = 0;
+       ctx->header = (void *) __get_free_page(GFP_KERNEL);
+       if (ctx->header == NULL)
+               goto out;
+
+       retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE,
+                             regs, callback);
+       if (retval < 0)
+               goto out_with_header;
+
+       return &ctx->base;
+
+ out_with_header:
+       free_page((unsigned long)ctx->header);
+ out:
+       spin_lock_irqsave(&ohci->lock, flags);
+       *mask |= 1 << index;
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       return ERR_PTR(retval);
+}
+
+static int ohci_start_iso(struct fw_iso_context *base,
+                         s32 cycle, u32 sync, u32 tags)
+{
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       struct fw_ohci *ohci = ctx->context.ohci;
+       u32 control, match;
+       int index;
+
+       if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+               index = ctx - ohci->it_context_list;
+               match = 0;
+               if (cycle >= 0)
+                       match = IT_CONTEXT_CYCLE_MATCH_ENABLE |
+                               (cycle & 0x7fff) << 16;
+
+               reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index);
+               reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index);
+               context_run(&ctx->context, match);
+       } else {
+               index = ctx - ohci->ir_context_list;
+               control = IR_CONTEXT_DUAL_BUFFER_MODE | IR_CONTEXT_ISOCH_HEADER;
+               match = (tags << 28) | (sync << 8) | ctx->base.channel;
+               if (cycle >= 0) {
+                       match |= (cycle & 0x07fff) << 12;
+                       control |= IR_CONTEXT_CYCLE_MATCH_ENABLE;
+               }
+
+               reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index);
+               reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
+               reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
+               context_run(&ctx->context, control);
+       }
+
+       return 0;
+}
+
+static int ohci_stop_iso(struct fw_iso_context *base)
+{
+       struct fw_ohci *ohci = fw_ohci(base->card);
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       int index;
+
+       if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+               index = ctx - ohci->it_context_list;
+               reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
+       } else {
+               index = ctx - ohci->ir_context_list;
+               reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
+       }
+       flush_writes(ohci);
+       context_stop(&ctx->context);
+
+       return 0;
+}
+
+static void ohci_free_iso_context(struct fw_iso_context *base)
+{
+       struct fw_ohci *ohci = fw_ohci(base->card);
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       unsigned long flags;
+       int index;
+
+       ohci_stop_iso(base);
+       context_release(&ctx->context);
+       free_page((unsigned long)ctx->header);
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+               index = ctx - ohci->it_context_list;
+               ohci->it_context_mask |= 1 << index;
+       } else {
+               index = ctx - ohci->ir_context_list;
+               ohci->ir_context_mask |= 1 << index;
+       }
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
+static int
+ohci_queue_iso_transmit(struct fw_iso_context *base,
+                       struct fw_iso_packet *packet,
+                       struct fw_iso_buffer *buffer,
+                       unsigned long payload)
+{
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       struct descriptor *d, *last, *pd;
+       struct fw_iso_packet *p;
+       __le32 *header;
+       dma_addr_t d_bus, page_bus;
+       u32 z, header_z, payload_z, irq;
+       u32 payload_index, payload_end_index, next_page_index;
+       int page, end_page, i, length, offset;
+
+       /*
+        * FIXME: Cycle lost behavior should be configurable: lose
+        * packet, retransmit or terminate..
+        */
+
+       p = packet;
+       payload_index = payload;
+
+       if (p->skip)
+               z = 1;
+       else
+               z = 2;
+       if (p->header_length > 0)
+               z++;
+
+       /* Determine the first page the payload isn't contained in. */
+       end_page = PAGE_ALIGN(payload_index + p->payload_length) >> PAGE_SHIFT;
+       if (p->payload_length > 0)
+               payload_z = end_page - (payload_index >> PAGE_SHIFT);
+       else
+               payload_z = 0;
+
+       z += payload_z;
+
+       /* Get header size in number of descriptors. */
+       header_z = DIV_ROUND_UP(p->header_length, sizeof(*d));
+
+       d = context_get_descriptors(&ctx->context, z + header_z, &d_bus);
+       if (d == NULL)
+               return -ENOMEM;
+
+       if (!p->skip) {
+               d[0].control   = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
+               d[0].req_count = cpu_to_le16(8);
+
+               header = (__le32 *) &d[1];
+               header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) |
+                                       IT_HEADER_TAG(p->tag) |
+                                       IT_HEADER_TCODE(TCODE_STREAM_DATA) |
+                                       IT_HEADER_CHANNEL(ctx->base.channel) |
+                                       IT_HEADER_SPEED(ctx->base.speed));
+               header[1] =
+                       cpu_to_le32(IT_HEADER_DATA_LENGTH(p->header_length +
+                                                         p->payload_length));
+       }
+
+       if (p->header_length > 0) {
+               d[2].req_count    = cpu_to_le16(p->header_length);
+               d[2].data_address = cpu_to_le32(d_bus + z * sizeof(*d));
+               memcpy(&d[z], p->header, p->header_length);
+       }
+
+       pd = d + z - payload_z;
+       payload_end_index = payload_index + p->payload_length;
+       for (i = 0; i < payload_z; i++) {
+               page               = payload_index >> PAGE_SHIFT;
+               offset             = payload_index & ~PAGE_MASK;
+               next_page_index    = (page + 1) << PAGE_SHIFT;
+               length             =
+                       min(next_page_index, payload_end_index) - payload_index;
+               pd[i].req_count    = cpu_to_le16(length);
+
+               page_bus = page_private(buffer->pages[page]);
+               pd[i].data_address = cpu_to_le32(page_bus + offset);
+
+               payload_index += length;
+       }
+
+       if (p->interrupt)
+               irq = DESCRIPTOR_IRQ_ALWAYS;
+       else
+               irq = DESCRIPTOR_NO_IRQ;
+
+       last = z == 2 ? d : d + z - 1;
+       last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST |
+                                    DESCRIPTOR_STATUS |
+                                    DESCRIPTOR_BRANCH_ALWAYS |
+                                    irq);
+
+       context_append(&ctx->context, d, z, header_z);
+
+       return 0;
+}
+
+static int
+ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
+                                 struct fw_iso_packet *packet,
+                                 struct fw_iso_buffer *buffer,
+                                 unsigned long payload)
+{
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+       struct db_descriptor *db = NULL;
+       struct descriptor *d;
+       struct fw_iso_packet *p;
+       dma_addr_t d_bus, page_bus;
+       u32 z, header_z, length, rest;
+       int page, offset, packet_count, header_size;
+
+       /*
+        * FIXME: Cycle lost behavior should be configurable: lose
+        * packet, retransmit or terminate..
+        */
+
+       if (packet->skip) {
+               d = context_get_descriptors(&ctx->context, 2, &d_bus);
+               if (d == NULL)
+                       return -ENOMEM;
+
+               db = (struct db_descriptor *) d;
+               db->control = cpu_to_le16(DESCRIPTOR_STATUS |
+                                         DESCRIPTOR_BRANCH_ALWAYS |
+                                         DESCRIPTOR_WAIT);
+               db->first_size = cpu_to_le16(ctx->base.header_size + 4);
+               context_append(&ctx->context, d, 2, 0);
+       }
+
+       p = packet;
+       z = 2;
+
+       /*
+        * The OHCI controller puts the status word in the header
+        * buffer too, so we need 4 extra bytes per packet.
+        */
+       packet_count = p->header_length / ctx->base.header_size;
+       header_size = packet_count * (ctx->base.header_size + 4);
+
+       /* Get header size in number of descriptors. */
+       header_z = DIV_ROUND_UP(header_size, sizeof(*d));
+       page     = payload >> PAGE_SHIFT;
+       offset   = payload & ~PAGE_MASK;
+       rest     = p->payload_length;
+
+       /* FIXME: OHCI 1.0 doesn't support dual buffer receive */
+       /* FIXME: make packet-per-buffer/dual-buffer a context option */
+       while (rest > 0) {
+               d = context_get_descriptors(&ctx->context,
+                                           z + header_z, &d_bus);
+               if (d == NULL)
+                       return -ENOMEM;
+
+               db = (struct db_descriptor *) d;
+               db->control = cpu_to_le16(DESCRIPTOR_STATUS |
+                                         DESCRIPTOR_BRANCH_ALWAYS);
+               db->first_size = cpu_to_le16(ctx->base.header_size + 4);
+               db->first_req_count = cpu_to_le16(header_size);
+               db->first_res_count = db->first_req_count;
+               db->first_buffer = cpu_to_le32(d_bus + sizeof(*db));
+
+               if (offset + rest < PAGE_SIZE)
+                       length = rest;
+               else
+                       length = PAGE_SIZE - offset;
+
+               db->second_req_count = cpu_to_le16(length);
+               db->second_res_count = db->second_req_count;
+               page_bus = page_private(buffer->pages[page]);
+               db->second_buffer = cpu_to_le32(page_bus + offset);
+
+               if (p->interrupt && length == rest)
+                       db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
+
+               context_append(&ctx->context, d, z, header_z);
+               offset = (offset + length) & ~PAGE_MASK;
+               rest -= length;
+               page++;
+       }
+
+       return 0;
+}
+
+static int
+ohci_queue_iso(struct fw_iso_context *base,
+              struct fw_iso_packet *packet,
+              struct fw_iso_buffer *buffer,
+              unsigned long payload)
+{
+       struct iso_context *ctx = container_of(base, struct iso_context, base);
+
+       if (base->type == FW_ISO_CONTEXT_TRANSMIT)
+               return ohci_queue_iso_transmit(base, packet, buffer, payload);
+       else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
+               return ohci_queue_iso_receive_dualbuffer(base, packet,
+                                                        buffer, payload);
+       else
+               /* FIXME: Implement fallback for OHCI 1.0 controllers. */
+               return -EINVAL;
+}
+
+static const struct fw_card_driver ohci_driver = {
+       .name                   = ohci_driver_name,
+       .enable                 = ohci_enable,
+       .update_phy_reg         = ohci_update_phy_reg,
+       .set_config_rom         = ohci_set_config_rom,
+       .send_request           = ohci_send_request,
+       .send_response          = ohci_send_response,
+       .cancel_packet          = ohci_cancel_packet,
+       .enable_phys_dma        = ohci_enable_phys_dma,
+       .get_bus_time           = ohci_get_bus_time,
+
+       .allocate_iso_context   = ohci_allocate_iso_context,
+       .free_iso_context       = ohci_free_iso_context,
+       .queue_iso              = ohci_queue_iso,
+       .start_iso              = ohci_start_iso,
+       .stop_iso               = ohci_stop_iso,
+};
+
+static int software_reset(struct fw_ohci *ohci)
+{
+       int i;
+
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+       for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+               if ((reg_read(ohci, OHCI1394_HCControlSet) &
+                    OHCI1394_HCControl_softReset) == 0)
+                       return 0;
+               msleep(1);
+       }
+
+       return -EBUSY;
+}
+
+static int __devinit
+pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+       struct fw_ohci *ohci;
+       u32 bus_options, max_receive, link_speed;
+       u64 guid;
+       int err;
+       size_t size;
+
+       ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
+       if (ohci == NULL) {
+               fw_error("Could not malloc fw_ohci data.\n");
+               return -ENOMEM;
+       }
+
+       fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
+
+       err = pci_enable_device(dev);
+       if (err) {
+               fw_error("Failed to enable OHCI hardware.\n");
+               goto fail_put_card;
+       }
+
+       pci_set_master(dev);
+       pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
+       pci_set_drvdata(dev, ohci);
+
+       spin_lock_init(&ohci->lock);
+
+       tasklet_init(&ohci->bus_reset_tasklet,
+                    bus_reset_tasklet, (unsigned long)ohci);
+
+       err = pci_request_region(dev, 0, ohci_driver_name);
+       if (err) {
+               fw_error("MMIO resource unavailable\n");
+               goto fail_disable;
+       }
+
+       ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE);
+       if (ohci->registers == NULL) {
+               fw_error("Failed to remap registers\n");
+               err = -ENXIO;
+               goto fail_iomem;
+       }
+
+       if (software_reset(ohci)) {
+               fw_error("Failed to reset ohci card.\n");
+               err = -EBUSY;
+               goto fail_registers;
+       }
+
+       /*
+        * Now enable LPS, which we need in order to start accessing
+        * most of the registers.  In fact, on some cards (ALI M5251),
+        * accessing registers in the SClk domain without LPS enabled
+        * will lock up the machine.  Wait 50msec to make sure we have
+        * full link enabled.
+        */
+       reg_write(ohci, OHCI1394_HCControlSet,
+                 OHCI1394_HCControl_LPS |
+                 OHCI1394_HCControl_postedWriteEnable);
+       flush_writes(ohci);
+       msleep(50);
+
+       reg_write(ohci, OHCI1394_HCControlClear,
+                 OHCI1394_HCControl_noByteSwapData);
+
+       reg_write(ohci, OHCI1394_LinkControlSet,
+                 OHCI1394_LinkControl_rcvSelfID |
+                 OHCI1394_LinkControl_cycleTimerEnable |
+                 OHCI1394_LinkControl_cycleMaster);
+
+       ar_context_init(&ohci->ar_request_ctx, ohci,
+                       OHCI1394_AsReqRcvContextControlSet);
+
+       ar_context_init(&ohci->ar_response_ctx, ohci,
+                       OHCI1394_AsRspRcvContextControlSet);
+
+       context_init(&ohci->at_request_ctx, ohci, AT_BUFFER_SIZE,
+                    OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+
+       context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE,
+                    OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+
+       reg_write(ohci, OHCI1394_ATRetries,
+                 OHCI1394_MAX_AT_REQ_RETRIES |
+                 (OHCI1394_MAX_AT_RESP_RETRIES << 4) |
+                 (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
+
+       reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
+       ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+       reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
+       size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask);
+       ohci->it_context_list = kzalloc(size, GFP_KERNEL);
+
+       reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
+       ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+       reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
+       size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask);
+       ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
+
+       if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
+               fw_error("Out of memory for it/ir contexts.\n");
+               err = -ENOMEM;
+               goto fail_registers;
+       }
+
+       /* self-id dma buffer allocation */
+       ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device,
+                                              SELF_ID_BUF_SIZE,
+                                              &ohci->self_id_bus,
+                                              GFP_KERNEL);
+       if (ohci->self_id_cpu == NULL) {
+               fw_error("Out of memory for self ID buffer.\n");
+               err = -ENOMEM;
+               goto fail_registers;
+       }
+
+       reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+       reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
+       reg_write(ohci, OHCI1394_IntEventClear, ~0);
+       reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+       reg_write(ohci, OHCI1394_IntMaskSet,
+                 OHCI1394_selfIDComplete |
+                 OHCI1394_RQPkt | OHCI1394_RSPkt |
+                 OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
+                 OHCI1394_isochRx | OHCI1394_isochTx |
+                 OHCI1394_masterIntEnable |
+                 OHCI1394_cycle64Seconds);
+
+       bus_options = reg_read(ohci, OHCI1394_BusOptions);
+       max_receive = (bus_options >> 12) & 0xf;
+       link_speed = bus_options & 0x7;
+       guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) |
+               reg_read(ohci, OHCI1394_GUIDLo);
+
+       err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
+       if (err < 0)
+               goto fail_self_id;
+
+       ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+       fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
+                 dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
+
+       return 0;
+
+ fail_self_id:
+       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
+                         ohci->self_id_cpu, ohci->self_id_bus);
+ fail_registers:
+       kfree(ohci->it_context_list);
+       kfree(ohci->ir_context_list);
+       pci_iounmap(dev, ohci->registers);
+ fail_iomem:
+       pci_release_region(dev, 0);
+ fail_disable:
+       pci_disable_device(dev);
+ fail_put_card:
+       fw_card_put(&ohci->card);
+
+       return err;
+}
+
+static void pci_remove(struct pci_dev *dev)
+{
+       struct fw_ohci *ohci;
+
+       ohci = pci_get_drvdata(dev);
+       reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+       flush_writes(ohci);
+       fw_core_remove_card(&ohci->card);
+
+       /*
+        * FIXME: Fail all pending packets here, now that the upper
+        * layers can't queue any more.
+        */
+
+       software_reset(ohci);
+       free_irq(dev->irq, ohci);
+       dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
+                         ohci->self_id_cpu, ohci->self_id_bus);
+       kfree(ohci->it_context_list);
+       kfree(ohci->ir_context_list);
+       pci_iounmap(dev, ohci->registers);
+       pci_release_region(dev, 0);
+       pci_disable_device(dev);
+       fw_card_put(&ohci->card);
+
+       fw_notify("Removed fw-ohci device.\n");
+}
+
+static struct pci_device_id pci_table[] = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_table);
+
+static struct pci_driver fw_ohci_pci_driver = {
+       .name           = ohci_driver_name,
+       .id_table       = pci_table,
+       .probe          = pci_probe,
+       .remove         = pci_remove,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
+MODULE_LICENSE("GPL");
+
+/* Provide a module alias so root-on-sbp2 initrds don't break. */
+#ifndef CONFIG_IEEE1394_OHCI1394_MODULE
+MODULE_ALIAS("ohci1394");
+#endif
+
+static int __init fw_ohci_init(void)
+{
+       return pci_register_driver(&fw_ohci_pci_driver);
+}
+
+static void __exit fw_ohci_cleanup(void)
+{
+       pci_unregister_driver(&fw_ohci_pci_driver);
+}
+
+module_init(fw_ohci_init);
+module_exit(fw_ohci_cleanup);
diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h
new file mode 100644 (file)
index 0000000..fa15706
--- /dev/null
@@ -0,0 +1,153 @@
+#ifndef __fw_ohci_h
+#define __fw_ohci_h
+
+/* OHCI register map */
+
+#define OHCI1394_Version                      0x000
+#define OHCI1394_GUID_ROM                     0x004
+#define OHCI1394_ATRetries                    0x008
+#define OHCI1394_CSRData                      0x00C
+#define OHCI1394_CSRCompareData               0x010
+#define OHCI1394_CSRControl                   0x014
+#define OHCI1394_ConfigROMhdr                 0x018
+#define OHCI1394_BusID                        0x01C
+#define OHCI1394_BusOptions                   0x020
+#define OHCI1394_GUIDHi                       0x024
+#define OHCI1394_GUIDLo                       0x028
+#define OHCI1394_ConfigROMmap                 0x034
+#define OHCI1394_PostedWriteAddressLo         0x038
+#define OHCI1394_PostedWriteAddressHi         0x03C
+#define OHCI1394_VendorID                     0x040
+#define OHCI1394_HCControlSet                 0x050
+#define OHCI1394_HCControlClear               0x054
+#define  OHCI1394_HCControl_BIBimageValid      0x80000000
+#define  OHCI1394_HCControl_noByteSwapData     0x40000000
+#define  OHCI1394_HCControl_programPhyEnable   0x00800000
+#define  OHCI1394_HCControl_aPhyEnhanceEnable  0x00400000
+#define  OHCI1394_HCControl_LPS                        0x00080000
+#define  OHCI1394_HCControl_postedWriteEnable  0x00040000
+#define  OHCI1394_HCControl_linkEnable         0x00020000
+#define  OHCI1394_HCControl_softReset          0x00010000
+#define OHCI1394_SelfIDBuffer                 0x064
+#define OHCI1394_SelfIDCount                  0x068
+#define OHCI1394_IRMultiChanMaskHiSet         0x070
+#define OHCI1394_IRMultiChanMaskHiClear       0x074
+#define OHCI1394_IRMultiChanMaskLoSet         0x078
+#define OHCI1394_IRMultiChanMaskLoClear       0x07C
+#define OHCI1394_IntEventSet                  0x080
+#define OHCI1394_IntEventClear                0x084
+#define OHCI1394_IntMaskSet                   0x088
+#define OHCI1394_IntMaskClear                 0x08C
+#define OHCI1394_IsoXmitIntEventSet           0x090
+#define OHCI1394_IsoXmitIntEventClear         0x094
+#define OHCI1394_IsoXmitIntMaskSet            0x098
+#define OHCI1394_IsoXmitIntMaskClear          0x09C
+#define OHCI1394_IsoRecvIntEventSet           0x0A0
+#define OHCI1394_IsoRecvIntEventClear         0x0A4
+#define OHCI1394_IsoRecvIntMaskSet            0x0A8
+#define OHCI1394_IsoRecvIntMaskClear          0x0AC
+#define OHCI1394_InitialBandwidthAvailable    0x0B0
+#define OHCI1394_InitialChannelsAvailableHi   0x0B4
+#define OHCI1394_InitialChannelsAvailableLo   0x0B8
+#define OHCI1394_FairnessControl              0x0DC
+#define OHCI1394_LinkControlSet               0x0E0
+#define OHCI1394_LinkControlClear             0x0E4
+#define   OHCI1394_LinkControl_rcvSelfID       (1 << 9)
+#define   OHCI1394_LinkControl_rcvPhyPkt       (1 << 10)
+#define   OHCI1394_LinkControl_cycleTimerEnable        (1 << 20)
+#define   OHCI1394_LinkControl_cycleMaster     (1 << 21)
+#define   OHCI1394_LinkControl_cycleSource     (1 << 22)
+#define OHCI1394_NodeID                       0x0E8
+#define   OHCI1394_NodeID_idValid             0x80000000
+#define OHCI1394_PhyControl                   0x0EC
+#define   OHCI1394_PhyControl_Read(addr)       (((addr) << 8) | 0x00008000)
+#define   OHCI1394_PhyControl_ReadDone         0x80000000
+#define   OHCI1394_PhyControl_ReadData(r)      (((r) & 0x00ff0000) >> 16)
+#define   OHCI1394_PhyControl_Write(addr, data)        (((addr) << 8) | (data) | 0x00004000)
+#define   OHCI1394_PhyControl_WriteDone                0x00004000
+#define OHCI1394_IsochronousCycleTimer        0x0F0
+#define OHCI1394_AsReqFilterHiSet             0x100
+#define OHCI1394_AsReqFilterHiClear           0x104
+#define OHCI1394_AsReqFilterLoSet             0x108
+#define OHCI1394_AsReqFilterLoClear           0x10C
+#define OHCI1394_PhyReqFilterHiSet            0x110
+#define OHCI1394_PhyReqFilterHiClear          0x114
+#define OHCI1394_PhyReqFilterLoSet            0x118
+#define OHCI1394_PhyReqFilterLoClear          0x11C
+#define OHCI1394_PhyUpperBound                0x120
+
+#define OHCI1394_AsReqTrContextBase           0x180
+#define OHCI1394_AsReqTrContextControlSet     0x180
+#define OHCI1394_AsReqTrContextControlClear   0x184
+#define OHCI1394_AsReqTrCommandPtr            0x18C
+
+#define OHCI1394_AsRspTrContextBase           0x1A0
+#define OHCI1394_AsRspTrContextControlSet     0x1A0
+#define OHCI1394_AsRspTrContextControlClear   0x1A4
+#define OHCI1394_AsRspTrCommandPtr            0x1AC
+
+#define OHCI1394_AsReqRcvContextBase          0x1C0
+#define OHCI1394_AsReqRcvContextControlSet    0x1C0
+#define OHCI1394_AsReqRcvContextControlClear  0x1C4
+#define OHCI1394_AsReqRcvCommandPtr           0x1CC
+
+#define OHCI1394_AsRspRcvContextBase          0x1E0
+#define OHCI1394_AsRspRcvContextControlSet    0x1E0
+#define OHCI1394_AsRspRcvContextControlClear  0x1E4
+#define OHCI1394_AsRspRcvCommandPtr           0x1EC
+
+/* Isochronous transmit registers */
+#define OHCI1394_IsoXmitContextBase(n)           (0x200 + 16 * (n))
+#define OHCI1394_IsoXmitContextControlSet(n)     (0x200 + 16 * (n))
+#define OHCI1394_IsoXmitContextControlClear(n)   (0x204 + 16 * (n))
+#define OHCI1394_IsoXmitCommandPtr(n)            (0x20C + 16 * (n))
+
+/* Isochronous receive registers */
+#define OHCI1394_IsoRcvContextBase(n)         (0x400 + 32 * (n))
+#define OHCI1394_IsoRcvContextControlSet(n)   (0x400 + 32 * (n))
+#define OHCI1394_IsoRcvContextControlClear(n) (0x404 + 32 * (n))
+#define OHCI1394_IsoRcvCommandPtr(n)          (0x40C + 32 * (n))
+#define OHCI1394_IsoRcvContextMatch(n)        (0x410 + 32 * (n))
+
+/* Interrupts Mask/Events */
+#define OHCI1394_reqTxComplete         0x00000001
+#define OHCI1394_respTxComplete                0x00000002
+#define OHCI1394_ARRQ                  0x00000004
+#define OHCI1394_ARRS                  0x00000008
+#define OHCI1394_RQPkt                 0x00000010
+#define OHCI1394_RSPkt                 0x00000020
+#define OHCI1394_isochTx               0x00000040
+#define OHCI1394_isochRx               0x00000080
+#define OHCI1394_postedWriteErr                0x00000100
+#define OHCI1394_lockRespErr           0x00000200
+#define OHCI1394_selfIDComplete                0x00010000
+#define OHCI1394_busReset              0x00020000
+#define OHCI1394_phy                   0x00080000
+#define OHCI1394_cycleSynch            0x00100000
+#define OHCI1394_cycle64Seconds                0x00200000
+#define OHCI1394_cycleLost             0x00400000
+#define OHCI1394_cycleInconsistent     0x00800000
+#define OHCI1394_unrecoverableError    0x01000000
+#define OHCI1394_cycleTooLong          0x02000000
+#define OHCI1394_phyRegRcvd            0x04000000
+#define OHCI1394_masterIntEnable       0x80000000
+
+#define OHCI1394_evt_no_status         0x0
+#define OHCI1394_evt_long_packet       0x2
+#define OHCI1394_evt_missing_ack       0x3
+#define OHCI1394_evt_underrun          0x4
+#define OHCI1394_evt_overrun           0x5
+#define OHCI1394_evt_descriptor_read   0x6
+#define OHCI1394_evt_data_read         0x7
+#define OHCI1394_evt_data_write                0x8
+#define OHCI1394_evt_bus_reset         0x9
+#define OHCI1394_evt_timeout           0xa
+#define OHCI1394_evt_tcode_err         0xb
+#define OHCI1394_evt_reserved_b                0xc
+#define OHCI1394_evt_reserved_c                0xd
+#define OHCI1394_evt_unknown           0xe
+#define OHCI1394_evt_flushed           0xf
+
+#define OHCI1394_phy_tcode             0xe
+
+#endif /* __fw_ohci_h */
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
new file mode 100644 (file)
index 0000000..6830041
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+ * SBP2 driver (SCSI over IEEE1394)
+ *
+ * Copyright (C) 2005-2007  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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.
+ */
+
+/*
+ * The basic structure of this driver is based on the old storage driver,
+ * drivers/ieee1394/sbp2.c, originally written by
+ *     James Goodwin <jamesg@filanet.com>
+ * with later contributions and ongoing maintenance from
+ *     Ben Collins <bcollins@debian.org>,
+ *     Stefan Richter <stefanr@s5r6.in-berlin.de>
+ * and many others.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/timer.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+/* I don't know why the SCSI stack doesn't define something like this... */
+typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
+
+static const char sbp2_driver_name[] = "sbp2";
+
+struct sbp2_device {
+       struct kref kref;
+       struct fw_unit *unit;
+       struct fw_address_handler address_handler;
+       struct list_head orb_list;
+       u64 management_agent_address;
+       u64 command_block_agent_address;
+       u32 workarounds;
+       int login_id;
+
+       /*
+        * We cache these addresses and only update them once we've
+        * logged in or reconnected to the sbp2 device.  That way, any
+        * IO to the device will automatically fail and get retried if
+        * it happens in a window where the device is not ready to
+        * handle it (e.g. after a bus reset but before we reconnect).
+        */
+       int node_id;
+       int address_high;
+       int generation;
+
+       int retries;
+       struct delayed_work work;
+};
+
+#define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
+#define SBP2_MAX_SECTORS               255     /* Max sectors supported */
+#define SBP2_ORB_TIMEOUT               2000    /* Timeout in ms */
+
+#define SBP2_ORB_NULL                  0x80000000
+
+#define SBP2_DIRECTION_TO_MEDIA                0x0
+#define SBP2_DIRECTION_FROM_MEDIA      0x1
+
+/* Unit directory keys */
+#define SBP2_COMMAND_SET_SPECIFIER     0x38
+#define SBP2_COMMAND_SET               0x39
+#define SBP2_COMMAND_SET_REVISION      0x3b
+#define SBP2_FIRMWARE_REVISION         0x3c
+
+/* Flags for detected oddities and brokeness */
+#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
+#define SBP2_WORKAROUND_INQUIRY_36     0x2
+#define SBP2_WORKAROUND_MODE_SENSE_8   0x4
+#define SBP2_WORKAROUND_FIX_CAPACITY   0x8
+#define SBP2_WORKAROUND_OVERRIDE       0x100
+
+/* Management orb opcodes */
+#define SBP2_LOGIN_REQUEST             0x0
+#define SBP2_QUERY_LOGINS_REQUEST      0x1
+#define SBP2_RECONNECT_REQUEST         0x3
+#define SBP2_SET_PASSWORD_REQUEST      0x4
+#define SBP2_LOGOUT_REQUEST            0x7
+#define SBP2_ABORT_TASK_REQUEST                0xb
+#define SBP2_ABORT_TASK_SET            0xc
+#define SBP2_LOGICAL_UNIT_RESET                0xe
+#define SBP2_TARGET_RESET_REQUEST      0xf
+
+/* Offsets for command block agent registers */
+#define SBP2_AGENT_STATE               0x00
+#define SBP2_AGENT_RESET               0x04
+#define SBP2_ORB_POINTER               0x08
+#define SBP2_DOORBELL                  0x10
+#define SBP2_UNSOLICITED_STATUS_ENABLE 0x14
+
+/* Status write response codes */
+#define SBP2_STATUS_REQUEST_COMPLETE   0x0
+#define SBP2_STATUS_TRANSPORT_FAILURE  0x1
+#define SBP2_STATUS_ILLEGAL_REQUEST    0x2
+#define SBP2_STATUS_VENDOR_DEPENDENT   0x3
+
+#define STATUS_GET_ORB_HIGH(v)         ((v).status & 0xffff)
+#define STATUS_GET_SBP_STATUS(v)       (((v).status >> 16) & 0xff)
+#define STATUS_GET_LEN(v)              (((v).status >> 24) & 0x07)
+#define STATUS_GET_DEAD(v)             (((v).status >> 27) & 0x01)
+#define STATUS_GET_RESPONSE(v)         (((v).status >> 28) & 0x03)
+#define STATUS_GET_SOURCE(v)           (((v).status >> 30) & 0x03)
+#define STATUS_GET_ORB_LOW(v)          ((v).orb_low)
+#define STATUS_GET_DATA(v)             ((v).data)
+
+struct sbp2_status {
+       u32 status;
+       u32 orb_low;
+       u8 data[24];
+};
+
+struct sbp2_pointer {
+       u32 high;
+       u32 low;
+};
+
+struct sbp2_orb {
+       struct fw_transaction t;
+       dma_addr_t request_bus;
+       int rcode;
+       struct sbp2_pointer pointer;
+       void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status);
+       struct list_head link;
+};
+
+#define MANAGEMENT_ORB_LUN(v)                  ((v))
+#define MANAGEMENT_ORB_FUNCTION(v)             ((v) << 16)
+#define MANAGEMENT_ORB_RECONNECT(v)            ((v) << 20)
+#define MANAGEMENT_ORB_EXCLUSIVE               ((1) << 28)
+#define MANAGEMENT_ORB_REQUEST_FORMAT(v)       ((v) << 29)
+#define MANAGEMENT_ORB_NOTIFY                  ((1) << 31)
+
+#define MANAGEMENT_ORB_RESPONSE_LENGTH(v)      ((v))
+#define MANAGEMENT_ORB_PASSWORD_LENGTH(v)      ((v) << 16)
+
+struct sbp2_management_orb {
+       struct sbp2_orb base;
+       struct {
+               struct sbp2_pointer password;
+               struct sbp2_pointer response;
+               u32 misc;
+               u32 length;
+               struct sbp2_pointer status_fifo;
+       } request;
+       __be32 response[4];
+       dma_addr_t response_bus;
+       struct completion done;
+       struct sbp2_status status;
+};
+
+#define LOGIN_RESPONSE_GET_LOGIN_ID(v) ((v).misc & 0xffff)
+#define LOGIN_RESPONSE_GET_LENGTH(v)   (((v).misc >> 16) & 0xffff)
+
+struct sbp2_login_response {
+       u32 misc;
+       struct sbp2_pointer command_block_agent;
+       u32 reconnect_hold;
+};
+#define COMMAND_ORB_DATA_SIZE(v)       ((v))
+#define COMMAND_ORB_PAGE_SIZE(v)       ((v) << 16)
+#define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19)
+#define COMMAND_ORB_MAX_PAYLOAD(v)     ((v) << 20)
+#define COMMAND_ORB_SPEED(v)           ((v) << 24)
+#define COMMAND_ORB_DIRECTION(v)       ((v) << 27)
+#define COMMAND_ORB_REQUEST_FORMAT(v)  ((v) << 29)
+#define COMMAND_ORB_NOTIFY             ((1) << 31)
+
+struct sbp2_command_orb {
+       struct sbp2_orb base;
+       struct {
+               struct sbp2_pointer next;
+               struct sbp2_pointer data_descriptor;
+               u32 misc;
+               u8 command_block[12];
+       } request;
+       struct scsi_cmnd *cmd;
+       scsi_done_fn_t done;
+       struct fw_unit *unit;
+
+       struct sbp2_pointer page_table[SG_ALL];
+       dma_addr_t page_table_bus;
+       dma_addr_t request_buffer_bus;
+};
+
+/*
+ * List of devices with known bugs.
+ *
+ * The firmware_revision field, masked with 0xffff00, is the best
+ * indicator for the type of bridge chip of a device.  It yields a few
+ * false positives but this did not break correctly behaving devices
+ * so far.  We use ~0 as a wildcard, since the 24 bit values we get
+ * from the config rom can never match that.
+ */
+static const struct {
+       u32 firmware_revision;
+       u32 model;
+       unsigned workarounds;
+} sbp2_workarounds_table[] = {
+       /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
+               .firmware_revision      = 0x002800,
+               .model                  = 0x001010,
+               .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
+                                         SBP2_WORKAROUND_MODE_SENSE_8,
+       },
+       /* Initio bridges, actually only needed for some older ones */ {
+               .firmware_revision      = 0x000200,
+               .model                  = ~0,
+               .workarounds            = SBP2_WORKAROUND_INQUIRY_36,
+       },
+       /* Symbios bridge */ {
+               .firmware_revision      = 0xa0b800,
+               .model                  = ~0,
+               .workarounds            = SBP2_WORKAROUND_128K_MAX_TRANS,
+       },
+
+       /*
+        * There are iPods (2nd gen, 3rd gen) with model_id == 0, but
+        * these iPods do not feature the read_capacity bug according
+        * to one report.  Read_capacity behaviour as well as model_id
+        * could change due to Apple-supplied firmware updates though.
+        */
+
+       /* iPod 4th generation. */ {
+               .firmware_revision      = 0x0a2700,
+               .model                  = 0x000021,
+               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
+       },
+       /* iPod mini */ {
+               .firmware_revision      = 0x0a2700,
+               .model                  = 0x000023,
+               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
+       },
+       /* iPod Photo */ {
+               .firmware_revision      = 0x0a2700,
+               .model                  = 0x00007e,
+               .workarounds            = SBP2_WORKAROUND_FIX_CAPACITY,
+       }
+};
+
+static void
+sbp2_status_write(struct fw_card *card, struct fw_request *request,
+                 int tcode, int destination, int source,
+                 int generation, int speed,
+                 unsigned long long offset,
+                 void *payload, size_t length, void *callback_data)
+{
+       struct sbp2_device *sd = callback_data;
+       struct sbp2_orb *orb;
+       struct sbp2_status status;
+       size_t header_size;
+       unsigned long flags;
+
+       if (tcode != TCODE_WRITE_BLOCK_REQUEST ||
+           length == 0 || length > sizeof(status)) {
+               fw_send_response(card, request, RCODE_TYPE_ERROR);
+               return;
+       }
+
+       header_size = min(length, 2 * sizeof(u32));
+       fw_memcpy_from_be32(&status, payload, header_size);
+       if (length > header_size)
+               memcpy(status.data, payload + 8, length - header_size);
+       if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) {
+               fw_notify("non-orb related status write, not handled\n");
+               fw_send_response(card, request, RCODE_COMPLETE);
+               return;
+       }
+
+       /* Lookup the orb corresponding to this status write. */
+       spin_lock_irqsave(&card->lock, flags);
+       list_for_each_entry(orb, &sd->orb_list, link) {
+               if (STATUS_GET_ORB_HIGH(status) == 0 &&
+                   STATUS_GET_ORB_LOW(status) == orb->request_bus &&
+                   orb->rcode == RCODE_COMPLETE) {
+                       list_del(&orb->link);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (&orb->link != &sd->orb_list)
+               orb->callback(orb, &status);
+       else
+               fw_error("status write for unknown orb\n");
+
+       fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+                    void *payload, size_t length, void *data)
+{
+       struct sbp2_orb *orb = data;
+       unsigned long flags;
+
+       orb->rcode = rcode;
+       if (rcode != RCODE_COMPLETE) {
+               spin_lock_irqsave(&card->lock, flags);
+               list_del(&orb->link);
+               spin_unlock_irqrestore(&card->lock, flags);
+               orb->callback(orb, NULL);
+       }
+}
+
+static void
+sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
+             int node_id, int generation, u64 offset)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd = unit->device.driver_data;
+       unsigned long flags;
+
+       orb->pointer.high = 0;
+       orb->pointer.low = orb->request_bus;
+       fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer));
+
+       spin_lock_irqsave(&device->card->lock, flags);
+       list_add_tail(&orb->link, &sd->orb_list);
+       spin_unlock_irqrestore(&device->card->lock, flags);
+
+       fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
+                       node_id, generation,
+                       device->node->max_speed, offset,
+                       &orb->pointer, sizeof(orb->pointer),
+                       complete_transaction, orb);
+}
+
+static int sbp2_cancel_orbs(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd = unit->device.driver_data;
+       struct sbp2_orb *orb, *next;
+       struct list_head list;
+       unsigned long flags;
+       int retval = -ENOENT;
+
+       INIT_LIST_HEAD(&list);
+       spin_lock_irqsave(&device->card->lock, flags);
+       list_splice_init(&sd->orb_list, &list);
+       spin_unlock_irqrestore(&device->card->lock, flags);
+
+       list_for_each_entry_safe(orb, next, &list, link) {
+               retval = 0;
+               if (fw_cancel_transaction(device->card, &orb->t) == 0)
+                       continue;
+
+               orb->rcode = RCODE_CANCELLED;
+               orb->callback(orb, NULL);
+       }
+
+       return retval;
+}
+
+static void
+complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+{
+       struct sbp2_management_orb *orb =
+           (struct sbp2_management_orb *)base_orb;
+
+       if (status)
+               memcpy(&orb->status, status, sizeof(*status));
+       complete(&orb->done);
+}
+
+static int
+sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
+                        int function, int lun, void *response)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd = unit->device.driver_data;
+       struct sbp2_management_orb *orb;
+       int retval = -ENOMEM;
+
+       orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
+       if (orb == NULL)
+               return -ENOMEM;
+
+       /*
+        * The sbp2 device is going to send a block read request to
+        * read out the request from host memory, so map it for dma.
+        */
+       orb->base.request_bus =
+               dma_map_single(device->card->device, &orb->request,
+                              sizeof(orb->request), DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->base.request_bus))
+               goto out;
+
+       orb->response_bus =
+               dma_map_single(device->card->device, &orb->response,
+                              sizeof(orb->response), DMA_FROM_DEVICE);
+       if (dma_mapping_error(orb->response_bus))
+               goto out;
+
+       orb->request.response.high    = 0;
+       orb->request.response.low     = orb->response_bus;
+
+       orb->request.misc =
+               MANAGEMENT_ORB_NOTIFY |
+               MANAGEMENT_ORB_FUNCTION(function) |
+               MANAGEMENT_ORB_LUN(lun);
+       orb->request.length =
+               MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response));
+
+       orb->request.status_fifo.high = sd->address_handler.offset >> 32;
+       orb->request.status_fifo.low  = sd->address_handler.offset;
+
+       /*
+        * FIXME: Yeah, ok this isn't elegant, we hardwire exclusive
+        * login and 1 second reconnect time.  The reconnect setting
+        * is probably fine, but the exclusive login should be an option.
+        */
+       if (function == SBP2_LOGIN_REQUEST) {
+               orb->request.misc |=
+                       MANAGEMENT_ORB_EXCLUSIVE |
+                       MANAGEMENT_ORB_RECONNECT(0);
+       }
+
+       fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
+
+       init_completion(&orb->done);
+       orb->base.callback = complete_management_orb;
+
+       sbp2_send_orb(&orb->base, unit,
+                     node_id, generation, sd->management_agent_address);
+
+       wait_for_completion_timeout(&orb->done,
+                                   msecs_to_jiffies(SBP2_ORB_TIMEOUT));
+
+       retval = -EIO;
+       if (sbp2_cancel_orbs(unit) == 0) {
+               fw_error("orb reply timed out, rcode=0x%02x\n",
+                        orb->base.rcode);
+               goto out;
+       }
+
+       if (orb->base.rcode != RCODE_COMPLETE) {
+               fw_error("management write failed, rcode 0x%02x\n",
+                        orb->base.rcode);
+               goto out;
+       }
+
+       if (STATUS_GET_RESPONSE(orb->status) != 0 ||
+           STATUS_GET_SBP_STATUS(orb->status) != 0) {
+               fw_error("error status: %d:%d\n",
+                        STATUS_GET_RESPONSE(orb->status),
+                        STATUS_GET_SBP_STATUS(orb->status));
+               goto out;
+       }
+
+       retval = 0;
+ out:
+       dma_unmap_single(device->card->device, orb->base.request_bus,
+                        sizeof(orb->request), DMA_TO_DEVICE);
+       dma_unmap_single(device->card->device, orb->response_bus,
+                        sizeof(orb->response), DMA_FROM_DEVICE);
+
+       if (response)
+               fw_memcpy_from_be32(response,
+                                   orb->response, sizeof(orb->response));
+       kfree(orb);
+
+       return retval;
+}
+
+static void
+complete_agent_reset_write(struct fw_card *card, int rcode,
+                          void *payload, size_t length, void *data)
+{
+       struct fw_transaction *t = data;
+
+       kfree(t);
+}
+
+static int sbp2_agent_reset(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd = unit->device.driver_data;
+       struct fw_transaction *t;
+       static u32 zero;
+
+       t = kzalloc(sizeof(*t), GFP_ATOMIC);
+       if (t == NULL)
+               return -ENOMEM;
+
+       fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
+                       sd->node_id, sd->generation, SCODE_400,
+                       sd->command_block_agent_address + SBP2_AGENT_RESET,
+                       &zero, sizeof(zero), complete_agent_reset_write, t);
+
+       return 0;
+}
+
+static void sbp2_reconnect(struct work_struct *work);
+static struct scsi_host_template scsi_driver_template;
+
+static void
+release_sbp2_device(struct kref *kref)
+{
+       struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
+       struct Scsi_Host *host =
+               container_of((void *)sd, struct Scsi_Host, hostdata[0]);
+
+       sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
+                                SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
+
+       scsi_remove_host(host);
+       fw_core_remove_address_handler(&sd->address_handler);
+       fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
+       put_device(&sd->unit->device);
+       scsi_host_put(host);
+}
+
+static void sbp2_login(struct work_struct *work)
+{
+       struct sbp2_device *sd =
+               container_of(work, struct sbp2_device, work.work);
+       struct Scsi_Host *host =
+               container_of((void *)sd, struct Scsi_Host, hostdata[0]);
+       struct fw_unit *unit = sd->unit;
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_login_response response;
+       int generation, node_id, local_node_id, lun, retval;
+
+       /* FIXME: Make this work for multi-lun devices. */
+       lun = 0;
+
+       generation    = device->card->generation;
+       node_id       = device->node->node_id;
+       local_node_id = device->card->local_node->node_id;
+
+       if (sbp2_send_management_orb(unit, node_id, generation,
+                                    SBP2_LOGIN_REQUEST, lun, &response) < 0) {
+               if (sd->retries++ < 5) {
+                       schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+               } else {
+                       fw_error("failed to login to %s\n",
+                                unit->device.bus_id);
+                       kref_put(&sd->kref, release_sbp2_device);
+               }
+               return;
+       }
+
+       sd->generation   = generation;
+       sd->node_id      = node_id;
+       sd->address_high = local_node_id << 16;
+
+       /* Get command block agent offset and login id. */
+       sd->command_block_agent_address =
+               ((u64) (response.command_block_agent.high & 0xffff) << 32) |
+               response.command_block_agent.low;
+       sd->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
+
+       fw_notify("logged in to sbp2 unit %s (%d retries)\n",
+                 unit->device.bus_id, sd->retries);
+       fw_notify(" - management_agent_address:    0x%012llx\n",
+                 (unsigned long long) sd->management_agent_address);
+       fw_notify(" - command_block_agent_address: 0x%012llx\n",
+                 (unsigned long long) sd->command_block_agent_address);
+       fw_notify(" - status write address:        0x%012llx\n",
+                 (unsigned long long) sd->address_handler.offset);
+
+#if 0
+       /* FIXME: The linux1394 sbp2 does this last step. */
+       sbp2_set_busy_timeout(scsi_id);
+#endif
+
+       PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect);
+       sbp2_agent_reset(unit);
+
+       /* FIXME: Loop over luns here. */
+       lun = 0;
+       retval = scsi_add_device(host, 0, 0, lun);
+       if (retval < 0) {
+               sbp2_send_management_orb(unit, sd->node_id, sd->generation,
+                                        SBP2_LOGOUT_REQUEST, sd->login_id,
+                                        NULL);
+               /*
+                * Set this back to sbp2_login so we fall back and
+                * retry login on bus reset.
+                */
+               PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+       }
+       kref_put(&sd->kref, release_sbp2_device);
+}
+
+static int sbp2_probe(struct device *dev)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd;
+       struct fw_csr_iterator ci;
+       struct Scsi_Host *host;
+       int i, key, value, err;
+       u32 model, firmware_revision;
+
+       err = -ENOMEM;
+       host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd));
+       if (host == NULL)
+               goto fail;
+
+       sd = (struct sbp2_device *) host->hostdata;
+       unit->device.driver_data = sd;
+       sd->unit = unit;
+       INIT_LIST_HEAD(&sd->orb_list);
+       kref_init(&sd->kref);
+
+       sd->address_handler.length = 0x100;
+       sd->address_handler.address_callback = sbp2_status_write;
+       sd->address_handler.callback_data = sd;
+
+       err = fw_core_add_address_handler(&sd->address_handler,
+                                         &fw_high_memory_region);
+       if (err < 0)
+               goto fail_host;
+
+       err = fw_device_enable_phys_dma(device);
+       if (err < 0)
+               goto fail_address_handler;
+
+       err = scsi_add_host(host, &unit->device);
+       if (err < 0)
+               goto fail_address_handler;
+
+       /*
+        * Scan unit directory to get management agent address,
+        * firmware revison and model.  Initialize firmware_revision
+        * and model to values that wont match anything in our table.
+        */
+       firmware_revision = 0xff000000;
+       model = 0xff000000;
+       fw_csr_iterator_init(&ci, unit->directory);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               switch (key) {
+               case CSR_DEPENDENT_INFO | CSR_OFFSET:
+                       sd->management_agent_address =
+                               0xfffff0000000ULL + 4 * value;
+                       break;
+               case SBP2_FIRMWARE_REVISION:
+                       firmware_revision = value;
+                       break;
+               case CSR_MODEL:
+                       model = value;
+                       break;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
+               if (sbp2_workarounds_table[i].firmware_revision !=
+                   (firmware_revision & 0xffffff00))
+                       continue;
+               if (sbp2_workarounds_table[i].model != model &&
+                   sbp2_workarounds_table[i].model != ~0)
+                       continue;
+               sd->workarounds |= sbp2_workarounds_table[i].workarounds;
+               break;
+       }
+
+       if (sd->workarounds)
+               fw_notify("Workarounds for node %s: 0x%x "
+                         "(firmware_revision 0x%06x, model_id 0x%06x)\n",
+                         unit->device.bus_id,
+                         sd->workarounds, firmware_revision, model);
+
+       get_device(&unit->device);
+
+       /*
+        * We schedule work to do the login so we can easily
+        * reschedule retries. Always get the ref before scheduling
+        * work.
+        */
+       INIT_DELAYED_WORK(&sd->work, sbp2_login);
+       if (schedule_delayed_work(&sd->work, 0))
+               kref_get(&sd->kref);
+
+       return 0;
+
+ fail_address_handler:
+       fw_core_remove_address_handler(&sd->address_handler);
+ fail_host:
+       scsi_host_put(host);
+ fail:
+       return err;
+}
+
+static int sbp2_remove(struct device *dev)
+{
+       struct fw_unit *unit = fw_unit(dev);
+       struct sbp2_device *sd = unit->device.driver_data;
+
+       kref_put(&sd->kref, release_sbp2_device);
+
+       return 0;
+}
+
+static void sbp2_reconnect(struct work_struct *work)
+{
+       struct sbp2_device *sd =
+               container_of(work, struct sbp2_device, work.work);
+       struct fw_unit *unit = sd->unit;
+       struct fw_device *device = fw_device(unit->device.parent);
+       int generation, node_id, local_node_id;
+
+       generation    = device->card->generation;
+       node_id       = device->node->node_id;
+       local_node_id = device->card->local_node->node_id;
+
+       if (sbp2_send_management_orb(unit, node_id, generation,
+                                    SBP2_RECONNECT_REQUEST,
+                                    sd->login_id, NULL) < 0) {
+               if (sd->retries++ >= 5) {
+                       fw_error("failed to reconnect to %s\n",
+                                unit->device.bus_id);
+                       /* Fall back and try to log in again. */
+                       sd->retries = 0;
+                       PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+               }
+               schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+               return;
+       }
+
+       sd->generation   = generation;
+       sd->node_id      = node_id;
+       sd->address_high = local_node_id << 16;
+
+       fw_notify("reconnected to unit %s (%d retries)\n",
+                 unit->device.bus_id, sd->retries);
+       sbp2_agent_reset(unit);
+       sbp2_cancel_orbs(unit);
+       kref_put(&sd->kref, release_sbp2_device);
+}
+
+static void sbp2_update(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_device *sd = unit->device.driver_data;
+
+       sd->retries = 0;
+       fw_device_enable_phys_dma(device);
+       if (schedule_delayed_work(&sd->work, 0))
+               kref_get(&sd->kref);
+}
+
+#define SBP2_UNIT_SPEC_ID_ENTRY        0x0000609e
+#define SBP2_SW_VERSION_ENTRY  0x00010483
+
+static const struct fw_device_id sbp2_id_table[] = {
+       {
+               .match_flags  = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION,
+               .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY,
+               .version      = SBP2_SW_VERSION_ENTRY,
+       },
+       { }
+};
+
+static struct fw_driver sbp2_driver = {
+       .driver   = {
+               .owner  = THIS_MODULE,
+               .name   = sbp2_driver_name,
+               .bus    = &fw_bus_type,
+               .probe  = sbp2_probe,
+               .remove = sbp2_remove,
+       },
+       .update   = sbp2_update,
+       .id_table = sbp2_id_table,
+};
+
+static unsigned int
+sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
+{
+       int sam_status;
+
+       sense_data[0] = 0x70;
+       sense_data[1] = 0x0;
+       sense_data[2] = sbp2_status[1];
+       sense_data[3] = sbp2_status[4];
+       sense_data[4] = sbp2_status[5];
+       sense_data[5] = sbp2_status[6];
+       sense_data[6] = sbp2_status[7];
+       sense_data[7] = 10;
+       sense_data[8] = sbp2_status[8];
+       sense_data[9] = sbp2_status[9];
+       sense_data[10] = sbp2_status[10];
+       sense_data[11] = sbp2_status[11];
+       sense_data[12] = sbp2_status[2];
+       sense_data[13] = sbp2_status[3];
+       sense_data[14] = sbp2_status[12];
+       sense_data[15] = sbp2_status[13];
+
+       sam_status = sbp2_status[0] & 0x3f;
+
+       switch (sam_status) {
+       case SAM_STAT_GOOD:
+       case SAM_STAT_CHECK_CONDITION:
+       case SAM_STAT_CONDITION_MET:
+       case SAM_STAT_BUSY:
+       case SAM_STAT_RESERVATION_CONFLICT:
+       case SAM_STAT_COMMAND_TERMINATED:
+               return DID_OK << 16 | sam_status;
+
+       default:
+               return DID_ERROR << 16;
+       }
+}
+
+static void
+complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+{
+       struct sbp2_command_orb *orb = (struct sbp2_command_orb *)base_orb;
+       struct fw_unit *unit = orb->unit;
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct scatterlist *sg;
+       int result;
+
+       if (status != NULL) {
+               if (STATUS_GET_DEAD(*status))
+                       sbp2_agent_reset(unit);
+
+               switch (STATUS_GET_RESPONSE(*status)) {
+               case SBP2_STATUS_REQUEST_COMPLETE:
+                       result = DID_OK << 16;
+                       break;
+               case SBP2_STATUS_TRANSPORT_FAILURE:
+                       result = DID_BUS_BUSY << 16;
+                       break;
+               case SBP2_STATUS_ILLEGAL_REQUEST:
+               case SBP2_STATUS_VENDOR_DEPENDENT:
+               default:
+                       result = DID_ERROR << 16;
+                       break;
+               }
+
+               if (result == DID_OK << 16 && STATUS_GET_LEN(*status) > 1)
+                       result = sbp2_status_to_sense_data(STATUS_GET_DATA(*status),
+                                                          orb->cmd->sense_buffer);
+       } else {
+               /*
+                * If the orb completes with status == NULL, something
+                * went wrong, typically a bus reset happened mid-orb
+                * or when sending the write (less likely).
+                */
+               result = DID_BUS_BUSY << 16;
+       }
+
+       dma_unmap_single(device->card->device, orb->base.request_bus,
+                        sizeof(orb->request), DMA_TO_DEVICE);
+
+       if (orb->cmd->use_sg > 0) {
+               sg = (struct scatterlist *)orb->cmd->request_buffer;
+               dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+                            orb->cmd->sc_data_direction);
+       }
+
+       if (orb->page_table_bus != 0)
+               dma_unmap_single(device->card->device, orb->page_table_bus,
+                                sizeof(orb->page_table_bus), DMA_TO_DEVICE);
+
+       if (orb->request_buffer_bus != 0)
+               dma_unmap_single(device->card->device, orb->request_buffer_bus,
+                                sizeof(orb->request_buffer_bus),
+                                DMA_FROM_DEVICE);
+
+       orb->cmd->result = result;
+       orb->done(orb->cmd);
+       kfree(orb);
+}
+
+static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
+{
+       struct sbp2_device *sd =
+               (struct sbp2_device *)orb->cmd->device->host->hostdata;
+       struct fw_unit *unit = sd->unit;
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct scatterlist *sg;
+       int sg_len, l, i, j, count;
+       size_t size;
+       dma_addr_t sg_addr;
+
+       sg = (struct scatterlist *)orb->cmd->request_buffer;
+       count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+                          orb->cmd->sc_data_direction);
+       if (count == 0)
+               goto fail;
+
+       /*
+        * Handle the special case where there is only one element in
+        * the scatter list by converting it to an immediate block
+        * request. This is also a workaround for broken devices such
+        * as the second generation iPod which doesn't support page
+        * tables.
+        */
+       if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
+               orb->request.data_descriptor.high = sd->address_high;
+               orb->request.data_descriptor.low  = sg_dma_address(sg);
+               orb->request.misc |=
+                       COMMAND_ORB_DATA_SIZE(sg_dma_len(sg));
+               return 0;
+       }
+
+       /*
+        * Convert the scatterlist to an sbp2 page table.  If any
+        * scatterlist entries are too big for sbp2, we split them as we
+        * go.  Even if we ask the block I/O layer to not give us sg
+        * elements larger than 65535 bytes, some IOMMUs may merge sg elements
+        * during DMA mapping, and Linux currently doesn't prevent this.
+        */
+       for (i = 0, j = 0; i < count; i++) {
+               sg_len = sg_dma_len(sg + i);
+               sg_addr = sg_dma_address(sg + i);
+               while (sg_len) {
+                       l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
+                       orb->page_table[j].low = sg_addr;
+                       orb->page_table[j].high = (l << 16);
+                       sg_addr += l;
+                       sg_len -= l;
+                       j++;
+               }
+       }
+
+       size = sizeof(orb->page_table[0]) * j;
+
+       /*
+        * The data_descriptor pointer is the one case where we need
+        * to fill in the node ID part of the address.  All other
+        * pointers assume that the data referenced reside on the
+        * initiator (i.e. us), but data_descriptor can refer to data
+        * on other nodes so we need to put our ID in descriptor.high.
+        */
+
+       orb->page_table_bus =
+               dma_map_single(device->card->device, orb->page_table,
+                              size, DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->page_table_bus))
+               goto fail_page_table;
+       orb->request.data_descriptor.high = sd->address_high;
+       orb->request.data_descriptor.low  = orb->page_table_bus;
+       orb->request.misc |=
+               COMMAND_ORB_PAGE_TABLE_PRESENT |
+               COMMAND_ORB_DATA_SIZE(j);
+
+       fw_memcpy_to_be32(orb->page_table, orb->page_table, size);
+
+       return 0;
+
+ fail_page_table:
+       dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+                    orb->cmd->sc_data_direction);
+ fail:
+       return -ENOMEM;
+}
+
+/* SCSI stack integration */
+
+static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+{
+       struct sbp2_device *sd =
+               (struct sbp2_device *)cmd->device->host->hostdata;
+       struct fw_unit *unit = sd->unit;
+       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_command_orb *orb;
+
+       /*
+        * Bidirectional commands are not yet implemented, and unknown
+        * transfer direction not handled.
+        */
+       if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
+               fw_error("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
+               cmd->result = DID_ERROR << 16;
+               done(cmd);
+               return 0;
+       }
+
+       orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
+       if (orb == NULL) {
+               fw_notify("failed to alloc orb\n");
+               goto fail_alloc;
+       }
+
+       /* Initialize rcode to something not RCODE_COMPLETE. */
+       orb->base.rcode = -1;
+       orb->base.request_bus =
+               dma_map_single(device->card->device, &orb->request,
+                              sizeof(orb->request), DMA_TO_DEVICE);
+       if (dma_mapping_error(orb->base.request_bus))
+               goto fail_mapping;
+
+       orb->unit = unit;
+       orb->done = done;
+       orb->cmd  = cmd;
+
+       orb->request.next.high   = SBP2_ORB_NULL;
+       orb->request.next.low    = 0x0;
+       /*
+        * At speed 100 we can do 512 bytes per packet, at speed 200,
+        * 1024 bytes per packet etc.  The SBP-2 max_payload field
+        * specifies the max payload size as 2 ^ (max_payload + 2), so
+        * if we set this to max_speed + 7, we get the right value.
+        */
+       orb->request.misc =
+               COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) |
+               COMMAND_ORB_SPEED(device->node->max_speed) |
+               COMMAND_ORB_NOTIFY;
+
+       if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+               orb->request.misc |=
+                       COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA);
+       else if (cmd->sc_data_direction == DMA_TO_DEVICE)
+               orb->request.misc |=
+                       COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
+
+       if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+               goto fail_map_payload;
+
+       fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
+
+       memset(orb->request.command_block,
+              0, sizeof(orb->request.command_block));
+       memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+       orb->base.callback = complete_command_orb;
+
+       sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
+                     sd->command_block_agent_address + SBP2_ORB_POINTER);
+
+       return 0;
+
+ fail_map_payload:
+       dma_unmap_single(device->card->device, orb->base.request_bus,
+                        sizeof(orb->request), DMA_TO_DEVICE);
+ fail_mapping:
+       kfree(orb);
+ fail_alloc:
+       return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
+{
+       struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
+
+       sdev->allow_restart = 1;
+
+       if (sd->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+               sdev->inquiry_len = 36;
+       return 0;
+}
+
+static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
+{
+       struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
+       struct fw_unit *unit = sd->unit;
+
+       sdev->use_10_for_rw = 1;
+
+       if (sdev->type == TYPE_ROM)
+               sdev->use_10_for_ms = 1;
+       if (sdev->type == TYPE_DISK &&
+           sd->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
+               sdev->skip_ms_page_8 = 1;
+       if (sd->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) {
+               fw_notify("setting fix_capacity for %s\n", unit->device.bus_id);
+               sdev->fix_capacity = 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Called by scsi stack when something has really gone wrong.  Usually
+ * called when a command has timed-out for some reason.
+ */
+static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
+{
+       struct sbp2_device *sd =
+               (struct sbp2_device *)cmd->device->host->hostdata;
+       struct fw_unit *unit = sd->unit;
+
+       fw_notify("sbp2_scsi_abort\n");
+       sbp2_agent_reset(unit);
+       sbp2_cancel_orbs(unit);
+
+       return SUCCESS;
+}
+
+static struct scsi_host_template scsi_driver_template = {
+       .module                 = THIS_MODULE,
+       .name                   = "SBP-2 IEEE-1394",
+       .proc_name              = (char *)sbp2_driver_name,
+       .queuecommand           = sbp2_scsi_queuecommand,
+       .slave_alloc            = sbp2_scsi_slave_alloc,
+       .slave_configure        = sbp2_scsi_slave_configure,
+       .eh_abort_handler       = sbp2_scsi_abort,
+       .this_id                = -1,
+       .sg_tablesize           = SG_ALL,
+       .use_clustering         = ENABLE_CLUSTERING,
+       .cmd_per_lun            = 1,
+       .can_queue              = 1,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("SCSI over IEEE1394");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
+
+/* Provide a module alias so root-on-sbp2 initrds don't break. */
+#ifndef CONFIG_IEEE1394_SBP2_MODULE
+MODULE_ALIAS("sbp2");
+#endif
+
+static int __init sbp2_init(void)
+{
+       return driver_register(&sbp2_driver.driver);
+}
+
+static void __exit sbp2_cleanup(void)
+{
+       driver_unregister(&sbp2_driver.driver);
+}
+
+module_init(sbp2_init);
+module_exit(sbp2_cleanup);
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c
new file mode 100644 (file)
index 0000000..7aebb8a
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Incremental bus scan, based on bus topology
+ *
+ * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/module.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+
+#define SELF_ID_PHY_ID(q)              (((q) >> 24) & 0x3f)
+#define SELF_ID_EXTENDED(q)            (((q) >> 23) & 0x01)
+#define SELF_ID_LINK_ON(q)             (((q) >> 22) & 0x01)
+#define SELF_ID_GAP_COUNT(q)           (((q) >> 16) & 0x3f)
+#define SELF_ID_PHY_SPEED(q)           (((q) >> 14) & 0x03)
+#define SELF_ID_CONTENDER(q)           (((q) >> 11) & 0x01)
+#define SELF_ID_PHY_INITIATOR(q)       (((q) >>  1) & 0x01)
+#define SELF_ID_MORE_PACKETS(q)                (((q) >>  0) & 0x01)
+
+#define SELF_ID_EXT_SEQUENCE(q)                (((q) >> 20) & 0x07)
+
+static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
+{
+       u32 q;
+       int port_type, shift, seq;
+
+       *total_port_count = 0;
+       *child_port_count = 0;
+
+       shift = 6;
+       q = *sid;
+       seq = 0;
+
+       while (1) {
+               port_type = (q >> shift) & 0x03;
+               switch (port_type) {
+               case SELFID_PORT_CHILD:
+                       (*child_port_count)++;
+               case SELFID_PORT_PARENT:
+               case SELFID_PORT_NCONN:
+                       (*total_port_count)++;
+               case SELFID_PORT_NONE:
+                       break;
+               }
+
+               shift -= 2;
+               if (shift == 0) {
+                       if (!SELF_ID_MORE_PACKETS(q))
+                               return sid + 1;
+
+                       shift = 16;
+                       sid++;
+                       q = *sid;
+
+                       /*
+                        * Check that the extra packets actually are
+                        * extended self ID packets and that the
+                        * sequence numbers in the extended self ID
+                        * packets increase as expected.
+                        */
+
+                       if (!SELF_ID_EXTENDED(q) ||
+                           seq != SELF_ID_EXT_SEQUENCE(q))
+                               return NULL;
+
+                       seq++;
+               }
+       }
+}
+
+static int get_port_type(u32 *sid, int port_index)
+{
+       int index, shift;
+
+       index = (port_index + 5) / 8;
+       shift = 16 - ((port_index + 5) & 7) * 2;
+       return (sid[index] >> shift) & 0x03;
+}
+
+static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
+{
+       struct fw_node *node;
+
+       node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]),
+                      GFP_ATOMIC);
+       if (node == NULL)
+               return NULL;
+
+       node->color = color;
+       node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid);
+       node->link_on = SELF_ID_LINK_ON(sid);
+       node->phy_speed = SELF_ID_PHY_SPEED(sid);
+       node->port_count = port_count;
+
+       atomic_set(&node->ref_count, 1);
+       INIT_LIST_HEAD(&node->link);
+
+       return node;
+}
+
+/*
+ * Compute the maximum hop count for this node and it's children.  The
+ * maximum hop count is the maximum number of connections between any
+ * two nodes in the subtree rooted at this node.  We need this for
+ * setting the gap count.  As we build the tree bottom up in
+ * build_tree() below, this is fairly easy to do: for each node we
+ * maintain the max hop count and the max depth, ie the number of hops
+ * to the furthest leaf.  Computing the max hop count breaks down into
+ * two cases: either the path goes through this node, in which case
+ * the hop count is the sum of the two biggest child depths plus 2.
+ * Or it could be the case that the max hop path is entirely
+ * containted in a child tree, in which case the max hop count is just
+ * the max hop count of this child.
+ */
+static void update_hop_count(struct fw_node *node)
+{
+       int depths[2] = { -1, -1 };
+       int max_child_hops = 0;
+       int i;
+
+       for (i = 0; i < node->port_count; i++) {
+               if (node->ports[i].node == NULL)
+                       continue;
+
+               if (node->ports[i].node->max_hops > max_child_hops)
+                       max_child_hops = node->ports[i].node->max_hops;
+
+               if (node->ports[i].node->max_depth > depths[0]) {
+                       depths[1] = depths[0];
+                       depths[0] = node->ports[i].node->max_depth;
+               } else if (node->ports[i].node->max_depth > depths[1])
+                       depths[1] = node->ports[i].node->max_depth;
+       }
+
+       node->max_depth = depths[0] + 1;
+       node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2);
+}
+
+
+/**
+ * build_tree - Build the tree representation of the topology
+ * @self_ids: array of self IDs to create the tree from
+ * @self_id_count: the length of the self_ids array
+ * @local_id: the node ID of the local node
+ *
+ * This function builds the tree representation of the topology given
+ * by the self IDs from the latest bus reset.  During the construction
+ * of the tree, the function checks that the self IDs are valid and
+ * internally consistent.  On succcess this funtions returns the
+ * fw_node corresponding to the local card otherwise NULL.
+ */
+static struct fw_node *build_tree(struct fw_card *card,
+                                 u32 *sid, int self_id_count)
+{
+       struct fw_node *node, *child, *local_node, *irm_node;
+       struct list_head stack, *h;
+       u32 *next_sid, *end, q;
+       int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
+       int gap_count, topology_type;
+
+       local_node = NULL;
+       node = NULL;
+       INIT_LIST_HEAD(&stack);
+       stack_depth = 0;
+       end = sid + self_id_count;
+       phy_id = 0;
+       irm_node = NULL;
+       gap_count = SELF_ID_GAP_COUNT(*sid);
+       topology_type = 0;
+
+       while (sid < end) {
+               next_sid = count_ports(sid, &port_count, &child_port_count);
+
+               if (next_sid == NULL) {
+                       fw_error("Inconsistent extended self IDs.\n");
+                       return NULL;
+               }
+
+               q = *sid;
+               if (phy_id != SELF_ID_PHY_ID(q)) {
+                       fw_error("PHY ID mismatch in self ID: %d != %d.\n",
+                                phy_id, SELF_ID_PHY_ID(q));
+                       return NULL;
+               }
+
+               if (child_port_count > stack_depth) {
+                       fw_error("Topology stack underflow\n");
+                       return NULL;
+               }
+
+               /*
+                * Seek back from the top of our stack to find the
+                * start of the child nodes for this node.
+                */
+               for (i = 0, h = &stack; i < child_port_count; i++)
+                       h = h->prev;
+               child = fw_node(h);
+
+               node = fw_node_create(q, port_count, card->color);
+               if (node == NULL) {
+                       fw_error("Out of memory while building topology.");
+                       return NULL;
+               }
+
+               if (phy_id == (card->node_id & 0x3f))
+                       local_node = node;
+
+               if (SELF_ID_CONTENDER(q))
+                       irm_node = node;
+
+               if (node->phy_speed == SCODE_BETA)
+                       topology_type |= FW_TOPOLOGY_B;
+               else
+                       topology_type |= FW_TOPOLOGY_A;
+
+               parent_count = 0;
+
+               for (i = 0; i < port_count; i++) {
+                       switch (get_port_type(sid, i)) {
+                       case SELFID_PORT_PARENT:
+                               /*
+                                * Who's your daddy?  We dont know the
+                                * parent node at this time, so we
+                                * temporarily abuse node->color for
+                                * remembering the entry in the
+                                * node->ports array where the parent
+                                * node should be.  Later, when we
+                                * handle the parent node, we fix up
+                                * the reference.
+                                */
+                               parent_count++;
+                               node->color = i;
+                               break;
+
+                       case SELFID_PORT_CHILD:
+                               node->ports[i].node = child;
+                               /*
+                                * Fix up parent reference for this
+                                * child node.
+                                */
+                               child->ports[child->color].node = node;
+                               child->color = card->color;
+                               child = fw_node(child->link.next);
+                               break;
+                       }
+               }
+
+               /*
+                * Check that the node reports exactly one parent
+                * port, except for the root, which of course should
+                * have no parents.
+                */
+               if ((next_sid == end && parent_count != 0) ||
+                   (next_sid < end && parent_count != 1)) {
+                       fw_error("Parent port inconsistency for node %d: "
+                                "parent_count=%d\n", phy_id, parent_count);
+                       return NULL;
+               }
+
+               /* Pop the child nodes off the stack and push the new node. */
+               __list_del(h->prev, &stack);
+               list_add_tail(&node->link, &stack);
+               stack_depth += 1 - child_port_count;
+
+               /*
+                * If all PHYs does not report the same gap count
+                * setting, we fall back to 63 which will force a gap
+                * count reconfiguration and a reset.
+                */
+               if (SELF_ID_GAP_COUNT(q) != gap_count)
+                       gap_count = 63;
+
+               update_hop_count(node);
+
+               sid = next_sid;
+               phy_id++;
+       }
+
+       card->root_node = node;
+       card->irm_node = irm_node;
+       card->gap_count = gap_count;
+       card->topology_type = topology_type;
+
+       return local_node;
+}
+
+typedef void (*fw_node_callback_t)(struct fw_card * card,
+                                  struct fw_node * node,
+                                  struct fw_node * parent);
+
+static void
+for_each_fw_node(struct fw_card *card, struct fw_node *root,
+                fw_node_callback_t callback)
+{
+       struct list_head list;
+       struct fw_node *node, *next, *child, *parent;
+       int i;
+
+       INIT_LIST_HEAD(&list);
+
+       fw_node_get(root);
+       list_add_tail(&root->link, &list);
+       parent = NULL;
+       list_for_each_entry(node, &list, link) {
+               node->color = card->color;
+
+               for (i = 0; i < node->port_count; i++) {
+                       child = node->ports[i].node;
+                       if (!child)
+                               continue;
+                       if (child->color == card->color)
+                               parent = child;
+                       else {
+                               fw_node_get(child);
+                               list_add_tail(&child->link, &list);
+                       }
+               }
+
+               callback(card, node, parent);
+       }
+
+       list_for_each_entry_safe(node, next, &list, link)
+               fw_node_put(node);
+}
+
+static void
+report_lost_node(struct fw_card *card,
+                struct fw_node *node, struct fw_node *parent)
+{
+       fw_node_event(card, node, FW_NODE_DESTROYED);
+       fw_node_put(node);
+}
+
+static void
+report_found_node(struct fw_card *card,
+                 struct fw_node *node, struct fw_node *parent)
+{
+       int b_path = (node->phy_speed == SCODE_BETA);
+
+       if (parent != NULL) {
+               /* min() macro doesn't work here with gcc 3.4 */
+               node->max_speed = parent->max_speed < node->phy_speed ?
+                                       parent->max_speed : node->phy_speed;
+               node->b_path = parent->b_path && b_path;
+       } else {
+               node->max_speed = node->phy_speed;
+               node->b_path = b_path;
+       }
+
+       fw_node_event(card, node, FW_NODE_CREATED);
+}
+
+void fw_destroy_nodes(struct fw_card *card)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       card->color++;
+       if (card->local_node != NULL)
+               for_each_fw_node(card, card->local_node, report_lost_node);
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
+{
+       struct fw_node *tree;
+       int i;
+
+       tree = node1->ports[port].node;
+       node0->ports[port].node = tree;
+       for (i = 0; i < tree->port_count; i++) {
+               if (tree->ports[i].node == node1) {
+                       tree->ports[i].node = node0;
+                       break;
+               }
+       }
+}
+
+/**
+ * update_tree - compare the old topology tree for card with the new
+ * one specified by root.  Queue the nodes and mark them as either
+ * found, lost or updated.  Update the nodes in the card topology tree
+ * as we go.
+ */
+static void
+update_tree(struct fw_card *card, struct fw_node *root)
+{
+       struct list_head list0, list1;
+       struct fw_node *node0, *node1;
+       int i, event;
+
+       INIT_LIST_HEAD(&list0);
+       list_add_tail(&card->local_node->link, &list0);
+       INIT_LIST_HEAD(&list1);
+       list_add_tail(&root->link, &list1);
+
+       node0 = fw_node(list0.next);
+       node1 = fw_node(list1.next);
+
+       while (&node0->link != &list0) {
+
+               /* assert(node0->port_count == node1->port_count); */
+               if (node0->link_on && !node1->link_on)
+                       event = FW_NODE_LINK_OFF;
+               else if (!node0->link_on && node1->link_on)
+                       event = FW_NODE_LINK_ON;
+               else
+                       event = FW_NODE_UPDATED;
+
+               node0->node_id = node1->node_id;
+               node0->color = card->color;
+               node0->link_on = node1->link_on;
+               node0->initiated_reset = node1->initiated_reset;
+               node0->max_hops = node1->max_hops;
+               node1->color = card->color;
+               fw_node_event(card, node0, event);
+
+               if (card->root_node == node1)
+                       card->root_node = node0;
+               if (card->irm_node == node1)
+                       card->irm_node = node0;
+
+               for (i = 0; i < node0->port_count; i++) {
+                       if (node0->ports[i].node && node1->ports[i].node) {
+                               /*
+                                * This port didn't change, queue the
+                                * connected node for further
+                                * investigation.
+                                */
+                               if (node0->ports[i].node->color == card->color)
+                                       continue;
+                               list_add_tail(&node0->ports[i].node->link,
+                                             &list0);
+                               list_add_tail(&node1->ports[i].node->link,
+                                             &list1);
+                       } else if (node0->ports[i].node) {
+                               /*
+                                * The nodes connected here were
+                                * unplugged; unref the lost nodes and
+                                * queue FW_NODE_LOST callbacks for
+                                * them.
+                                */
+
+                               for_each_fw_node(card, node0->ports[i].node,
+                                                report_lost_node);
+                               node0->ports[i].node = NULL;
+                       } else if (node1->ports[i].node) {
+                               /*
+                                * One or more node were connected to
+                                * this port. Move the new nodes into
+                                * the tree and queue FW_NODE_CREATED
+                                * callbacks for them.
+                                */
+                               move_tree(node0, node1, i);
+                               for_each_fw_node(card, node0->ports[i].node,
+                                                report_found_node);
+                       }
+               }
+
+               node0 = fw_node(node0->link.next);
+               node1 = fw_node(node1->link.next);
+       }
+}
+
+static void
+update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count)
+{
+       int node_count;
+
+       card->topology_map[1]++;
+       node_count = (card->root_node->node_id & 0x3f) + 1;
+       card->topology_map[2] = (node_count << 16) | self_id_count;
+       card->topology_map[0] = (self_id_count + 2) << 16;
+       memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
+       fw_compute_block_crc(card->topology_map);
+}
+
+void
+fw_core_handle_bus_reset(struct fw_card *card,
+                        int node_id, int generation,
+                        int self_id_count, u32 * self_ids)
+{
+       struct fw_node *local_node;
+       unsigned long flags;
+
+       fw_flush_transactions(card);
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       /*
+        * If the new topology has a different self_id_count the topology
+        * changed, either nodes were added or removed. In that case we
+        * reset the IRM reset counter.
+        */
+       if (card->self_id_count != self_id_count)
+               card->bm_retries = 0;
+
+       card->node_id = node_id;
+       card->generation = generation;
+       card->reset_jiffies = jiffies;
+       schedule_delayed_work(&card->work, 0);
+
+       local_node = build_tree(card, self_ids, self_id_count);
+
+       update_topology_map(card, self_ids, self_id_count);
+
+       card->color++;
+
+       if (local_node == NULL) {
+               fw_error("topology build failed\n");
+               /* FIXME: We need to issue a bus reset in this case. */
+       } else if (card->local_node == NULL) {
+               card->local_node = local_node;
+               for_each_fw_node(card, local_node, report_found_node);
+       } else {
+               update_tree(card, local_node);
+       }
+
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+EXPORT_SYMBOL(fw_core_handle_bus_reset);
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h
new file mode 100644 (file)
index 0000000..363b6cb
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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.
+ */
+
+#ifndef __fw_topology_h
+#define __fw_topology_h
+
+enum {
+       FW_TOPOLOGY_A =         0x01,
+       FW_TOPOLOGY_B =         0x02,
+       FW_TOPOLOGY_MIXED =     0x03,
+};
+
+enum {
+       FW_NODE_CREATED =   0x00,
+       FW_NODE_UPDATED =   0x01,
+       FW_NODE_DESTROYED = 0x02,
+       FW_NODE_LINK_ON =   0x03,
+       FW_NODE_LINK_OFF =  0x04,
+};
+
+struct fw_port {
+       struct fw_node *node;
+       unsigned speed : 3; /* S100, S200, ... S3200 */
+};
+
+struct fw_node {
+       u16 node_id;
+       u8 color;
+       u8 port_count;
+       unsigned link_on : 1;
+       unsigned initiated_reset : 1;
+       unsigned b_path : 1;
+       u8 phy_speed : 3; /* As in the self ID packet. */
+       u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on
+                          * the path from the local node to this node. */
+       u8 max_depth : 4; /* Maximum depth to any leaf node */
+       u8 max_hops : 4;  /* Max hops in this sub tree */
+       atomic_t ref_count;
+
+       /* For serializing node topology into a list. */
+       struct list_head link;
+
+       /* Upper layer specific data. */
+       void *data;
+
+       struct fw_port ports[0];
+};
+
+static inline struct fw_node *
+fw_node(struct list_head *l)
+{
+       return list_entry(l, struct fw_node, link);
+}
+
+static inline struct fw_node *
+fw_node_get(struct fw_node *node)
+{
+       atomic_inc(&node->ref_count);
+
+       return node;
+}
+
+static inline void
+fw_node_put(struct fw_node *node)
+{
+       if (atomic_dec_and_test(&node->ref_count))
+               kfree(node);
+}
+
+void
+fw_destroy_nodes(struct fw_card *card);
+
+int
+fw_compute_block_crc(u32 *block);
+
+
+#endif /* __fw_topology_h */
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
new file mode 100644 (file)
index 0000000..80d0121
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * Core IEEE1394 transaction logic
+ *
+ * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+#define HEADER_PRI(pri)                        ((pri) << 0)
+#define HEADER_TCODE(tcode)            ((tcode) << 4)
+#define HEADER_RETRY(retry)            ((retry) << 8)
+#define HEADER_TLABEL(tlabel)          ((tlabel) << 10)
+#define HEADER_DESTINATION(destination)        ((destination) << 16)
+#define HEADER_SOURCE(source)          ((source) << 16)
+#define HEADER_RCODE(rcode)            ((rcode) << 12)
+#define HEADER_OFFSET_HIGH(offset_high)        ((offset_high) << 0)
+#define HEADER_DATA_LENGTH(length)     ((length) << 16)
+#define HEADER_EXTENDED_TCODE(tcode)   ((tcode) << 0)
+
+#define HEADER_GET_TCODE(q)            (((q) >> 4) & 0x0f)
+#define HEADER_GET_TLABEL(q)           (((q) >> 10) & 0x3f)
+#define HEADER_GET_RCODE(q)            (((q) >> 12) & 0x0f)
+#define HEADER_GET_DESTINATION(q)      (((q) >> 16) & 0xffff)
+#define HEADER_GET_SOURCE(q)           (((q) >> 16) & 0xffff)
+#define HEADER_GET_OFFSET_HIGH(q)      (((q) >> 0) & 0xffff)
+#define HEADER_GET_DATA_LENGTH(q)      (((q) >> 16) & 0xffff)
+#define HEADER_GET_EXTENDED_TCODE(q)   (((q) >> 0) & 0xffff)
+
+#define PHY_CONFIG_GAP_COUNT(gap_count)        (((gap_count) << 16) | (1 << 22))
+#define PHY_CONFIG_ROOT_ID(node_id)    ((((node_id) & 0x3f) << 24) | (1 << 23))
+#define PHY_IDENTIFIER(id)             ((id) << 30)
+
+static int
+close_transaction(struct fw_transaction *transaction,
+                 struct fw_card *card, int rcode,
+                 u32 *payload, size_t length)
+{
+       struct fw_transaction *t;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       list_for_each_entry(t, &card->transaction_list, link) {
+               if (t == transaction) {
+                       list_del(&t->link);
+                       card->tlabel_mask &= ~(1 << t->tlabel);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (&t->link != &card->transaction_list) {
+               t->callback(card, rcode, payload, length, t->callback_data);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+/*
+ * Only valid for transactions that are potentially pending (ie have
+ * been sent).
+ */
+int
+fw_cancel_transaction(struct fw_card *card,
+                     struct fw_transaction *transaction)
+{
+       /*
+        * Cancel the packet transmission if it's still queued.  That
+        * will call the packet transmission callback which cancels
+        * the transaction.
+        */
+
+       if (card->driver->cancel_packet(card, &transaction->packet) == 0)
+               return 0;
+
+       /*
+        * If the request packet has already been sent, we need to see
+        * if the transaction is still pending and remove it in that case.
+        */
+
+       return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0);
+}
+EXPORT_SYMBOL(fw_cancel_transaction);
+
+static void
+transmit_complete_callback(struct fw_packet *packet,
+                          struct fw_card *card, int status)
+{
+       struct fw_transaction *t =
+           container_of(packet, struct fw_transaction, packet);
+
+       switch (status) {
+       case ACK_COMPLETE:
+               close_transaction(t, card, RCODE_COMPLETE, NULL, 0);
+               break;
+       case ACK_PENDING:
+               t->timestamp = packet->timestamp;
+               break;
+       case ACK_BUSY_X:
+       case ACK_BUSY_A:
+       case ACK_BUSY_B:
+               close_transaction(t, card, RCODE_BUSY, NULL, 0);
+               break;
+       case ACK_DATA_ERROR:
+               close_transaction(t, card, RCODE_DATA_ERROR, NULL, 0);
+               break;
+       case ACK_TYPE_ERROR:
+               close_transaction(t, card, RCODE_TYPE_ERROR, NULL, 0);
+               break;
+       default:
+               /*
+                * In this case the ack is really a juju specific
+                * rcode, so just forward that to the callback.
+                */
+               close_transaction(t, card, status, NULL, 0);
+               break;
+       }
+}
+
+static void
+fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
+               int node_id, int source_id, int generation, int speed,
+               unsigned long long offset, void *payload, size_t length)
+{
+       int ext_tcode;
+
+       if (tcode > 0x10) {
+               ext_tcode = tcode - 0x10;
+               tcode = TCODE_LOCK_REQUEST;
+       } else
+               ext_tcode = 0;
+
+       packet->header[0] =
+               HEADER_RETRY(RETRY_X) |
+               HEADER_TLABEL(tlabel) |
+               HEADER_TCODE(tcode) |
+               HEADER_DESTINATION(node_id);
+       packet->header[1] =
+               HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
+       packet->header[2] =
+               offset;
+
+       switch (tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+               packet->header[3] = *(u32 *)payload;
+               packet->header_length = 16;
+               packet->payload_length = 0;
+               break;
+
+       case TCODE_LOCK_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+               packet->header[3] =
+                       HEADER_DATA_LENGTH(length) |
+                       HEADER_EXTENDED_TCODE(ext_tcode);
+               packet->header_length = 16;
+               packet->payload = payload;
+               packet->payload_length = length;
+               break;
+
+       case TCODE_READ_QUADLET_REQUEST:
+               packet->header_length = 12;
+               packet->payload_length = 0;
+               break;
+
+       case TCODE_READ_BLOCK_REQUEST:
+               packet->header[3] =
+                       HEADER_DATA_LENGTH(length) |
+                       HEADER_EXTENDED_TCODE(ext_tcode);
+               packet->header_length = 16;
+               packet->payload_length = 0;
+               break;
+       }
+
+       packet->speed = speed;
+       packet->generation = generation;
+       packet->ack = 0;
+}
+
+/**
+ * This function provides low-level access to the IEEE1394 transaction
+ * logic.  Most C programs would use either fw_read(), fw_write() or
+ * fw_lock() instead - those function are convenience wrappers for
+ * this function.  The fw_send_request() function is primarily
+ * provided as a flexible, one-stop entry point for languages bindings
+ * and protocol bindings.
+ *
+ * FIXME: Document this function further, in particular the possible
+ * values for rcode in the callback.  In short, we map ACK_COMPLETE to
+ * RCODE_COMPLETE, internal errors set errno and set rcode to
+ * RCODE_SEND_ERROR (which is out of range for standard ieee1394
+ * rcodes).  All other rcodes are forwarded unchanged.  For all
+ * errors, payload is NULL, length is 0.
+ *
+ * Can not expect the callback to be called before the function
+ * returns, though this does happen in some cases (ACK_COMPLETE and
+ * errors).
+ *
+ * The payload is only used for write requests and must not be freed
+ * until the callback has been called.
+ *
+ * @param card the card from which to send the request
+ * @param tcode the tcode for this transaction.  Do not use
+ *   TCODE_LOCK_REQUEST directly, insted use TCODE_LOCK_MASK_SWAP
+ *   etc. to specify tcode and ext_tcode.
+ * @param node_id the destination node ID (bus ID and PHY ID concatenated)
+ * @param generation the generation for which node_id is valid
+ * @param speed the speed to use for sending the request
+ * @param offset the 48 bit offset on the destination node
+ * @param payload the data payload for the request subaction
+ * @param length the length in bytes of the data to read
+ * @param callback function to be called when the transaction is completed
+ * @param callback_data pointer to arbitrary data, which will be
+ *   passed to the callback
+ */
+void
+fw_send_request(struct fw_card *card, struct fw_transaction *t,
+               int tcode, int node_id, int generation, int speed,
+               unsigned long long offset,
+               void *payload, size_t length,
+               fw_transaction_callback_t callback, void *callback_data)
+{
+       unsigned long flags;
+       int tlabel, source;
+
+       /*
+        * Bump the flush timer up 100ms first of all so we
+        * don't race with a flush timer callback.
+        */
+
+       mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10));
+
+       /*
+        * Allocate tlabel from the bitmap and put the transaction on
+        * the list while holding the card spinlock.
+        */
+
+       spin_lock_irqsave(&card->lock, flags);
+
+       source = card->node_id;
+       tlabel = card->current_tlabel;
+       if (card->tlabel_mask & (1 << tlabel)) {
+               spin_unlock_irqrestore(&card->lock, flags);
+               callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
+               return;
+       }
+
+       card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
+       card->tlabel_mask |= (1 << tlabel);
+
+       list_add_tail(&t->link, &card->transaction_list);
+
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       /* Initialize rest of transaction, fill out packet and send it. */
+       t->node_id = node_id;
+       t->tlabel = tlabel;
+       t->callback = callback;
+       t->callback_data = callback_data;
+
+       fw_fill_request(&t->packet, tcode, t->tlabel,
+                       node_id, source, generation,
+                       speed, offset, payload, length);
+       t->packet.callback = transmit_complete_callback;
+
+       card->driver->send_request(card, &t->packet);
+}
+EXPORT_SYMBOL(fw_send_request);
+
+static void
+transmit_phy_packet_callback(struct fw_packet *packet,
+                            struct fw_card *card, int status)
+{
+       kfree(packet);
+}
+
+static void send_phy_packet(struct fw_card *card, u32 data, int generation)
+{
+       struct fw_packet *packet;
+
+       packet = kzalloc(sizeof(*packet), GFP_ATOMIC);
+       if (packet == NULL)
+               return;
+
+       packet->header[0] = data;
+       packet->header[1] = ~data;
+       packet->header_length = 8;
+       packet->payload_length = 0;
+       packet->speed = SCODE_100;
+       packet->generation = generation;
+       packet->callback = transmit_phy_packet_callback;
+
+       card->driver->send_request(card, packet);
+}
+
+void fw_send_phy_config(struct fw_card *card,
+                       int node_id, int generation, int gap_count)
+{
+       u32 q;
+
+       q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
+               PHY_CONFIG_ROOT_ID(node_id) |
+               PHY_CONFIG_GAP_COUNT(gap_count);
+
+       send_phy_packet(card, q, generation);
+}
+
+void fw_flush_transactions(struct fw_card *card)
+{
+       struct fw_transaction *t, *next;
+       struct list_head list;
+       unsigned long flags;
+
+       INIT_LIST_HEAD(&list);
+       spin_lock_irqsave(&card->lock, flags);
+       list_splice_init(&card->transaction_list, &list);
+       card->tlabel_mask = 0;
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       list_for_each_entry_safe(t, next, &list, link) {
+               card->driver->cancel_packet(card, &t->packet);
+
+               /*
+                * At this point cancel_packet will never call the
+                * transaction callback, since we just took all the
+                * transactions out of the list.  So do it here.
+                */
+               t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
+       }
+}
+
+static struct fw_address_handler *
+lookup_overlapping_address_handler(struct list_head *list,
+                                  unsigned long long offset, size_t length)
+{
+       struct fw_address_handler *handler;
+
+       list_for_each_entry(handler, list, link) {
+               if (handler->offset < offset + length &&
+                   offset < handler->offset + handler->length)
+                       return handler;
+       }
+
+       return NULL;
+}
+
+static struct fw_address_handler *
+lookup_enclosing_address_handler(struct list_head *list,
+                                unsigned long long offset, size_t length)
+{
+       struct fw_address_handler *handler;
+
+       list_for_each_entry(handler, list, link) {
+               if (handler->offset <= offset &&
+                   offset + length <= handler->offset + handler->length)
+                       return handler;
+       }
+
+       return NULL;
+}
+
+static DEFINE_SPINLOCK(address_handler_lock);
+static LIST_HEAD(address_handler_list);
+
+const struct fw_address_region fw_low_memory_region =
+       { .start = 0x000000000000ULL, .end = 0x000100000000ULL,  };
+const struct fw_address_region fw_high_memory_region =
+       { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL,  };
+const struct fw_address_region fw_private_region =
+       { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
+const struct fw_address_region fw_csr_region =
+       { .start = 0xfffff0000000ULL, .end = 0xfffff0000800ULL,  };
+const struct fw_address_region fw_unit_space_region =
+       { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
+EXPORT_SYMBOL(fw_low_memory_region);
+EXPORT_SYMBOL(fw_high_memory_region);
+EXPORT_SYMBOL(fw_private_region);
+EXPORT_SYMBOL(fw_csr_region);
+EXPORT_SYMBOL(fw_unit_space_region);
+
+/**
+ * Allocate a range of addresses in the node space of the OHCI
+ * controller.  When a request is received that falls within the
+ * specified address range, the specified callback is invoked.  The
+ * parameters passed to the callback give the details of the
+ * particular request
+ */
+int
+fw_core_add_address_handler(struct fw_address_handler *handler,
+                           const struct fw_address_region *region)
+{
+       struct fw_address_handler *other;
+       unsigned long flags;
+       int ret = -EBUSY;
+
+       spin_lock_irqsave(&address_handler_lock, flags);
+
+       handler->offset = region->start;
+       while (handler->offset + handler->length <= region->end) {
+               other =
+                   lookup_overlapping_address_handler(&address_handler_list,
+                                                      handler->offset,
+                                                      handler->length);
+               if (other != NULL) {
+                       handler->offset += other->length;
+               } else {
+                       list_add_tail(&handler->link, &address_handler_list);
+                       ret = 0;
+                       break;
+               }
+       }
+
+       spin_unlock_irqrestore(&address_handler_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(fw_core_add_address_handler);
+
+/**
+ * Deallocate a range of addresses allocated with fw_allocate.  This
+ * will call the associated callback one last time with a the special
+ * tcode TCODE_DEALLOCATE, to let the client destroy the registered
+ * callback data.  For convenience, the callback parameters offset and
+ * length are set to the start and the length respectively for the
+ * deallocated region, payload is set to NULL.
+ */
+void fw_core_remove_address_handler(struct fw_address_handler *handler)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&address_handler_lock, flags);
+       list_del(&handler->link);
+       spin_unlock_irqrestore(&address_handler_lock, flags);
+}
+EXPORT_SYMBOL(fw_core_remove_address_handler);
+
+struct fw_request {
+       struct fw_packet response;
+       u32 request_header[4];
+       int ack;
+       u32 length;
+       u32 data[0];
+};
+
+static void
+free_response_callback(struct fw_packet *packet,
+                      struct fw_card *card, int status)
+{
+       struct fw_request *request;
+
+       request = container_of(packet, struct fw_request, response);
+       kfree(request);
+}
+
+void
+fw_fill_response(struct fw_packet *response, u32 *request_header,
+                int rcode, void *payload, size_t length)
+{
+       int tcode, tlabel, extended_tcode, source, destination;
+
+       tcode          = HEADER_GET_TCODE(request_header[0]);
+       tlabel         = HEADER_GET_TLABEL(request_header[0]);
+       source         = HEADER_GET_DESTINATION(request_header[0]);
+       destination    = HEADER_GET_SOURCE(request_header[1]);
+       extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
+
+       response->header[0] =
+               HEADER_RETRY(RETRY_1) |
+               HEADER_TLABEL(tlabel) |
+               HEADER_DESTINATION(destination);
+       response->header[1] =
+               HEADER_SOURCE(source) |
+               HEADER_RCODE(rcode);
+       response->header[2] = 0;
+
+       switch (tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+       case TCODE_WRITE_BLOCK_REQUEST:
+               response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
+               response->header_length = 12;
+               response->payload_length = 0;
+               break;
+
+       case TCODE_READ_QUADLET_REQUEST:
+               response->header[0] |=
+                       HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
+               if (payload != NULL)
+                       response->header[3] = *(u32 *)payload;
+               else
+                       response->header[3] = 0;
+               response->header_length = 16;
+               response->payload_length = 0;
+               break;
+
+       case TCODE_READ_BLOCK_REQUEST:
+       case TCODE_LOCK_REQUEST:
+               response->header[0] |= HEADER_TCODE(tcode + 2);
+               response->header[3] =
+                       HEADER_DATA_LENGTH(length) |
+                       HEADER_EXTENDED_TCODE(extended_tcode);
+               response->header_length = 16;
+               response->payload = payload;
+               response->payload_length = length;
+               break;
+
+       default:
+               BUG();
+               return;
+       }
+}
+EXPORT_SYMBOL(fw_fill_response);
+
+static struct fw_request *
+allocate_request(struct fw_packet *p)
+{
+       struct fw_request *request;
+       u32 *data, length;
+       int request_tcode, t;
+
+       request_tcode = HEADER_GET_TCODE(p->header[0]);
+       switch (request_tcode) {
+       case TCODE_WRITE_QUADLET_REQUEST:
+               data = &p->header[3];
+               length = 4;
+               break;
+
+       case TCODE_WRITE_BLOCK_REQUEST:
+       case TCODE_LOCK_REQUEST:
+               data = p->payload;
+               length = HEADER_GET_DATA_LENGTH(p->header[3]);
+               break;
+
+       case TCODE_READ_QUADLET_REQUEST:
+               data = NULL;
+               length = 4;
+               break;
+
+       case TCODE_READ_BLOCK_REQUEST:
+               data = NULL;
+               length = HEADER_GET_DATA_LENGTH(p->header[3]);
+               break;
+
+       default:
+               BUG();
+               return NULL;
+       }
+
+       request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
+       if (request == NULL)
+               return NULL;
+
+       t = (p->timestamp & 0x1fff) + 4000;
+       if (t >= 8000)
+               t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000;
+       else
+               t = (p->timestamp & ~0x1fff) + t;
+
+       request->response.speed = p->speed;
+       request->response.timestamp = t;
+       request->response.generation = p->generation;
+       request->response.ack = 0;
+       request->response.callback = free_response_callback;
+       request->ack = p->ack;
+       request->length = length;
+       if (data)
+               memcpy(request->data, data, length);
+
+       memcpy(request->request_header, p->header, sizeof(p->header));
+
+       return request;
+}
+
+void
+fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
+{
+       /*
+        * Broadcast packets are reported as ACK_COMPLETE, so this
+        * check is sufficient to ensure we don't send response to
+        * broadcast packets or posted writes.
+        */
+       if (request->ack != ACK_PENDING)
+               return;
+
+       if (rcode == RCODE_COMPLETE)
+               fw_fill_response(&request->response, request->request_header,
+                                rcode, request->data, request->length);
+       else
+               fw_fill_response(&request->response, request->request_header,
+                                rcode, NULL, 0);
+
+       card->driver->send_response(card, &request->response);
+}
+EXPORT_SYMBOL(fw_send_response);
+
+void
+fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
+{
+       struct fw_address_handler *handler;
+       struct fw_request *request;
+       unsigned long long offset;
+       unsigned long flags;
+       int tcode, destination, source;
+
+       if (p->payload_length > 2048) {
+               /* FIXME: send error response. */
+               return;
+       }
+
+       if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
+               return;
+
+       request = allocate_request(p);
+       if (request == NULL) {
+               /* FIXME: send statically allocated busy packet. */
+               return;
+       }
+
+       offset      =
+               ((unsigned long long)
+                HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2];
+       tcode       = HEADER_GET_TCODE(p->header[0]);
+       destination = HEADER_GET_DESTINATION(p->header[0]);
+       source      = HEADER_GET_SOURCE(p->header[0]);
+
+       spin_lock_irqsave(&address_handler_lock, flags);
+       handler = lookup_enclosing_address_handler(&address_handler_list,
+                                                  offset, request->length);
+       spin_unlock_irqrestore(&address_handler_lock, flags);
+
+       /*
+        * FIXME: lookup the fw_node corresponding to the sender of
+        * this request and pass that to the address handler instead
+        * of the node ID.  We may also want to move the address
+        * allocations to fw_node so we only do this callback if the
+        * upper layers registered it for this node.
+        */
+
+       if (handler == NULL)
+               fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+       else
+               handler->address_callback(card, request,
+                                         tcode, destination, source,
+                                         p->generation, p->speed, offset,
+                                         request->data, request->length,
+                                         handler->callback_data);
+}
+EXPORT_SYMBOL(fw_core_handle_request);
+
+void
+fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
+{
+       struct fw_transaction *t;
+       unsigned long flags;
+       u32 *data;
+       size_t data_length;
+       int tcode, tlabel, destination, source, rcode;
+
+       tcode       = HEADER_GET_TCODE(p->header[0]);
+       tlabel      = HEADER_GET_TLABEL(p->header[0]);
+       destination = HEADER_GET_DESTINATION(p->header[0]);
+       source      = HEADER_GET_SOURCE(p->header[1]);
+       rcode       = HEADER_GET_RCODE(p->header[1]);
+
+       spin_lock_irqsave(&card->lock, flags);
+       list_for_each_entry(t, &card->transaction_list, link) {
+               if (t->node_id == source && t->tlabel == tlabel) {
+                       list_del(&t->link);
+                       card->tlabel_mask &= ~(1 << t->tlabel);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (&t->link == &card->transaction_list) {
+               fw_notify("Unsolicited response (source %x, tlabel %x)\n",
+                         source, tlabel);
+               return;
+       }
+
+       /*
+        * FIXME: sanity check packet, is length correct, does tcodes
+        * and addresses match.
+        */
+
+       switch (tcode) {
+       case TCODE_READ_QUADLET_RESPONSE:
+               data = (u32 *) &p->header[3];
+               data_length = 4;
+               break;
+
+       case TCODE_WRITE_RESPONSE:
+               data = NULL;
+               data_length = 0;
+               break;
+
+       case TCODE_READ_BLOCK_RESPONSE:
+       case TCODE_LOCK_RESPONSE:
+               data = p->payload;
+               data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
+               break;
+
+       default:
+               /* Should never happen, this is just to shut up gcc. */
+               data = NULL;
+               data_length = 0;
+               break;
+       }
+
+       t->callback(card, rcode, data, data_length, t->callback_data);
+}
+EXPORT_SYMBOL(fw_core_handle_response);
+
+const struct fw_address_region topology_map_region =
+       { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
+
+static void
+handle_topology_map(struct fw_card *card, struct fw_request *request,
+                   int tcode, int destination, int source,
+                   int generation, int speed,
+                   unsigned long long offset,
+                   void *payload, size_t length, void *callback_data)
+{
+       int i, start, end;
+       u32 *map;
+
+       if (!TCODE_IS_READ_REQUEST(tcode)) {
+               fw_send_response(card, request, RCODE_TYPE_ERROR);
+               return;
+       }
+
+       if ((offset & 3) > 0 || (length & 3) > 0) {
+               fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+               return;
+       }
+
+       start = (offset - topology_map_region.start) / 4;
+       end = start + length / 4;
+       map = payload;
+
+       for (i = 0; i < length / 4; i++)
+               map[i] = cpu_to_be32(card->topology_map[start + i]);
+
+       fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+static struct fw_address_handler topology_map = {
+       .length                 = 0x200,
+       .address_callback       = handle_topology_map,
+};
+
+const struct fw_address_region registers_region =
+       { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, };
+
+static void
+handle_registers(struct fw_card *card, struct fw_request *request,
+                int tcode, int destination, int source,
+                int generation, int speed,
+                unsigned long long offset,
+                void *payload, size_t length, void *callback_data)
+{
+       int reg = offset - CSR_REGISTER_BASE;
+       unsigned long long bus_time;
+       __be32 *data = payload;
+
+       switch (reg) {
+       case CSR_CYCLE_TIME:
+       case CSR_BUS_TIME:
+               if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {
+                       fw_send_response(card, request, RCODE_TYPE_ERROR);
+                       break;
+               }
+
+               bus_time = card->driver->get_bus_time(card);
+               if (reg == CSR_CYCLE_TIME)
+                       *data = cpu_to_be32(bus_time);
+               else
+                       *data = cpu_to_be32(bus_time >> 25);
+               fw_send_response(card, request, RCODE_COMPLETE);
+               break;
+
+       case CSR_BUS_MANAGER_ID:
+       case CSR_BANDWIDTH_AVAILABLE:
+       case CSR_CHANNELS_AVAILABLE_HI:
+       case CSR_CHANNELS_AVAILABLE_LO:
+               /*
+                * FIXME: these are handled by the OHCI hardware and
+                * the stack never sees these request. If we add
+                * support for a new type of controller that doesn't
+                * handle this in hardware we need to deal with these
+                * transactions.
+                */
+               BUG();
+               break;
+
+       case CSR_BUSY_TIMEOUT:
+               /* FIXME: Implement this. */
+       default:
+               fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+               break;
+       }
+}
+
+static struct fw_address_handler registers = {
+       .length                 = 0x400,
+       .address_callback       = handle_registers,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
+MODULE_LICENSE("GPL");
+
+static const u32 vendor_textual_descriptor[] = {
+       /* textual descriptor leaf () */
+       0x00060000,
+       0x00000000,
+       0x00000000,
+       0x4c696e75,             /* L i n u */
+       0x78204669,             /* x   F i */
+       0x72657769,             /* r e w i */
+       0x72650000,             /* r e     */
+};
+
+static const u32 model_textual_descriptor[] = {
+       /* model descriptor leaf () */
+       0x00030000,
+       0x00000000,
+       0x00000000,
+       0x4a756a75,             /* J u j u */
+};
+
+static struct fw_descriptor vendor_id_descriptor = {
+       .length = ARRAY_SIZE(vendor_textual_descriptor),
+       .immediate = 0x03d00d1e,
+       .key = 0x81000000,
+       .data = vendor_textual_descriptor,
+};
+
+static struct fw_descriptor model_id_descriptor = {
+       .length = ARRAY_SIZE(model_textual_descriptor),
+       .immediate = 0x17000001,
+       .key = 0x81000000,
+       .data = model_textual_descriptor,
+};
+
+static int __init fw_core_init(void)
+{
+       int retval;
+
+       retval = bus_register(&fw_bus_type);
+       if (retval < 0)
+               return retval;
+
+       fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
+       if (fw_cdev_major < 0) {
+               bus_unregister(&fw_bus_type);
+               return fw_cdev_major;
+       }
+
+       retval = fw_core_add_address_handler(&topology_map,
+                                            &topology_map_region);
+       BUG_ON(retval < 0);
+
+       retval = fw_core_add_address_handler(&registers,
+                                            &registers_region);
+       BUG_ON(retval < 0);
+
+       /* Add the vendor textual descriptor. */
+       retval = fw_core_add_descriptor(&vendor_id_descriptor);
+       BUG_ON(retval < 0);
+       retval = fw_core_add_descriptor(&model_id_descriptor);
+       BUG_ON(retval < 0);
+
+       return 0;
+}
+
+static void __exit fw_core_cleanup(void)
+{
+       unregister_chrdev(fw_cdev_major, "firewire");
+       bus_unregister(&fw_bus_type);
+}
+
+module_init(fw_core_init);
+module_exit(fw_core_cleanup);
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
new file mode 100644 (file)
index 0000000..acdc3be
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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.
+ */
+
+#ifndef __fw_transaction_h
+#define __fw_transaction_h
+
+#include <linux/device.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/firewire-constants.h>
+
+#define TCODE_IS_READ_REQUEST(tcode)   (((tcode) & ~1) == 4)
+#define TCODE_IS_BLOCK_PACKET(tcode)   (((tcode) &  1) != 0)
+#define TCODE_IS_REQUEST(tcode)                (((tcode) &  2) == 0)
+#define TCODE_IS_RESPONSE(tcode)       (((tcode) &  2) != 0)
+#define TCODE_HAS_REQUEST_DATA(tcode)  (((tcode) & 12) != 4)
+#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
+
+#define LOCAL_BUS 0xffc0
+
+#define SELFID_PORT_CHILD      0x3
+#define SELFID_PORT_PARENT     0x2
+#define SELFID_PORT_NCONN      0x1
+#define SELFID_PORT_NONE       0x0
+
+#define PHY_PACKET_CONFIG      0x0
+#define PHY_PACKET_LINK_ON     0x1
+#define PHY_PACKET_SELF_ID     0x2
+
+/* Bit fields _within_ the PHY registers. */
+#define PHY_LINK_ACTIVE                0x80
+#define PHY_CONTENDER          0x40
+#define PHY_BUS_RESET          0x40
+#define PHY_BUS_SHORT_RESET    0x40
+
+#define CSR_REGISTER_BASE              0xfffff0000000ULL
+
+/* register offsets relative to CSR_REGISTER_BASE */
+#define CSR_STATE_CLEAR                        0x0
+#define CSR_STATE_SET                  0x4
+#define CSR_NODE_IDS                   0x8
+#define CSR_RESET_START                        0xc
+#define CSR_SPLIT_TIMEOUT_HI           0x18
+#define CSR_SPLIT_TIMEOUT_LO           0x1c
+#define CSR_CYCLE_TIME                 0x200
+#define CSR_BUS_TIME                   0x204
+#define CSR_BUSY_TIMEOUT               0x210
+#define CSR_BUS_MANAGER_ID             0x21c
+#define CSR_BANDWIDTH_AVAILABLE                0x220
+#define CSR_CHANNELS_AVAILABLE         0x224
+#define CSR_CHANNELS_AVAILABLE_HI      0x224
+#define CSR_CHANNELS_AVAILABLE_LO      0x228
+#define CSR_BROADCAST_CHANNEL          0x234
+#define CSR_CONFIG_ROM                 0x400
+#define CSR_CONFIG_ROM_END             0x800
+#define CSR_FCP_COMMAND                        0xB00
+#define CSR_FCP_RESPONSE               0xD00
+#define CSR_FCP_END                    0xF00
+#define CSR_TOPOLOGY_MAP               0x1000
+#define CSR_TOPOLOGY_MAP_END           0x1400
+#define CSR_SPEED_MAP                  0x2000
+#define CSR_SPEED_MAP_END              0x3000
+
+#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
+#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+#define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args)
+
+static inline void
+fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
+{
+       u32 *dst = _dst;
+       u32 *src = _src;
+       int i;
+
+       for (i = 0; i < size / 4; i++)
+               dst[i] = cpu_to_be32(src[i]);
+}
+
+static inline void
+fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
+{
+       fw_memcpy_from_be32(_dst, _src, size);
+}
+
+struct fw_card;
+struct fw_packet;
+struct fw_node;
+struct fw_request;
+
+struct fw_descriptor {
+       struct list_head link;
+       size_t length;
+       u32 immediate;
+       u32 key;
+       const u32 *data;
+};
+
+int fw_core_add_descriptor(struct fw_descriptor *desc);
+void fw_core_remove_descriptor(struct fw_descriptor *desc);
+
+typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
+                                    struct fw_card *card, int status);
+
+typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
+                                         void *data,
+                                         size_t length,
+                                         void *callback_data);
+
+typedef void (*fw_address_callback_t)(struct fw_card *card,
+                                     struct fw_request *request,
+                                     int tcode, int destination, int source,
+                                     int generation, int speed,
+                                     unsigned long long offset,
+                                     void *data, size_t length,
+                                     void *callback_data);
+
+typedef void (*fw_bus_reset_callback_t)(struct fw_card *handle,
+                                       int node_id, int generation,
+                                       u32 *self_ids,
+                                       int self_id_count,
+                                       void *callback_data);
+
+struct fw_packet {
+       int speed;
+       int generation;
+       u32 header[4];
+       size_t header_length;
+       void *payload;
+       size_t payload_length;
+       u32 timestamp;
+
+       /*
+        * This callback is called when the packet transmission has
+        * completed; for successful transmission, the status code is
+        * the ack received from the destination, otherwise it's a
+        * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
+        * The callback can be called from tasklet context and thus
+        * must never block.
+        */
+       fw_packet_callback_t callback;
+       int ack;
+       struct list_head link;
+       void *driver_data;
+};
+
+struct fw_transaction {
+       int node_id; /* The generation is implied; it is always the current. */
+       int tlabel;
+       int timestamp;
+       struct list_head link;
+
+       struct fw_packet packet;
+
+       /*
+        * The data passed to the callback is valid only during the
+        * callback.
+        */
+       fw_transaction_callback_t callback;
+       void *callback_data;
+};
+
+static inline struct fw_packet *
+fw_packet(struct list_head *l)
+{
+       return list_entry(l, struct fw_packet, link);
+}
+
+struct fw_address_handler {
+       u64 offset;
+       size_t length;
+       fw_address_callback_t address_callback;
+       void *callback_data;
+       struct list_head link;
+};
+
+
+struct fw_address_region {
+       u64 start;
+       u64 end;
+};
+
+extern const struct fw_address_region fw_low_memory_region;
+extern const struct fw_address_region fw_high_memory_region;
+extern const struct fw_address_region fw_private_region;
+extern const struct fw_address_region fw_csr_region;
+extern const struct fw_address_region fw_unit_space_region;
+
+int fw_core_add_address_handler(struct fw_address_handler *handler,
+                               const struct fw_address_region *region);
+void fw_core_remove_address_handler(struct fw_address_handler *handler);
+void fw_fill_response(struct fw_packet *response, u32 *request_header,
+                     int rcode, void *payload, size_t length);
+void fw_send_response(struct fw_card *card,
+                     struct fw_request *request, int rcode);
+
+extern struct bus_type fw_bus_type;
+
+struct fw_card {
+       const struct fw_card_driver *driver;
+       struct device *device;
+       struct kref kref;
+
+       int node_id;
+       int generation;
+       /* This is the generation used for timestamping incoming requests. */
+       int request_generation;
+       int current_tlabel, tlabel_mask;
+       struct list_head transaction_list;
+       struct timer_list flush_timer;
+       unsigned long reset_jiffies;
+
+       unsigned long long guid;
+       int max_receive;
+       int link_speed;
+       int config_rom_generation;
+
+       /*
+        * We need to store up to 4 self ID for a maximum of 63
+        * devices plus 3 words for the topology map header.
+        */
+       int self_id_count;
+       u32 topology_map[252 + 3];
+
+       spinlock_t lock; /* Take this lock when handling the lists in
+                         * this struct. */
+       struct fw_node *local_node;
+       struct fw_node *root_node;
+       struct fw_node *irm_node;
+       int color;
+       int gap_count;
+       int topology_type;
+
+       int index;
+
+       struct list_head link;
+
+       /* Work struct for BM duties. */
+       struct delayed_work work;
+       int bm_retries;
+       int bm_generation;
+};
+
+struct fw_card *fw_card_get(struct fw_card *card);
+void fw_card_put(struct fw_card *card);
+
+/*
+ * The iso packet format allows for an immediate header/payload part
+ * stored in 'header' immediately after the packet info plus an
+ * indirect payload part that is pointer to by the 'payload' field.
+ * Applications can use one or the other or both to implement simple
+ * low-bandwidth streaming (e.g. audio) or more advanced
+ * scatter-gather streaming (e.g. assembling video frame automatically).
+ */
+
+struct fw_iso_packet {
+       u16 payload_length;     /* Length of indirect payload. */
+       u32 interrupt : 1;      /* Generate interrupt on this packet */
+       u32 skip : 1;           /* Set to not send packet at all. */
+       u32 tag : 2;
+       u32 sy : 4;
+       u32 header_length : 8;  /* Length of immediate header. */
+       u32 header[0];
+};
+
+#define FW_ISO_CONTEXT_TRANSMIT        0
+#define FW_ISO_CONTEXT_RECEIVE 1
+
+#define FW_ISO_CONTEXT_MATCH_TAG0       1
+#define FW_ISO_CONTEXT_MATCH_TAG1       2
+#define FW_ISO_CONTEXT_MATCH_TAG2       4
+#define FW_ISO_CONTEXT_MATCH_TAG3       8
+#define FW_ISO_CONTEXT_MATCH_ALL_TAGS  15
+
+struct fw_iso_context;
+
+typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
+                                 u32 cycle,
+                                 size_t header_length,
+                                 void *header,
+                                 void *data);
+
+/*
+ * An iso buffer is just a set of pages mapped for DMA in the
+ * specified direction.  Since the pages are to be used for DMA, they
+ * are not mapped into the kernel virtual address space.  We store the
+ * DMA address in the page private. The helper function
+ * fw_iso_buffer_map() will map the pages into a given vma.
+ */
+
+struct fw_iso_buffer {
+       enum dma_data_direction direction;
+       struct page **pages;
+       int page_count;
+};
+
+struct fw_iso_context {
+       struct fw_card *card;
+       int type;
+       int channel;
+       int speed;
+       size_t header_size;
+       fw_iso_callback_t callback;
+       void *callback_data;
+};
+
+int
+fw_iso_buffer_init(struct fw_iso_buffer *buffer,
+                  struct fw_card *card,
+                  int page_count,
+                  enum dma_data_direction direction);
+int
+fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
+void
+fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
+
+struct fw_iso_context *
+fw_iso_context_create(struct fw_card *card, int type,
+                     int channel, int speed, size_t header_size,
+                     fw_iso_callback_t callback, void *callback_data);
+
+void
+fw_iso_context_destroy(struct fw_iso_context *ctx);
+
+int
+fw_iso_context_queue(struct fw_iso_context *ctx,
+                    struct fw_iso_packet *packet,
+                    struct fw_iso_buffer *buffer,
+                    unsigned long payload);
+
+int
+fw_iso_context_start(struct fw_iso_context *ctx,
+                    int cycle, int sync, int tags);
+
+int
+fw_iso_context_stop(struct fw_iso_context *ctx);
+
+struct fw_card_driver {
+       const char *name;
+
+       /*
+        * Enable the given card with the given initial config rom.
+        * This function is expected to activate the card, and either
+        * enable the PHY or set the link_on bit and initiate a bus
+        * reset.
+        */
+       int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
+
+       int (*update_phy_reg)(struct fw_card *card, int address,
+                             int clear_bits, int set_bits);
+
+       /*
+        * Update the config rom for an enabled card.  This function
+        * should change the config rom that is presented on the bus
+        * an initiate a bus reset.
+        */
+       int (*set_config_rom)(struct fw_card *card,
+                             u32 *config_rom, size_t length);
+
+       void (*send_request)(struct fw_card *card, struct fw_packet *packet);
+       void (*send_response)(struct fw_card *card, struct fw_packet *packet);
+       /* Calling cancel is valid once a packet has been submitted. */
+       int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
+
+       /*
+        * Allow the specified node ID to do direct DMA out and in of
+        * host memory.  The card will disable this for all node when
+        * a bus reset happens, so driver need to reenable this after
+        * bus reset.  Returns 0 on success, -ENODEV if the card
+        * doesn't support this, -ESTALE if the generation doesn't
+        * match.
+        */
+       int (*enable_phys_dma)(struct fw_card *card,
+                              int node_id, int generation);
+
+       u64 (*get_bus_time)(struct fw_card *card);
+
+       struct fw_iso_context *
+       (*allocate_iso_context)(struct fw_card *card,
+                               int type, size_t header_size);
+       void (*free_iso_context)(struct fw_iso_context *ctx);
+
+       int (*start_iso)(struct fw_iso_context *ctx,
+                        s32 cycle, u32 sync, u32 tags);
+
+       int (*queue_iso)(struct fw_iso_context *ctx,
+                        struct fw_iso_packet *packet,
+                        struct fw_iso_buffer *buffer,
+                        unsigned long payload);
+
+       int (*stop_iso)(struct fw_iso_context *ctx);
+};
+
+int
+fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
+
+void
+fw_send_request(struct fw_card *card, struct fw_transaction *t,
+               int tcode, int node_id, int generation, int speed,
+               unsigned long long offset,
+               void *data, size_t length,
+               fw_transaction_callback_t callback, void *callback_data);
+
+int fw_cancel_transaction(struct fw_card *card,
+                         struct fw_transaction *transaction);
+
+void fw_flush_transactions(struct fw_card *card);
+
+void fw_send_phy_config(struct fw_card *card,
+                       int node_id, int generation, int gap_count);
+
+/*
+ * Called by the topology code to inform the device code of node
+ * activity; found, lost, or updated nodes.
+ */
+void
+fw_node_event(struct fw_card *card, struct fw_node *node, int event);
+
+/* API used by card level drivers */
+
+void
+fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
+                  struct device *device);
+int
+fw_card_add(struct fw_card *card,
+           u32 max_receive, u32 link_speed, u64 guid);
+
+void
+fw_core_remove_card(struct fw_card *card);
+
+void
+fw_core_handle_bus_reset(struct fw_card *card,
+                        int node_id, int generation,
+                        int self_id_count, u32 *self_ids);
+void
+fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
+
+void
+fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
+
+#endif /* __fw_transaction_h */
index 3ba3a5221c41776f75f07706a4d20effbca452c4..4d1cb5b855d17e86285b7f3aeca698e80775fa57 100644 (file)
@@ -4,6 +4,7 @@
 
 menuconfig HWMON
        tristate "Hardware Monitoring support"
+       depends on HAS_IOMEM
        default y
        help
          Hardware monitoring devices let you monitor the hardware health
index 18210164e307621c7edf41b3f51d221988b0899d..ca7095d96ad0f0f1a786b095f414bb27138c8a00 100644 (file)
@@ -87,7 +87,7 @@ static void ams_input_enable(void)
        ams_info.idev->id.vendor = 0;
        ams_info.idev->open = ams_input_open;
        ams_info.idev->close = ams_input_close;
-       ams_info.idev->cdev.dev = &ams_info.of_dev->dev;
+       ams_info.idev->dev.parent = &ams_info.of_dev->dev;
 
        input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
        input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
index 3215f9c87f329dcbcf1a79469eff01551ede9019..0c160675b3acc54d70b2580dfbf507edff00a85d 100644 (file)
@@ -981,7 +981,7 @@ static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
 static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
        applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
 \
-static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \
+static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
        applesmc_show_fan_position, NULL, offset-1); \
 \
 static struct attribute *fan##offset##_attributes[] = { \
@@ -991,7 +991,7 @@ static struct attribute *fan##offset##_attributes[] = { \
        &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
        &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
        &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
-       &sensor_dev_attr_fan##offset##_position.dev_attr.attr, \
+       &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
        NULL \
 };
 
@@ -1100,7 +1100,7 @@ static int applesmc_create_accelerometer(void)
        /* initialize the input class */
        applesmc_idev->name = "applesmc";
        applesmc_idev->id.bustype = BUS_HOST;
-       applesmc_idev->cdev.dev = &pdev->dev;
+       applesmc_idev->dev.parent = &pdev->dev;
        applesmc_idev->evbit[0] = BIT(EV_ABS);
        applesmc_idev->open = applesmc_idev_open;
        applesmc_idev->close = applesmc_idev_close;
@@ -1190,7 +1190,8 @@ static int __init applesmc_init(void)
        if (ret)
                goto out_region;
 
-       pdev = platform_device_register_simple("applesmc", -1, NULL, 0);
+       pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
+                                              NULL, 0);
        if (IS_ERR(pdev)) {
                ret = PTR_ERR(pdev);
                goto out_driver;
index 03b1f650d1c47d04d7cb2b9b3ca140f50f25b30d..75e3911810a38af22deafc4f68cf1a4205ef5942 100644 (file)
@@ -309,9 +309,11 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                coretemp_device_add(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                coretemp_device_remove(cpu);
                break;
        }
index f82fa2d23f9529febecc64209a129e60b1d9c269..e0cf5e6fe5bc4498f61df424a7cfd06fcd0c1f6d 100644 (file)
@@ -574,7 +574,7 @@ static int __init hdaps_init(void)
 
        /* initialize the input class */
        hdaps_idev->name = "hdaps";
-       hdaps_idev->cdev.dev = &pdev->dev;
+       hdaps_idev->dev.parent = &pdev->dev;
        hdaps_idev->evbit[0] = BIT(EV_ABS);
        input_set_abs_params(hdaps_idev, ABS_X,
                        -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
index 434a61b415a347ba529241ac439bbe3e36d69bbe..96867347bcbfffa0639d0df93b08cbbb86c23b68 100644 (file)
@@ -4,6 +4,7 @@
 
 menuconfig I2C
        tristate "I2C support"
+       depends on HAS_IOMEM
        ---help---
          I2C (pronounce: I-square-C) is a slow serial bus protocol used in
          many micro controller applications and developed by Philips.  SMBus,
index f35156c5892221bdb05d3280276fbc6cd06b6532..9c8b6d5eaec9ef301fe1491d6bf8ce714bfc3c8c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/delay.h>
@@ -226,13 +227,14 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev)
        adapter->algo = &at91_algorithm;
        adapter->class = I2C_CLASS_HWMON;
        adapter->dev.parent = &pdev->dev;
+       /* adapter->id == 0 ... only one TWI controller for now */
 
        platform_set_drvdata(pdev, adapter);
 
        clk_enable(twi_clk);            /* enable peripheral clock */
        at91_twi_hwinit();              /* initialize TWI controller */
 
-       rc = i2c_add_adapter(adapter);
+       rc = i2c_add_numbered_adapter(adapter);
        if (rc) {
                dev_err(&pdev->dev, "Adapter %s registration failed\n",
                                adapter->name);
@@ -295,6 +297,9 @@ static int at91_i2c_resume(struct platform_device *pdev)
 #define at91_i2c_resume                NULL
 #endif
 
+/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
+MODULE_ALIAS("at91_i2c");
+
 static struct platform_driver at91_i2c_driver = {
        .probe          = at91_i2c_probe,
        .remove         = __devexit_p(at91_i2c_remove),
index 873544ab598e9b92695d9c9e6aa3ed0f09a6161b..8a0a99b93641d46b10efd56b09341e619cb15615 100644 (file)
@@ -548,7 +548,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
         */
        icr = readl(_ICR(i2c));
        icr &= ~(ICR_STOP | ICR_ACKNAK);
-       writel(icr, _IRC(i2c));
+       writel(icr, _ICR(i2c));
 }
 
 /*
index 7ed92dc3d833304da757d7e99aed88023df232fc..3c3f2ebf3fc9786eecf042ed4aa1d1ae9a56c9c3 100644 (file)
@@ -354,7 +354,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
                         * also needs to get error handling and probably
                         * an #ifdef CONFIG_SOFTWARE_SUSPEND
                         */
-                       pm_suspend(PM_SUSPEND_DISK);
+                       hibernate();
 #endif
                        poll = 1;
                }
index 5bdf64b779134d555508891dbe49e7a55651f904..9040809d2c254f2df0a43a9c216f5fa08bbefd86 100644 (file)
@@ -7,6 +7,7 @@
 if BLOCK
 
 menu "ATA/ATAPI/MFM/RLL support"
+       depends on HAS_IOMEM
 
 config IDE
        tristate "ATA/ATAPI/MFM/RLL support"
@@ -291,6 +292,17 @@ config IDE_TASK_IOCTL
 
          If you are unsure, say N here.
 
+config IDE_PROC_FS
+       bool "legacy /proc/ide/ support"
+       depends on IDE && PROC_FS
+       default y
+       help
+         This option enables support for the various files in
+         /proc/ide.  In Linux 2.6 this has been superseded by
+         files in sysfs but many legacy applications rely on this.
+
+         If unsure say Y.
+
 comment "IDE chipset support/bugfixes"
 
 config IDE_GENERIC
@@ -360,6 +372,9 @@ config IDEPCI_SHARE_IRQ
          It is safe to say Y to this question, in most cases.
          If unsure, say N.
 
+config IDEPCI_PCIBUS_ORDER
+       def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+
 config BLK_DEV_OFFBOARD
        bool "Boot off-board chipsets first support"
        depends on PCI && BLK_DEV_IDEPCI
index d9f029e8ff7411cdb5827d5ed889bcbd5847402d..75dc6969e0a7dfc4e6ed01015c96c21b98387b3c 100644 (file)
@@ -20,7 +20,7 @@ ide-core-$(CONFIG_BLK_DEV_CMD640)     += pci/cmd640.o
 # Core IDE code - must come before legacy
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)      += setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)      += ide-dma.o
-ide-core-$(CONFIG_PROC_FS)             += ide-proc.o
+ide-core-$(CONFIG_IDE_PROC_FS)         += ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEPNP)      += ide-pnp.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
 
index 9d474e5fd8dc49484b555651c925fe22561147a5..f7449d04114a1b1e984917e35fb23755424abaf3 100644 (file)
@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
        hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
        hw.irq = irq;
 
-       ide_register_hw(&hw, hwif);
+       ide_register_hw(&hw, 0, hwif);
 
        return 0;
 }
index e2953fc1fafbc175bb87bac04e9acf94a28944e2..1fe0457243dbbcf824d8ef1f468a5ca9fe275b24 100644 (file)
@@ -342,7 +342,7 @@ static int icside_dma_check(ide_drive_t *drive)
         * Enable DMA on any drive that has multiword DMA
         */
        if (id->field_valid & 2) {
-               xfer_mode = ide_dma_speed(drive, 0);
+               xfer_mode = ide_max_dma_mode(drive);
                goto out;
        }
 
@@ -591,7 +591,8 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
        state->hwif[0] = hwif;
 
        probe_hwif_init(hwif);
-       create_proc_ide_interfaces();
+
+       ide_proc_register_port(hwif);
 
        return 0;
 }
@@ -679,7 +680,9 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
-       create_proc_ide_interfaces();
+
+       ide_proc_register_port(hwif);
+       ide_proc_register_port(mate);
 
        return 0;
 
index 23488c4d1fcdca96c987fd2838dd3961a88104aa..a3d6744e870a18870e7b98a23129e76b78cce34c 100644 (file)
@@ -38,6 +38,6 @@ void __init ide_arm_init(void)
                memset(&hw, 0, sizeof(hw));
                ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
                hw.irq = IDE_ARM_IRQ;
-               ide_register_hw(&hw, NULL);
+               ide_register_hw(&hw, 1, NULL);
        }
 }
index 9c6c49fdd2b14997d51d441b3ca9399cfd1d1f08..890ea3fac3c6feb80bb50f8ced8a392fe9369aed 100644 (file)
@@ -76,7 +76,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
                hwif->gendev.parent = &ec->dev;
                hwif->noprobe = 0;
                probe_hwif_init(hwif);
-               create_proc_ide_interfaces();
+               ide_proc_register_port(hwif);
                ecard_set_drvdata(ec, hwif);
                goto out;
        }
index 5e8efc89255a79fdf8dd1399325e37dcb7eb5efe..c04cb25a01ff4ee2c8a9e0e2f60599bd11fc3d66 100644 (file)
@@ -796,7 +796,7 @@ init_e100_ide (void)
                                ide_offsets,
                                0, 0, cris_ide_ack_intr,
                                ide_default_irq(0));
-               ide_register_hw(&hw, &hwif);
+               ide_register_hw(&hw, 1, &hwif);
                hwif->mmio = 1;
                hwif->chipset = ide_etrax100;
                hwif->tuneproc = &tune_cris_ide;
@@ -1004,7 +1004,7 @@ static int cris_ide_build_dmatable (ide_drive_t *drive)
 
 static int cris_config_drive_for_dma (ide_drive_t *drive)
 {
-       u8 speed = ide_dma_speed(drive, 1);
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!speed)
                return 0;
index 88750a300337dfd122509564363fcf14335f3d31..6d26ad7360d52c35dd01ab897dafe24b8fd2dacd 100644 (file)
@@ -101,7 +101,7 @@ void __init h8300_ide_init(void)
        hw_setup(&hw);
 
        /* register if */
-       idx = ide_register_hw(&hw, &hwif);
+       idx = ide_register_hw(&hw, 1, &hwif);
        if (idx == -1) {
                printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
                return;
index 638becda81c6206fa1413bac1003842e6d8664eb..252ab8295edfd9fef5fc0fb029e0ed33c898e9f0 100644 (file)
@@ -3059,10 +3059,14 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
        return nslots;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void ide_cdrom_add_settings(ide_drive_t *drive)
 {
-       ide_add_setting(drive,  "dsc_overlap",          SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
+       ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
 }
+#else
+static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  * standard prep_rq_fn that builds 10 byte cmds
@@ -3274,7 +3278,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
        return 0;
 }
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static
 sector_t ide_cdrom_capacity (ide_drive_t *drive)
 {
@@ -3291,7 +3295,7 @@ static void ide_cd_remove(ide_drive_t *drive)
 {
        struct cdrom_info *info = drive->driver_data;
 
-       ide_unregister_subdriver(drive, info->driver);
+       ide_proc_unregister_driver(drive, info->driver);
 
        del_gendisk(info->disk);
 
@@ -3321,7 +3325,7 @@ static void ide_cd_release(struct kref *kref)
 
 static int ide_cd_probe(ide_drive_t *);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idecd_read_capacity
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -3336,8 +3340,6 @@ static ide_proc_entry_t idecd_proc[] = {
        { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
        { NULL, 0, NULL, NULL }
 };
-#else
-# define idecd_proc    NULL
 #endif
 
 static ide_driver_t ide_cdrom_driver = {
@@ -3355,7 +3357,9 @@ static ide_driver_t ide_cdrom_driver = {
        .end_request            = ide_end_request,
        .error                  = __ide_error,
        .abort                  = __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
        .proc                   = idecd_proc,
+#endif
 };
 
 static int idecd_open(struct inode * inode, struct file * file)
@@ -3517,7 +3521,7 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_register_subdriver(drive, &ide_cdrom_driver);
+       ide_proc_register_driver(drive, &ide_cdrom_driver);
 
        kref_init(&info->kref);
 
@@ -3534,7 +3538,7 @@ static int ide_cd_probe(ide_drive_t *drive)
        g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
        if (ide_cdrom_setup(drive)) {
                struct cdrom_device_info *devinfo = &info->devinfo;
-               ide_unregister_subdriver(drive, &ide_cdrom_driver);
+               ide_proc_unregister_driver(drive, &ide_cdrom_driver);
                kfree(info->buffer);
                kfree(info->toc);
                kfree(info->changer_info);
index 37aa6ddd97020f91bbf067a97fa0e168fe1e7083..7fff773f2df77ece16e19644346c771b6864516b 100644 (file)
@@ -559,8 +559,7 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
        return drive->capacity64 - drive->sect0;
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int smart_enable(ide_drive_t *drive)
 {
        ide_task_t args;
@@ -678,12 +677,7 @@ static ide_proc_entry_t idedisk_proc[] = {
        { "smart_thresholds",   S_IFREG|S_IRUSR,        proc_idedisk_read_smart_thresholds,     NULL },
        { NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define        idedisk_proc    NULL
-
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_IDE_PROC_FS */
 
 static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
 {
@@ -737,6 +731,9 @@ static int set_multcount(ide_drive_t *drive, int arg)
 {
        struct request rq;
 
+       if (arg < 0 || arg > drive->id->max_multsect)
+               return -EINVAL;
+
        if (drive->special.b.set_multmode)
                return -EBUSY;
        ide_init_drive_cmd (&rq);
@@ -749,6 +746,9 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 static int set_nowerr(ide_drive_t *drive, int arg)
 {
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        if (ide_spin_wait_hwgroup(drive))
                return -EBUSY;
        drive->nowerr = arg;
@@ -800,6 +800,9 @@ static int write_cache(ide_drive_t *drive, int arg)
        ide_task_t args;
        int err = 1;
 
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        if (ide_id_has_flush_cache(drive->id)) {
                memset(&args, 0, sizeof(ide_task_t));
                args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ?
@@ -835,6 +838,9 @@ static int set_acoustic (ide_drive_t *drive, int arg)
 {
        ide_task_t args;
 
+       if (arg < 0 || arg > 254)
+               return -EINVAL;
+
        memset(&args, 0, sizeof(ide_task_t));
        args.tfRegister[IDE_FEATURE_OFFSET]     = (arg) ? SETFEATURES_EN_AAM :
                                                          SETFEATURES_DIS_AAM;
@@ -855,6 +861,9 @@ static int set_acoustic (ide_drive_t *drive, int arg)
  */
 static int set_lba_addressing(ide_drive_t *drive, int arg)
 {
+       if (arg < 0 || arg > 2)
+               return -EINVAL;
+
        drive->addressing =  0;
 
        if (HWIF(drive)->no_lba48)
@@ -866,23 +875,27 @@ static int set_lba_addressing(ide_drive_t *drive, int arg)
        return 0;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idedisk_add_settings(ide_drive_t *drive)
 {
        struct hd_driveid *id = drive->id;
 
-       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->bios_cyl,               NULL);
-       ide_add_setting(drive,  "bios_head",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &drive->bios_head,              NULL);
-       ide_add_setting(drive,  "bios_sect",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      63,                             1,      1,      &drive->bios_sect,              NULL);
-       ide_add_setting(drive,  "address",              SETTING_RW,                                     HDIO_GET_ADDRESS,       HDIO_SET_ADDRESS,       TYPE_INTA,      0,      2,                              1,      1,      &drive->addressing,     set_lba_addressing);
-       ide_add_setting(drive,  "bswap",                SETTING_READ,                                   -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,      1,      &drive->bswap,                  NULL);
-       ide_add_setting(drive,  "multcount",            id ? SETTING_RW : SETTING_READ,                 HDIO_GET_MULTCOUNT,     HDIO_SET_MULTCOUNT,     TYPE_BYTE,      0,      id ? id->max_multsect : 0,      1,      1,      &drive->mult_count,             set_multcount);
-       ide_add_setting(drive,  "nowerr",               SETTING_RW,                                     HDIO_GET_NOWERR,        HDIO_SET_NOWERR,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->nowerr,                 set_nowerr);
-       ide_add_setting(drive,  "lun",                  SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      7,                              1,      1,      &drive->lun,                    NULL);
-       ide_add_setting(drive,  "wcache",               SETTING_RW,                                     HDIO_GET_WCACHE,        HDIO_SET_WCACHE,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->wcache,                 write_cache);
-       ide_add_setting(drive,  "acoustic",             SETTING_RW,                                     HDIO_GET_ACOUSTIC,      HDIO_SET_ACOUSTIC,      TYPE_BYTE,      0,      254,                            1,      1,      &drive->acoustic,               set_acoustic);
-       ide_add_setting(drive,  "failures",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->failures,               NULL);
-       ide_add_setting(drive,  "max_failures",         SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->max_failures,           NULL);
+       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     TYPE_INT,       0,      65535,                  1,      1,      &drive->bios_cyl,       NULL);
+       ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,                    1,      1,      &drive->bios_head,      NULL);
+       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,                     1,      1,      &drive->bios_sect,      NULL);
+       ide_add_setting(drive,  "address",      SETTING_RW,     TYPE_BYTE,      0,      2,                      1,      1,      &drive->addressing,     set_lba_addressing);
+       ide_add_setting(drive,  "bswap",        SETTING_READ,   TYPE_BYTE,      0,      1,                      1,      1,      &drive->bswap,          NULL);
+       ide_add_setting(drive,  "multcount",    SETTING_RW,     TYPE_BYTE,      0,      id->max_multsect,       1,      1,      &drive->mult_count,     set_multcount);
+       ide_add_setting(drive,  "nowerr",       SETTING_RW,     TYPE_BYTE,      0,      1,                      1,      1,      &drive->nowerr,         set_nowerr);
+       ide_add_setting(drive,  "lun",          SETTING_RW,     TYPE_INT,       0,      7,                      1,      1,      &drive->lun,            NULL);
+       ide_add_setting(drive,  "wcache",       SETTING_RW,     TYPE_BYTE,      0,      1,                      1,      1,      &drive->wcache,         write_cache);
+       ide_add_setting(drive,  "acoustic",     SETTING_RW,     TYPE_BYTE,      0,      254,                    1,      1,      &drive->acoustic,       set_acoustic);
+       ide_add_setting(drive,  "failures",     SETTING_RW,     TYPE_INT,       0,      65535,                  1,      1,      &drive->failures,       NULL);
+       ide_add_setting(drive,  "max_failures", SETTING_RW,     TYPE_INT,       0,      65535,                  1,      1,      &drive->max_failures,   NULL);
 }
+#else
+static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 static void idedisk_setup (ide_drive_t *drive)
 {
@@ -1001,7 +1014,7 @@ static void ide_disk_remove(ide_drive_t *drive)
        struct ide_disk_obj *idkp = drive->driver_data;
        struct gendisk *g = idkp->disk;
 
-       ide_unregister_subdriver(drive, idkp->driver);
+       ide_proc_unregister_driver(drive, idkp->driver);
 
        del_gendisk(g);
 
@@ -1066,7 +1079,9 @@ static ide_driver_t idedisk_driver = {
        .end_request            = ide_end_request,
        .error                  = __ide_error,
        .abort                  = __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
        .proc                   = idedisk_proc,
+#endif
 };
 
 static int idedisk_open(struct inode *inode, struct file *filp)
@@ -1140,9 +1155,49 @@ static int idedisk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 static int idedisk_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
+       unsigned long flags;
        struct block_device *bdev = inode->i_bdev;
        struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
-       return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg);
+       ide_drive_t *drive = idkp->drive;
+       int err, (*setfunc)(ide_drive_t *, int);
+       u8 *val;
+
+       switch (cmd) {
+       case HDIO_GET_ADDRESS:   val = &drive->addressing;      goto read_val;
+       case HDIO_GET_MULTCOUNT: val = &drive->mult_count;      goto read_val;
+       case HDIO_GET_NOWERR:    val = &drive->nowerr;          goto read_val;
+       case HDIO_GET_WCACHE:    val = &drive->wcache;          goto read_val;
+       case HDIO_GET_ACOUSTIC:  val = &drive->acoustic;        goto read_val;
+       case HDIO_SET_ADDRESS:   setfunc = set_lba_addressing;  goto set_val;
+       case HDIO_SET_MULTCOUNT: setfunc = set_multcount;       goto set_val;
+       case HDIO_SET_NOWERR:    setfunc = set_nowerr;          goto set_val;
+       case HDIO_SET_WCACHE:    setfunc = write_cache;         goto set_val;
+       case HDIO_SET_ACOUSTIC:  setfunc = set_acoustic;        goto set_val;
+       }
+
+       return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+read_val:
+       down(&ide_setting_sem);
+       spin_lock_irqsave(&ide_lock, flags);
+       err = *val;
+       spin_unlock_irqrestore(&ide_lock, flags);
+       up(&ide_setting_sem);
+       return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+       if (bdev != bdev->bd_contains)
+               err = -EINVAL;
+       else {
+               if (!capable(CAP_SYS_ADMIN))
+                       err = -EACCES;
+               else {
+                       down(&ide_setting_sem);
+                       err = setfunc(drive, arg);
+                       up(&ide_setting_sem);
+               }
+       }
+       return err;
 }
 
 static int idedisk_media_changed(struct gendisk *disk)
@@ -1202,7 +1257,7 @@ static int ide_disk_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_register_subdriver(drive, &idedisk_driver);
+       ide_proc_register_driver(drive, &idedisk_driver);
 
        kref_init(&idkp->kref);
 
index fd213088b06b4a467afc8222a87fd634f100cfe3..5fe85191d49c1f05cffc34aeb429dbbb54971f80 100644 (file)
@@ -705,6 +705,100 @@ int ide_use_dma(ide_drive_t *drive)
 
 EXPORT_SYMBOL_GPL(ide_use_dma);
 
+static const u8 xfer_mode_bases[] = {
+       XFER_UDMA_0,
+       XFER_MW_DMA_0,
+       XFER_SW_DMA_0,
+};
+
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
+{
+       struct hd_driveid *id = drive->id;
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int mask = 0;
+
+       switch(base) {
+       case XFER_UDMA_0:
+               if ((id->field_valid & 4) == 0)
+                       break;
+
+               mask = id->dma_ultra & hwif->ultra_mask;
+
+               if (hwif->udma_filter)
+                       mask &= hwif->udma_filter(drive);
+
+               if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+                       mask &= 0x07;
+               break;
+       case XFER_MW_DMA_0:
+               mask = id->dma_mword & hwif->mwdma_mask;
+               break;
+       case XFER_SW_DMA_0:
+               mask = id->dma_1word & hwif->swdma_mask;
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       return mask;
+}
+
+/**
+ *     ide_max_dma_mode        -       compute DMA speed
+ *     @drive: IDE device
+ *
+ *     Checks the drive capabilities and returns the speed to use
+ *     for the DMA transfer.  Returns 0 if the drive is incapable
+ *     of DMA transfers.
+ */
+
+u8 ide_max_dma_mode(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int mask;
+       int x, i;
+       u8 mode = 0;
+
+       if (drive->media != ide_disk && hwif->atapi_dma == 0)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
+               mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
+               x = fls(mask) - 1;
+               if (x >= 0) {
+                       mode = xfer_mode_bases[i] + x;
+                       break;
+               }
+       }
+
+       printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
+
+       return mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_max_dma_mode);
+
+int ide_tune_dma(ide_drive_t *drive)
+{
+       u8 speed;
+
+       /* TODO: use only ide_max_dma_mode() */
+       if (!ide_use_dma(drive))
+               return 0;
+
+       speed = ide_max_dma_mode(drive);
+
+       if (!speed)
+               return 0;
+
+       drive->hwif->speedproc(drive, speed);
+
+       return ide_dma_enable(drive);
+}
+
+EXPORT_SYMBOL_GPL(ide_tune_dma);
+
 void ide_dma_verbose(ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
index 57cd21c5b2c1f0c0fdc7a79985f226f736a0da00..f429be88c4f9d568846baeb765181ccefc479ddd 100644 (file)
@@ -1811,18 +1811,22 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
        return 0;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idefloppy_add_settings(ide_drive_t *drive)
 {
        idefloppy_floppy_t *floppy = drive->driver_data;
 
 /*
- *                     drive   setting name    read/write      ioctl   ioctl           data type       min     max     mul_factor      div_factor      data pointer            set function
+ *                     drive   setting name    read/write      data type       min     max     mul_factor      div_factor      data pointer            set function
  */
-       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      1023,                           1,      1,      &drive->bios_cyl,               NULL);
-       ide_add_setting(drive,  "bios_head",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &drive->bios_head,              NULL);
-       ide_add_setting(drive,  "bios_sect",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      63,                             1,      1,      &drive->bios_sect,              NULL);
-       ide_add_setting(drive,  "ticks",                SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &floppy->ticks,         NULL);
+       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     TYPE_INT,       0,      1023,           1,              1,      &drive->bios_cyl,       NULL);
+       ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,            1,              1,      &drive->bios_head,      NULL);
+       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,             1,              1,      &drive->bios_sect,      NULL);
+       ide_add_setting(drive,  "ticks",        SETTING_RW,     TYPE_BYTE,      0,      255,            1,              1,      &floppy->ticks,         NULL);
 }
+#else
+static inline void idefloppy_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *     Driver initialization.
@@ -1873,7 +1877,7 @@ static void ide_floppy_remove(ide_drive_t *drive)
        idefloppy_floppy_t *floppy = drive->driver_data;
        struct gendisk *g = floppy->disk;
 
-       ide_unregister_subdriver(drive, floppy->driver);
+       ide_proc_unregister_driver(drive, floppy->driver);
 
        del_gendisk(g);
 
@@ -1892,8 +1896,7 @@ static void ide_floppy_release(struct kref *kref)
        kfree(floppy);
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idefloppy_read_capacity
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -1909,12 +1912,7 @@ static ide_proc_entry_t idefloppy_proc[] = {
        { "geometry",   S_IFREG|S_IRUGO,        proc_ide_read_geometry, NULL },
        { NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define        idefloppy_proc  NULL
-
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_IDE_PROC_FS */
 
 static int ide_floppy_probe(ide_drive_t *);
 
@@ -1933,7 +1931,9 @@ static ide_driver_t idefloppy_driver = {
        .end_request            = idefloppy_do_end_request,
        .error                  = __ide_error,
        .abort                  = __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
        .proc                   = idefloppy_proc,
+#endif
 };
 
 static int idefloppy_open(struct inode *inode, struct file *filp)
@@ -2159,7 +2159,7 @@ static int ide_floppy_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_register_subdriver(drive, &idefloppy_driver);
+       ide_proc_register_driver(drive, &idefloppy_driver);
 
        kref_init(&floppy->kref);
 
index 99fd56151131cb4fc92b9f2e9da5091811a37483..0f72b98d727f43ba72f4d68b2a53871ec9806bcd 100644 (file)
@@ -22,8 +22,6 @@ static int __init ide_generic_init(void)
        if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
                ide_release_lock();     /* for atari only */
 
-       create_proc_ide_interfaces();
-
        return 0;
 }
 
index 8670112f1d3947a579fef59d59ec431485c9d288..8e568143d90d73e74da45f99878bceb4ea5a62b6 100644 (file)
@@ -172,15 +172,6 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
 
        memset(args, 0, sizeof(*args));
 
-       if (drive->media != ide_disk) {
-               /*
-                * skip idedisk_pm_restore_pio and idedisk_pm_idle for ATAPI
-                * devices
-                */
-               if (pm->pm_step == idedisk_pm_restore_pio)
-                       pm->pm_step = ide_pm_restore_dma;
-       }
-
        switch (pm->pm_step) {
        case ide_pm_flush_cache:        /* Suspend step 1 (flush cache) */
                if (drive->media != ide_disk)
@@ -207,7 +198,13 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
        case idedisk_pm_restore_pio:    /* Resume step 1 (restore PIO) */
                if (drive->hwif->tuneproc != NULL)
                        drive->hwif->tuneproc(drive, 255);
-               ide_complete_power_step(drive, rq, 0, 0);
+               /*
+                * skip idedisk_pm_idle for ATAPI devices
+                */
+               if (drive->media != ide_disk)
+                       pm->pm_step = ide_pm_restore_dma;
+               else
+                       ide_complete_power_step(drive, rq, 0, 0);
                return ide_stopped;
 
        case idedisk_pm_idle:           /* Resume step 2 (idle) */
index 3caa176b31553bd4b2b79cee575aa9b4c8a43595..f0be5f665a0e0ae21af516609c0a82c556b4e0cd 100644 (file)
@@ -571,51 +571,54 @@ EXPORT_SYMBOL(ide_wait_stat);
  */
 u8 eighty_ninty_three (ide_drive_t *drive)
 {
-       if(HWIF(drive)->udma_four == 0)
-               return 0;
+       ide_hwif_t *hwif = drive->hwif;
+       struct hd_driveid *id = drive->id;
+
+       if (hwif->udma_four == 0)
+               goto no_80w;
 
        /* Check for SATA but only if we are ATA5 or higher */
-       if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0))
+       if (id->hw_config == 0 && (id->major_rev_num & 0x7FE0))
                return 1;
-       if (!(drive->id->hw_config & 0x6000))
-               return 0;
-#ifndef CONFIG_IDEDMA_IVB
-       if(!(drive->id->hw_config & 0x4000))
-               return 0;
-#endif /* CONFIG_IDEDMA_IVB */
+
        /*
         * FIXME:
         * - change master/slave IDENTIFY order
         * - force bit13 (80c cable present) check
         *   (unless the slave device is pre-ATA3)
         */
-       return 1;
-}
+#ifndef CONFIG_IDEDMA_IVB
+       if (id->hw_config & 0x4000)
+#else
+       if (id->hw_config & 0x6000)
+#endif
+               return 1;
+
+no_80w:
+       if (drive->udma33_warned == 1)
+               return 0;
 
-EXPORT_SYMBOL(eighty_ninty_three);
+       printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
+                           "limiting max speed to UDMA33\n",
+                           drive->name, hwif->udma_four ? "drive" : "host");
+
+       drive->udma33_warned = 1;
+
+       return 0;
+}
 
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
        if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
            (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
            (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-#ifndef CONFIG_IDEDMA_IVB
-               if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-               if (((drive->id->hw_config & 0x2000) == 0) ||
-                   ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-                       printk("%s: Speed warnings UDMA 3/4/5 is not "
-                               "functional.\n", drive->name);
-                       return 1;
-               }
-               if (!HWIF(drive)->udma_four) {
-                       printk("%s: Speed warnings UDMA 3/4/5 is not "
-                               "functional.\n",
-                               HWIF(drive)->name);
+               if (eighty_ninty_three(drive) == 0) {
+                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+                                           "be set\n", drive->name);
                        return 1;
                }
        }
+
        return 0;
 }
 
index 68719314df3f099f0888e4de2fdf6b776173c577..3be3c69383f2e1ec256f0c19a77dfdcfe071e5b1 100644 (file)
@@ -69,123 +69,41 @@ char *ide_xfer_verbose (u8 xfer_rate)
 EXPORT_SYMBOL(ide_xfer_verbose);
 
 /**
- *     ide_dma_speed   -       compute DMA speed
- *     @drive: drive
- *     @mode:  modes available
- *
- *     Checks the drive capabilities and returns the speed to use
- *     for the DMA transfer.  Returns 0 if the drive is incapable
- *     of DMA transfers.
- */
-u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
-{
-       struct hd_driveid *id   = drive->id;
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 ultra_mask, mwdma_mask, swdma_mask;
-       u8 speed = 0;
-
-       if (drive->media != ide_disk && hwif->atapi_dma == 0)
-               return 0;
-
-       /* Capable of UltraDMA modes? */
-       ultra_mask = id->dma_ultra & hwif->ultra_mask;
-
-       if (!(id->field_valid & 4))
-               mode = 0;       /* fallback to MW/SW DMA if no UltraDMA */
-
-       switch (mode) {
-       case 4:
-               if (ultra_mask & 0x40) {
-                       speed = XFER_UDMA_6;
-                       break;
-               }
-       case 3:
-               if (ultra_mask & 0x20) {
-                       speed = XFER_UDMA_5;
-                       break;
-               }
-       case 2:
-               if (ultra_mask & 0x10) {
-                       speed = XFER_UDMA_4;
-                       break;
-               }
-               if (ultra_mask & 0x08) {
-                       speed = XFER_UDMA_3;
-                       break;
-               }
-       case 1:
-               if (ultra_mask & 0x04) {
-                       speed = XFER_UDMA_2;
-                       break;
-               }
-               if (ultra_mask & 0x02) {
-                       speed = XFER_UDMA_1;
-                       break;
-               }
-               if (ultra_mask & 0x01) {
-                       speed = XFER_UDMA_0;
-                       break;
-               }
-       case 0:
-               mwdma_mask = id->dma_mword & hwif->mwdma_mask;
-
-               if (mwdma_mask & 0x04) {
-                       speed = XFER_MW_DMA_2;
-                       break;
-               }
-               if (mwdma_mask & 0x02) {
-                       speed = XFER_MW_DMA_1;
-                       break;
-               }
-               if (mwdma_mask & 0x01) {
-                       speed = XFER_MW_DMA_0;
-                       break;
-               }
-
-               swdma_mask = id->dma_1word & hwif->swdma_mask;
-
-               if (swdma_mask & 0x04) {
-                       speed = XFER_SW_DMA_2;
-                       break;
-               }
-               if (swdma_mask & 0x02) {
-                       speed = XFER_SW_DMA_1;
-                       break;
-               }
-               if (swdma_mask & 0x01) {
-                       speed = XFER_SW_DMA_0;
-                       break;
-               }
-       }
-
-       return speed;
-}
-EXPORT_SYMBOL(ide_dma_speed);
-
-
-/**
- *     ide_rate_filter         -       return best speed for mode
- *     @mode: modes available
+ *     ide_rate_filter         -       filter transfer mode
+ *     @drive: IDE device
  *     @speed: desired speed
  *
- *     Given the available DMA/UDMA mode this function returns
+ *     Given the available transfer modes this function returns
  *     the best available speed at or below the speed requested.
+ *
+ *     FIXME: filter also PIO/SWDMA/MWDMA modes
  */
 
-u8 ide_rate_filter (u8 mode, u8 speed) 
+u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-       static u8 speed_max[] = {
-               XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
-               XFER_UDMA_5, XFER_UDMA_6
-       };
+       ide_hwif_t *hwif = drive->hwif;
+       u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+
+       if (hwif->udma_filter)
+               mask = hwif->udma_filter(drive);
+
+       /*
+        * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false
+        * cable warning from eighty_ninty_three(), moving ide_rate_filter()
+        * calls from ->speedproc to core code will make this hack go away
+        */
+       if (speed > XFER_UDMA_2) {
+               if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+                       mask &= 0x07;
+       }
+
+       if (mask)
+               mode = fls(mask) - 1 + XFER_UDMA_0;
 
 //     printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
 
-       /* So that we remember to update this if new modes appear */
-       BUG_ON(mode > 4);
-       return min(speed, speed_max[mode]);
+       return min(speed, mode);
 #else /* !CONFIG_BLK_DEV_IDEDMA */
        return min(speed, (u8)XFER_PIO_4);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
index 98410ca044cfc4c21a50f430f930a322588ab96c..2b8009c50e91363c1316c3a8bbfad6208e823942 100644 (file)
@@ -42,7 +42,7 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
        hw.irq = pnp_irq(dev, 0);
        hw.dma = NO_DMA;
 
-       index = ide_register_hw(&hw, &hwif);
+       index = ide_register_hw(&hw, 1, &hwif);
 
        if (index != -1) {
                printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
index 8f15c23aa70d7eaa2e049ad7a0e2be95705886a0..3cebed77f55d27020b8be9b4331571cd80e00844 100644 (file)
@@ -1427,6 +1427,9 @@ int ideprobe_init (void)
                                }
                }
        }
+       for (index = 0; index < MAX_HWIFS; ++index)
+               if (probe[index])
+                       ide_proc_register_port(&ide_hwifs[index]);
        return 0;
 }
 
index a9e0b30fb1f2180216c75aadded6492821aa6898..d50bd996ff22939a9613c6399cd9b4d932789bd4 100644 (file)
@@ -3,6 +3,8 @@
  *
  *  Copyright (C) 1997-1998    Mark Lord
  *  Copyright (C) 2003         Red Hat <alan@redhat.com>
+ *
+ *  Some code was moved here from ide.c, see it for original copyrights.
  */
 
 /*
@@ -37,6 +39,8 @@
 
 #include <asm/io.h>
 
+static struct proc_dir_entry *proc_ide_root;
+
 static int proc_ide_read_imodel
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -121,6 +125,265 @@ static int proc_ide_read_identify
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+/**
+ *     __ide_add_setting       -       add an ide setting option
+ *     @drive: drive to use
+ *     @name: setting name
+ *     @rw: true if the function is read write
+ *     @data_type: type of data
+ *     @min: range minimum
+ *     @max: range maximum
+ *     @mul_factor: multiplication scale
+ *     @div_factor: divison scale
+ *     @data: private data field
+ *     @set: setting
+ *     @auto_remove: setting auto removal flag
+ *
+ *     Removes the setting named from the device if it is present.
+ *     The function takes the settings_lock to protect against
+ *     parallel changes. This function must not be called from IRQ
+ *     context. Returns 0 on success or -1 on failure.
+ *
+ *     BUGS: This code is seriously over-engineered. There is also
+ *     magic about how the driver specific features are setup. If
+ *     a driver is attached we assume the driver settings are auto
+ *     remove.
+ */
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
+{
+       ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
+
+       down(&ide_setting_sem);
+       while ((*p) && strcmp((*p)->name, name) < 0)
+               p = &((*p)->next);
+       if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+               goto abort;
+       if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
+               goto abort;
+       strcpy(setting->name, name);
+       setting->rw = rw;
+       setting->data_type = data_type;
+       setting->min = min;
+       setting->max = max;
+       setting->mul_factor = mul_factor;
+       setting->div_factor = div_factor;
+       setting->data = data;
+       setting->set = set;
+
+       setting->next = *p;
+       if (auto_remove)
+               setting->auto_remove = 1;
+       *p = setting;
+       up(&ide_setting_sem);
+       return 0;
+abort:
+       up(&ide_setting_sem);
+       kfree(setting);
+       return -1;
+}
+
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+       return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
+EXPORT_SYMBOL(ide_add_setting);
+
+/**
+ *     __ide_remove_setting    -       remove an ide setting option
+ *     @drive: drive to use
+ *     @name: setting name
+ *
+ *     Removes the setting named from the device if it is present.
+ *     The caller must hold the setting semaphore.
+ */
+
+static void __ide_remove_setting (ide_drive_t *drive, char *name)
+{
+       ide_settings_t **p, *setting;
+
+       p = (ide_settings_t **) &drive->settings;
+
+       while ((*p) && strcmp((*p)->name, name))
+               p = &((*p)->next);
+       if ((setting = (*p)) == NULL)
+               return;
+
+       (*p) = setting->next;
+
+       kfree(setting->name);
+       kfree(setting);
+}
+
+/**
+ *     auto_remove_settings    -       remove driver specific settings
+ *     @drive: drive
+ *
+ *     Automatically remove all the driver specific settings for this
+ *     drive. This function may not be called from IRQ context. The
+ *     caller must hold ide_setting_sem.
+ */
+
+static void auto_remove_settings (ide_drive_t *drive)
+{
+       ide_settings_t *setting;
+repeat:
+       setting = drive->settings;
+       while (setting) {
+               if (setting->auto_remove) {
+                       __ide_remove_setting(drive, setting->name);
+                       goto repeat;
+               }
+               setting = setting->next;
+       }
+}
+
+/**
+ *     ide_find_setting_by_name        -       find a drive specific setting
+ *     @drive: drive to scan
+ *     @name: setting name
+ *
+ *     Scan's the device setting table for a matching entry and returns
+ *     this or NULL if no entry is found. The caller must hold the
+ *     setting semaphore
+ */
+
+static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+{
+       ide_settings_t *setting = drive->settings;
+
+       while (setting) {
+               if (strcmp(setting->name, name) == 0)
+                       break;
+               setting = setting->next;
+       }
+       return setting;
+}
+
+/**
+ *     ide_read_setting        -       read an IDE setting
+ *     @drive: drive to read from
+ *     @setting: drive setting
+ *
+ *     Read a drive setting and return the value. The caller
+ *     must hold the ide_setting_sem when making this call.
+ *
+ *     BUGS: the data return and error are the same return value
+ *     so an error -EINVAL and true return of the same value cannot
+ *     be told apart
+ */
+
+static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+{
+       int             val = -EINVAL;
+       unsigned long   flags;
+
+       if ((setting->rw & SETTING_READ)) {
+               spin_lock_irqsave(&ide_lock, flags);
+               switch(setting->data_type) {
+                       case TYPE_BYTE:
+                               val = *((u8 *) setting->data);
+                               break;
+                       case TYPE_SHORT:
+                               val = *((u16 *) setting->data);
+                               break;
+                       case TYPE_INT:
+                               val = *((u32 *) setting->data);
+                               break;
+               }
+               spin_unlock_irqrestore(&ide_lock, flags);
+       }
+       return val;
+}
+
+/**
+ *     ide_write_setting       -       read an IDE setting
+ *     @drive: drive to read from
+ *     @setting: drive setting
+ *     @val: value
+ *
+ *     Write a drive setting if it is possible. The caller
+ *     must hold the ide_setting_sem when making this call.
+ *
+ *     BUGS: the data return and error are the same return value
+ *     so an error -EINVAL and true return of the same value cannot
+ *     be told apart
+ *
+ *     FIXME:  This should be changed to enqueue a special request
+ *     to the driver to change settings, and then wait on a sema for completion.
+ *     The current scheme of polling is kludgy, though safe enough.
+ */
+
+static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (setting->set)
+               return setting->set(drive, val);
+       if (!(setting->rw & SETTING_WRITE))
+               return -EPERM;
+       if (val < setting->min || val > setting->max)
+               return -EINVAL;
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       switch (setting->data_type) {
+               case TYPE_BYTE:
+                       *((u8 *) setting->data) = val;
+                       break;
+               case TYPE_SHORT:
+                       *((u16 *) setting->data) = val;
+                       break;
+               case TYPE_INT:
+                       *((u32 *) setting->data) = val;
+                       break;
+       }
+       spin_unlock_irq(&ide_lock);
+       return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+       int err;
+
+       if (arg < 0 || arg > 70)
+               return -EINVAL;
+
+       err = ide_wait_cmd(drive,
+                       WIN_SETFEATURES, (u8) arg,
+                       SETFEATURES_XFER, 0, NULL);
+
+       if (!err && arg) {
+               ide_set_xfer_rate(drive, (u8) arg);
+               ide_driveid_update(drive);
+       }
+       return err;
+}
+
+/**
+ *     ide_add_generic_settings        -       generic ide settings
+ *     @drive: drive being configured
+ *
+ *     Add the generic parts of the system settings to the /proc files.
+ *     The caller must not be holding the ide_setting_sem.
+ */
+
+void ide_add_generic_settings (ide_drive_t *drive)
+{
+/*
+ *                       drive         setting name            read/write access                               data type       min     max                             mul_factor      div_factor      data pointer                    set function
+ */
+       __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
+       __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
+       __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
+       __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
+       __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
+       __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
+       __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
+       __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
+       __ide_add_setting(drive,        "number",               SETTING_RW,                                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
+}
+
 static void proc_ide_settings_warn(void)
 {
        static int warned = 0;
@@ -399,7 +662,7 @@ static ide_proc_entry_t generic_drive_entries[] = {
        { NULL, 0, NULL, NULL }
 };
 
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
+static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
 {
        struct proc_dir_entry *ent;
 
@@ -415,7 +678,7 @@ void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void
        }
 }
 
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
+static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
        if (!dir || !p)
                return;
@@ -425,6 +688,51 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
        }
 }
 
+void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+       ide_add_proc_entries(drive->proc, driver->proc, drive);
+}
+
+EXPORT_SYMBOL(ide_proc_register_driver);
+
+/**
+ *     ide_proc_unregister_driver      -       remove driver specific data
+ *     @drive: drive
+ *     @driver: driver
+ *
+ *     Clean up the driver specific /proc files and IDE settings
+ *     for a given drive.
+ *
+ *     Takes ide_setting_sem and ide_lock.
+ *     Caller must hold none of the locks.
+ */
+
+void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+       unsigned long flags;
+
+       ide_remove_proc_entries(drive->proc, driver->proc);
+
+       down(&ide_setting_sem);
+       spin_lock_irqsave(&ide_lock, flags);
+       /*
+        * ide_setting_sem protects the settings list
+        * ide_lock protects the use of settings
+        *
+        * so we need to hold both, ide_settings_sem because we want to
+        * modify the settings list, and ide_lock because we cannot take
+        * a setting out that is being used.
+        *
+        * OTOH both ide_{read,write}_setting are only ever used under
+        * ide_setting_sem.
+        */
+       auto_remove_settings(drive);
+       spin_unlock_irqrestore(&ide_lock, flags);
+       up(&ide_setting_sem);
+}
+
+EXPORT_SYMBOL(ide_proc_unregister_driver);
+
 static void create_proc_ide_drives(ide_hwif_t *hwif)
 {
        int     d;
@@ -477,26 +785,24 @@ static ide_proc_entry_t hwif_entries[] = {
        { NULL, 0, NULL, NULL }
 };
 
-void create_proc_ide_interfaces(void)
+void ide_proc_register_port(ide_hwif_t *hwif)
 {
-       int     h;
+       if (!hwif->present)
+               return;
 
-       for (h = 0; h < MAX_HWIFS; h++) {
-               ide_hwif_t *hwif = &ide_hwifs[h];
+       if (!hwif->proc) {
+               hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
 
-               if (!hwif->present)
-                       continue;
-               if (!hwif->proc) {
-                       hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
-                       if (!hwif->proc)
-                               return;
-                       ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
-               }
-               create_proc_ide_drives(hwif);
+               if (!hwif->proc)
+                       return;
+
+               ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
        }
+
+       create_proc_ide_drives(hwif);
 }
 
-EXPORT_SYMBOL(create_proc_ide_interfaces);
+EXPORT_SYMBOL_GPL(ide_proc_register_port);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
@@ -507,7 +813,7 @@ void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
 EXPORT_SYMBOL_GPL(ide_pci_create_host_proc);
 #endif
 
-void destroy_proc_ide_interface(ide_hwif_t *hwif)
+void ide_proc_unregister_port(ide_hwif_t *hwif)
 {
        if (hwif->proc) {
                destroy_proc_ide_drives(hwif);
@@ -554,11 +860,11 @@ void proc_ide_create(void)
 {
        struct proc_dir_entry *entry;
 
+       proc_ide_root = proc_mkdir("ide", NULL);
+
        if (!proc_ide_root)
                return;
 
-       create_proc_ide_interfaces();
-
        entry = create_proc_entry("drivers", 0, proc_ide_root);
        if (entry)
                entry->proc_fops = &ide_drivers_operations;
index 4e59239fef75e1ecd7638d0dcf3f7fdc6e4a2b7b..e82bfa5e0ab88a383cff8d665cb0fe7d1f78d758 100644 (file)
@@ -4561,28 +4561,33 @@ static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
        printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
+#ifdef CONFIG_IDE_PROC_FS
 static void idetape_add_settings (ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
 /*
- *                     drive   setting name    read/write      ioctl   ioctl           data type       min                     max                     mul_factor                      div_factor                      data pointer                            set function
+ *                     drive   setting name            read/write      data type       min                     max                     mul_factor                      div_factor      data pointer                            set function
  */
-       ide_add_setting(drive,  "buffer",       SETTING_READ,   -1,     -1,             TYPE_SHORT,     0,                      0xffff,                 1,                              2,                              &tape->capabilities.buffer_size,        NULL);
-       ide_add_setting(drive,  "pipeline_min", SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->min_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline",     SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->max_stages,                      NULL);
-       ide_add_setting(drive,  "pipeline_max", SETTING_RW,     -1,     -1,             TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->max_pipeline,                    NULL);
-       ide_add_setting(drive,  "pipeline_used",SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->nr_stages,                       NULL);
-       ide_add_setting(drive,  "pipeline_pending",SETTING_READ,-1,     -1,             TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,                              &tape->nr_pending_stages,               NULL);
-       ide_add_setting(drive,  "speed",        SETTING_READ,   -1,     -1,             TYPE_SHORT,     0,                      0xffff,                 1,                              1,                              &tape->capabilities.speed,              NULL);
-       ide_add_setting(drive,  "stage",        SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1024,                           &tape->stage_size,                      NULL);
-       ide_add_setting(drive,  "tdsc",         SETTING_RW,     -1,     -1,             TYPE_INT,       IDETAPE_DSC_RW_MIN,     IDETAPE_DSC_RW_MAX,     1000,                           HZ,                             &tape->best_dsc_rw_frequency,           NULL);
-       ide_add_setting(drive,  "dsc_overlap",  SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,                      1,                      1,                              1,                              &drive->dsc_overlap,                    NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_c",SETTING_READ,   -1,     -1,     TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->controlled_pipeline_head_speed,  NULL);
-       ide_add_setting(drive,  "pipeline_head_speed_u",SETTING_READ,   -1,     -1,     TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->uncontrolled_pipeline_head_speed,        NULL);
-       ide_add_setting(drive,  "avg_speed",    SETTING_READ,   -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->avg_speed,               NULL);
-       ide_add_setting(drive,  "debug_level",SETTING_RW,       -1,     -1,             TYPE_INT,       0,                      0xffff,                 1,                              1,                              &tape->debug_level,             NULL);
+       ide_add_setting(drive,  "buffer",               SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              2,              &tape->capabilities.buffer_size,        NULL);
+       ide_add_setting(drive,  "pipeline_min",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->min_pipeline,                    NULL);
+       ide_add_setting(drive,  "pipeline",             SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_stages,                      NULL);
+       ide_add_setting(drive,  "pipeline_max",         SETTING_RW,     TYPE_INT,       1,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->max_pipeline,                    NULL);
+       ide_add_setting(drive,  "pipeline_used",        SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_stages,                       NULL);
+       ide_add_setting(drive,  "pipeline_pending",     SETTING_READ,   TYPE_INT,       0,                      0xffff,                 tape->stage_size / 1024,        1,              &tape->nr_pending_stages,               NULL);
+       ide_add_setting(drive,  "speed",                SETTING_READ,   TYPE_SHORT,     0,                      0xffff,                 1,                              1,              &tape->capabilities.speed,              NULL);
+       ide_add_setting(drive,  "stage",                SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1024,           &tape->stage_size,                      NULL);
+       ide_add_setting(drive,  "tdsc",                 SETTING_RW,     TYPE_INT,       IDETAPE_DSC_RW_MIN,     IDETAPE_DSC_RW_MAX,     1000,                           HZ,             &tape->best_dsc_rw_frequency,           NULL);
+       ide_add_setting(drive,  "dsc_overlap",          SETTING_RW,     TYPE_BYTE,      0,                      1,                      1,                              1,              &drive->dsc_overlap,                    NULL);
+       ide_add_setting(drive,  "pipeline_head_speed_c",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->controlled_pipeline_head_speed,  NULL);
+       ide_add_setting(drive,  "pipeline_head_speed_u",SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->uncontrolled_pipeline_head_speed,NULL);
+       ide_add_setting(drive,  "avg_speed",            SETTING_READ,   TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->avg_speed,                       NULL);
+       ide_add_setting(drive,  "debug_level",          SETTING_RW,     TYPE_INT,       0,                      0xffff,                 1,                              1,              &tape->debug_level,                     NULL);
 }
+#else
+static inline void idetape_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *     ide_setup is called to:
@@ -4703,7 +4708,7 @@ static void ide_tape_remove(ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
 
-       ide_unregister_subdriver(drive, tape->driver);
+       ide_proc_unregister_driver(drive, tape->driver);
 
        ide_unregister_region(tape->disk);
 
@@ -4730,8 +4735,7 @@ static void ide_tape_release(struct kref *kref)
        kfree(tape);
 }
 
-#ifdef CONFIG_PROC_FS
-
+#ifdef CONFIG_IDE_PROC_FS
 static int proc_idetape_read_name
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -4749,11 +4753,6 @@ static ide_proc_entry_t idetape_proc[] = {
        { "name",       S_IFREG|S_IRUGO,        proc_idetape_read_name, NULL },
        { NULL, 0, NULL, NULL }
 };
-
-#else
-
-#define        idetape_proc    NULL
-
 #endif
 
 static int ide_tape_probe(ide_drive_t *);
@@ -4773,7 +4772,9 @@ static ide_driver_t idetape_driver = {
        .end_request            = idetape_end_request,
        .error                  = __ide_error,
        .abort                  = __ide_abort,
+#ifdef CONFIG_IDE_PROC_FS
        .proc                   = idetape_proc,
+#endif
 };
 
 /*
@@ -4864,7 +4865,7 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       ide_register_subdriver(drive, &idetape_driver);
+       ide_proc_register_driver(drive, &idetape_driver);
 
        kref_init(&tape->kref);
 
index ae5bf2be6f52b158597aadd6b57245b746824f43..f2b547ff7722f320b7d7d9ac8e220c4ab9c77e9d 100644 (file)
@@ -168,12 +168,11 @@ static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 
 static int idebus_parameter;   /* holds the "idebus=" parameter */
 static int system_bus_speed;   /* holds what we think is VESA/PCI bus speed */
-static int initializing;       /* set while initializing built-in drivers */
 
 DECLARE_MUTEX(ide_cfg_sem);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
@@ -216,9 +215,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
        hwif->bus_state = BUSSTATE_ON;
 
        hwif->atapi_dma = 0;            /* disable all atapi dma */ 
-       hwif->ultra_mask = 0x80;        /* disable all ultra */
-       hwif->mwdma_mask = 0x80;        /* disable all mwdma */
-       hwif->swdma_mask = 0x80;        /* disable all swdma */
 
        init_completion(&hwif->gendev_rel_comp);
 
@@ -305,9 +301,7 @@ static void __init init_ide_data (void)
 #endif
        }
 #ifdef CONFIG_IDE_ARM
-       initializing = 1;
        ide_arm_init();
-       initializing = 0;
 #endif
 }
 
@@ -353,10 +347,6 @@ static int ide_system_bus_speed(void)
        return system_bus_speed;
 }
 
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ide_root;
-#endif
-
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
                                            unsigned long addr, int num)
 {
@@ -480,6 +470,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 
        hwif->tuneproc                  = tmp_hwif->tuneproc;
        hwif->speedproc                 = tmp_hwif->speedproc;
+       hwif->udma_filter               = tmp_hwif->udma_filter;
        hwif->selectproc                = tmp_hwif->selectproc;
        hwif->reset_poll                = tmp_hwif->reset_poll;
        hwif->pre_reset                 = tmp_hwif->pre_reset;
@@ -599,7 +590,7 @@ void ide_unregister(unsigned int index)
 
        spin_unlock_irq(&ide_lock);
 
-       destroy_proc_ide_interface(hwif);
+       ide_proc_unregister_port(hwif);
 
        hwgroup = hwif->hwgroup;
        /*
@@ -751,6 +742,7 @@ void ide_setup_ports (      hw_regs_t *hw,
 /**
  *     ide_register_hw_with_fixup      -       register IDE interface
  *     @hw: hardware registers
+ *     @initializing: set while initializing built-in drivers
  *     @hwifp: pointer to returned hwif
  *     @fixup: fixup function
  *
@@ -760,7 +752,9 @@ void ide_setup_ports (      hw_regs_t *hw,
  *     Returns -1 on error.
  */
 
-int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
+int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
+                              ide_hwif_t **hwifp,
+                              void(*fixup)(ide_hwif_t *hwif))
 {
        int index, retry = 1;
        ide_hwif_t *hwif;
@@ -801,7 +795,7 @@ found:
 
        if (!initializing) {
                probe_hwif_init_with_fixup(hwif, fixup);
-               create_proc_ide_interfaces();
+               ide_proc_register_port(hwif);
        }
 
        if (hwifp)
@@ -812,9 +806,9 @@ found:
 
 EXPORT_SYMBOL(ide_register_hw_with_fixup);
 
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, int initializing, ide_hwif_t **hwifp)
 {
-       return ide_register_hw_with_fixup(hw, hwifp, NULL);
+       return ide_register_hw_with_fixup(hw, initializing, hwifp, NULL);
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -825,205 +819,7 @@ EXPORT_SYMBOL(ide_register_hw);
 
 DECLARE_MUTEX(ide_setting_sem);
 
-/**
- *     __ide_add_setting       -       add an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *     @rw: true if the function is read write
- *     @read_ioctl: function to call on read
- *     @write_ioctl: function to call on write
- *     @data_type: type of data
- *     @min: range minimum
- *     @max: range maximum
- *     @mul_factor: multiplication scale
- *     @div_factor: divison scale
- *     @data: private data field
- *     @set: setting
- *     @auto_remove: setting auto removal flag
- *
- *     Removes the setting named from the device if it is present.
- *     The function takes the settings_lock to protect against 
- *     parallel changes. This function must not be called from IRQ
- *     context. Returns 0 on success or -1 on failure.
- *
- *     BUGS: This code is seriously over-engineered. There is also
- *     magic about how the driver specific features are setup. If
- *     a driver is attached we assume the driver settings are auto
- *     remove.
- */
-
-static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
-{
-       ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
-
-       down(&ide_setting_sem);
-       while ((*p) && strcmp((*p)->name, name) < 0)
-               p = &((*p)->next);
-       if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
-               goto abort;
-       if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
-               goto abort;
-       strcpy(setting->name, name);
-       setting->rw = rw;
-       setting->read_ioctl = read_ioctl;
-       setting->write_ioctl = write_ioctl;
-       setting->data_type = data_type;
-       setting->min = min;
-       setting->max = max;
-       setting->mul_factor = mul_factor;
-       setting->div_factor = div_factor;
-       setting->data = data;
-       setting->set = set;
-       
-       setting->next = *p;
-       if (auto_remove)
-               setting->auto_remove = 1;
-       *p = setting;
-       up(&ide_setting_sem);
-       return 0;
-abort:
-       up(&ide_setting_sem);
-       kfree(setting);
-       return -1;
-}
-
-int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
-{
-       return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
-}
-
-EXPORT_SYMBOL(ide_add_setting);
-
-/**
- *     __ide_remove_setting    -       remove an ide setting option
- *     @drive: drive to use
- *     @name: setting name
- *
- *     Removes the setting named from the device if it is present.
- *     The caller must hold the setting semaphore.
- */
-static void __ide_remove_setting (ide_drive_t *drive, char *name)
-{
-       ide_settings_t **p, *setting;
-
-       p = (ide_settings_t **) &drive->settings;
-
-       while ((*p) && strcmp((*p)->name, name))
-               p = &((*p)->next);
-       if ((setting = (*p)) == NULL)
-               return;
-
-       (*p) = setting->next;
-       
-       kfree(setting->name);
-       kfree(setting);
-}
-
-/**
- *     ide_find_setting_by_ioctl       -       find a drive specific ioctl
- *     @drive: drive to scan
- *     @cmd: ioctl command to handle
- *
- *     Scan's the device setting table for a matching entry and returns
- *     this or NULL if no entry is found. The caller must hold the
- *     setting semaphore
- */
-static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
-{
-       ide_settings_t *setting = drive->settings;
-
-       while (setting) {
-               if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
-                       break;
-               setting = setting->next;
-       }
-       
-       return setting;
-}
-
-/**
- *     ide_find_setting_by_name        -       find a drive specific setting
- *     @drive: drive to scan
- *     @name: setting name
- *
- *     Scan's the device setting table for a matching entry and returns
- *     this or NULL if no entry is found. The caller must hold the
- *     setting semaphore
- */
-ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
-{
-       ide_settings_t *setting = drive->settings;
-
-       while (setting) {
-               if (strcmp(setting->name, name) == 0)
-                       break;
-               setting = setting->next;
-       }
-       return setting;
-}
-
-/**
- *     auto_remove_settings    -       remove driver specific settings
- *     @drive: drive
- *
- *     Automatically remove all the driver specific settings for this
- *     drive. This function may not be called from IRQ context. The
- *     caller must hold ide_setting_sem.
- */
-static void auto_remove_settings (ide_drive_t *drive)
-{
-       ide_settings_t *setting;
-repeat:
-       setting = drive->settings;
-       while (setting) {
-               if (setting->auto_remove) {
-                       __ide_remove_setting(drive, setting->name);
-                       goto repeat;
-               }
-               setting = setting->next;
-       }
-}
-
-/**
- *     ide_read_setting        -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *
- *     Read a drive setting and return the value. The caller
- *     must hold the ide_setting_sem when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- */
-int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
-{
-       int             val = -EINVAL;
-       unsigned long   flags;
-
-       if ((setting->rw & SETTING_READ)) {
-               spin_lock_irqsave(&ide_lock, flags);
-               switch(setting->data_type) {
-                       case TYPE_BYTE:
-                               val = *((u8 *) setting->data);
-                               break;
-                       case TYPE_SHORT:
-                               val = *((u16 *) setting->data);
-                               break;
-                       case TYPE_INT:
-                       case TYPE_INTA:
-                               val = *((u32 *) setting->data);
-                               break;
-               }
-               spin_unlock_irqrestore(&ide_lock, flags);
-       }
-       return val;
-}
+EXPORT_SYMBOL_GPL(ide_setting_sem);
 
 /**
  *     ide_spin_wait_hwgroup   -       wait for group
@@ -1058,61 +854,14 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
 
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
 
-/**
- *     ide_write_setting       -       read an IDE setting
- *     @drive: drive to read from
- *     @setting: drive setting
- *     @val: value
- *
- *     Write a drive setting if it is possible. The caller
- *     must hold the ide_setting_sem when making this call.
- *
- *     BUGS: the data return and error are the same return value
- *     so an error -EINVAL and true return of the same value cannot
- *     be told apart
- *
- *     FIXME:  This should be changed to enqueue a special request
- *     to the driver to change settings, and then wait on a sema for completion.
- *     The current scheme of polling is kludgy, though safe enough.
- */
-
-int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
+int set_io_32bit(ide_drive_t *drive, int arg)
 {
-       int i;
-       u32 *p;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EACCES;
-       if (!(setting->rw & SETTING_WRITE))
+       if (drive->no_io_32bit)
                return -EPERM;
-       if (val < setting->min || val > setting->max)
+
+       if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
                return -EINVAL;
-       if (setting->set)
-               return setting->set(drive, val);
-       if (ide_spin_wait_hwgroup(drive))
-               return -EBUSY;
-       switch (setting->data_type) {
-               case TYPE_BYTE:
-                       *((u8 *) setting->data) = val;
-                       break;
-               case TYPE_SHORT:
-                       *((u16 *) setting->data) = val;
-                       break;
-               case TYPE_INT:
-                       *((u32 *) setting->data) = val;
-                       break;
-               case TYPE_INTA:
-                       p = (u32 *) setting->data;
-                       for (i = 0; i < 1 << PARTN_BITS; i++, p++)
-                               *p = val;
-                       break;
-       }
-       spin_unlock_irq(&ide_lock);
-       return 0;
-}
 
-static int set_io_32bit(ide_drive_t *drive, int arg)
-{
        drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
        if (HWIF(drive)->chipset == ide_dtc2278)
@@ -1121,12 +870,28 @@ static int set_io_32bit(ide_drive_t *drive, int arg)
        return 0;
 }
 
-static int set_using_dma (ide_drive_t *drive, int arg)
+static int set_ksettings(ide_drive_t *drive, int arg)
+{
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       drive->keep_settings = arg;
+       spin_unlock_irq(&ide_lock);
+
+       return 0;
+}
+
+int set_using_dma(ide_drive_t *drive, int arg)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
        ide_hwif_t *hwif = drive->hwif;
        int err = -EPERM;
 
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        if (!drive->id || !(drive->id->capability & 1))
                goto out;
 
@@ -1159,14 +924,20 @@ static int set_using_dma (ide_drive_t *drive, int arg)
 out:
        return err;
 #else
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
+
        return -EPERM;
 #endif
 }
 
-static int set_pio_mode (ide_drive_t *drive, int arg)
+int set_pio_mode(ide_drive_t *drive, int arg)
 {
        struct request rq;
 
+       if (arg < 0 || arg > 255)
+               return -EINVAL;
+
        if (!HWIF(drive)->tuneproc)
                return -ENOSYS;
        if (drive->special.b.set_tune)
@@ -1178,42 +949,20 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
        return 0;
 }
 
-static int set_xfer_rate (ide_drive_t *drive, int arg)
+static int set_unmaskirq(ide_drive_t *drive, int arg)
 {
-       int err = ide_wait_cmd(drive,
-                       WIN_SETFEATURES, (u8) arg,
-                       SETFEATURES_XFER, 0, NULL);
+       if (drive->no_unmask)
+               return -EPERM;
 
-       if (!err && arg) {
-               ide_set_xfer_rate(drive, (u8) arg);
-               ide_driveid_update(drive);
-       }
-       return err;
-}
+       if (arg < 0 || arg > 1)
+               return -EINVAL;
 
-/**
- *     ide_add_generic_settings        -       generic ide settings
- *     @drive: drive being configured
- *
- *     Add the generic parts of the system settings to the /proc files and
- *     ioctls for this IDE device. The caller must not be holding the
- *     ide_setting_sem.
- */
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       drive->unmask = arg;
+       spin_unlock_irq(&ide_lock);
 
-void ide_add_generic_settings (ide_drive_t *drive)
-{
-/*
- *                       drive         setting name            read/write access                               read ioctl              write ioctl             data type       min     max                             mul_factor      div_factor      data pointer                    set function
- */
-       __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT,         HDIO_SET_32BIT,         TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
-       __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     HDIO_GET_KEEPSETTINGS,  HDIO_SET_KEEPSETTINGS,  TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
-       __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
-       __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  -1,                     HDIO_SET_PIO_MODE,      TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
-       __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   HDIO_GET_UNMASKINTR,    HDIO_SET_UNMASKINTR,    TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
-       __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     HDIO_GET_DMA,           HDIO_SET_DMA,           TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
-       __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
-       __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
-       __ide_add_setting(drive,        "number",               SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
+       return 0;
 }
 
 /**
@@ -1285,27 +1034,23 @@ static int generic_ide_resume(struct device *dev)
 int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
                        unsigned int cmd, unsigned long arg)
 {
-       ide_settings_t *setting;
+       unsigned long flags;
        ide_driver_t *drv;
-       int err = 0;
        void __user *p = (void __user *)arg;
+       int err = 0, (*setfunc)(ide_drive_t *, int);
+       u8 *val;
 
-       down(&ide_setting_sem);
-       if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
-               if (cmd == setting->read_ioctl) {
-                       err = ide_read_setting(drive, setting);
-                       up(&ide_setting_sem);
-                       return err >= 0 ? put_user(err, (long __user *)arg) : err;
-               } else {
-                       if (bdev != bdev->bd_contains)
-                               err = -EINVAL;
-                       else
-                               err = ide_write_setting(drive, setting, arg);
-                       up(&ide_setting_sem);
-                       return err;
-               }
+       switch (cmd) {
+       case HDIO_GET_32BIT:        val = &drive->io_32bit;      goto read_val;
+       case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val;
+       case HDIO_GET_UNMASKINTR:   val = &drive->unmask;        goto read_val;
+       case HDIO_GET_DMA:          val = &drive->using_dma;     goto read_val;
+       case HDIO_SET_32BIT:        setfunc = set_io_32bit;      goto set_val;
+       case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings;     goto set_val;
+       case HDIO_SET_PIO_MODE:     setfunc = set_pio_mode;      goto set_val;
+       case HDIO_SET_UNMASKINTR:   setfunc = set_unmaskirq;     goto set_val;
+       case HDIO_SET_DMA:          setfunc = set_using_dma;     goto set_val;
        }
-       up(&ide_setting_sem);
 
        switch (cmd) {
                case HDIO_OBSOLETE_IDENTITY:
@@ -1359,7 +1104,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        ide_init_hwif_ports(&hw, (unsigned long) args[0],
                                            (unsigned long) args[1], NULL);
                        hw.irq = args[2];
-                       if (ide_register_hw(&hw, NULL) == -1)
+                       if (ide_register_hw(&hw, 0, NULL) == -1)
                                return -EIO;
                        return 0;
                }
@@ -1434,6 +1179,28 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                default:
                        return -EINVAL;
        }
+
+read_val:
+       down(&ide_setting_sem);
+       spin_lock_irqsave(&ide_lock, flags);
+       err = *val;
+       spin_unlock_irqrestore(&ide_lock, flags);
+       up(&ide_setting_sem);
+       return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+       if (bdev != bdev->bd_contains)
+               err = -EINVAL;
+       else {
+               if (!capable(CAP_SYS_ADMIN))
+                       err = -EACCES;
+               else {
+                       down(&ide_setting_sem);
+                       err = setfunc(drive, arg);
+                       up(&ide_setting_sem);
+               }
+       }
+       return err;
 }
 
 EXPORT_SYMBOL(generic_ide_ioctl);
@@ -1566,13 +1333,13 @@ static int __init ide_setup(char *s)
                return 1;
        }
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
        if (!strcmp(s, "ide=reverse")) {
                ide_scan_direction = 1;
                printk(" : Enabled support for IDE inverse scan order.\n");
                return 1;
        }
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 
 #ifdef CONFIG_BLK_DEV_IDEACPI
        if (!strcmp(s, "ide=noacpi")) {
@@ -1832,9 +1599,9 @@ extern void __init h8300_ide_init(void);
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_BLK_DEV_IDEPCI
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
        ide_scan_pcibus(ide_scan_direction);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 
 #ifdef CONFIG_ETRAX_IDE
        {
@@ -1892,54 +1659,6 @@ static void __init probe_for_hwifs (void)
 #endif
 }
 
-void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-#ifdef CONFIG_PROC_FS
-       ide_add_proc_entries(drive->proc, driver->proc, drive);
-#endif
-}
-
-EXPORT_SYMBOL(ide_register_subdriver);
-
-/**
- *     ide_unregister_subdriver        -       disconnect drive from driver
- *     @drive: drive to unplug
- *     @driver: driver
- *
- *     Disconnect a drive from the driver it was attached to and then
- *     clean up the various proc files and other objects attached to it.
- *
- *     Takes ide_setting_sem and ide_lock.
- *     Caller must hold none of the locks.
- */
-
-void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver)
-{
-       unsigned long flags;
-       
-#ifdef CONFIG_PROC_FS
-       ide_remove_proc_entries(drive->proc, driver->proc);
-#endif
-       down(&ide_setting_sem);
-       spin_lock_irqsave(&ide_lock, flags);
-       /*
-        * ide_setting_sem protects the settings list
-        * ide_lock protects the use of settings
-        *
-        * so we need to hold both, ide_settings_sem because we want to
-        * modify the settings list, and ide_lock because we cannot take
-        * a setting out that is being used.
-        *
-        * OTOH both ide_{read,write}_setting are only ever used under
-        * ide_setting_sem.
-        */
-       auto_remove_settings(drive);
-       spin_unlock_irqrestore(&ide_lock, flags);
-       up(&ide_setting_sem);
-}
-
-EXPORT_SYMBOL(ide_unregister_subdriver);
-
 /*
  * Probe module
  */
@@ -2071,9 +1790,7 @@ static int __init ide_init(void)
 
        init_ide_data();
 
-#ifdef CONFIG_PROC_FS
-       proc_ide_root = proc_mkdir("ide", NULL);
-#endif
+       proc_ide_create();
 
 #ifdef CONFIG_BLK_DEV_ALI14XX
        if (probe_ali14xx)
@@ -2096,14 +1813,9 @@ static int __init ide_init(void)
                (void)qd65xx_init();
 #endif
 
-       initializing = 1;
        /* Probe for special PCI and other "known" interface chipsets. */
        probe_for_hwifs();
-       initializing = 0;
 
-#ifdef CONFIG_PROC_FS
-       proc_ide_create();
-#endif
        return 0;
 }
 
@@ -2143,9 +1855,7 @@ void __exit cleanup_module (void)
        pnpide_exit();
 #endif
 
-#ifdef CONFIG_PROC_FS
        proc_ide_destroy();
-#endif
 
        bus_unregister(&ide_bus_type);
 }
index 91961aa030474fa02057f8ed2e8dd270b69f87d3..df17ed68c0bcb393635e2aeac319d1d119d8854b 100644 (file)
@@ -223,7 +223,8 @@ static int __init ali14xx_probe(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
-       create_proc_ide_interfaces();
+       ide_proc_register_port(hwif);
+       ide_proc_register_port(mate);
 
        return 0;
 }
index 1ed224a01f79ddd24e371740cccc55a4065e26fc..101aee1711c489c7985bc1d730e3ca6fb1452c29 100644 (file)
@@ -213,7 +213,7 @@ fail_base2:
                                                IRQ_AMIGA_PORTS);
                        }       
                        
-                       index = ide_register_hw(&hw, &hwif);
+                       index = ide_register_hw(&hw, 1, &hwif);
                        if (index != -1) {
                                hwif->mmio = 1;
                                printk("ide%d: ", index);
index 0219ffa64db663fae60e8bc3e994e1d76bd048c7..36a3f0ac61628767f8ca555d9a476a1101b89bb9 100644 (file)
@@ -138,7 +138,8 @@ static int __init dtc2278_probe(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
-       create_proc_ide_interfaces();
+       ide_proc_register_port(hwif);
+       ide_proc_register_port(mate);
 
        return 0;
 }
index a9f2cd5bb81e8419c31cad30e2eaa0a9db12a5b0..e1e9d9d6893fdd82990abdf124ae049c4e23c681 100644 (file)
@@ -70,7 +70,7 @@ void __init falconide_init(void)
                        0, 0, NULL,
 //                     falconide_iops,
                        IRQ_MFP_IDE);
-       index = ide_register_hw(&hw, NULL);
+       index = ide_register_hw(&hw, 1, NULL);
 
        if (index != -1)
            printk("ide%d: Falcon IDE interface\n", index);
index dcfadbbf55d88e0ccbe56b0abc831a63d9ecaab8..0830a021bbb609d4b103dc037239a0f2ec5bc934 100644 (file)
@@ -165,7 +165,7 @@ found:
 //                     &gayle_iops,
                        IRQ_AMIGA_PORTS);
 
-       index = ide_register_hw(&hw, &hwif);
+       index = ide_register_hw(&hw, 1, &hwif);
        if (index != -1) {
            hwif->mmio = 1;
            switch (i) {
index a2832643c522f0cc6805ca497cde92e32fb5fbbc..c8f353b1296f9ca84c50bb8e1f127f2b2e3f3bd3 100644 (file)
@@ -357,7 +357,8 @@ int __init ht6560b_init(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
-       create_proc_ide_interfaces();
+       ide_proc_register_port(hwif);
+       ide_proc_register_port(mate);
 
        return 0;
 
index c6522a64d7ec31b60cf25f5fd063452c6b0a8ab5..2f3977f195b7fab9f31ebe509d2639ddcee923b6 100644 (file)
@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
     hw.irq = irq;
     hw.chipset = ide_pci;
     hw.dev = &handle->dev;
-    return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
+    return ide_register_hw_with_fixup(&hw, 0, NULL, ide_undecoded_slave);
 }
 
 /*======================================================================
index 4c0079ad52ac16a9dd95df58e9afdde2a29239bf..c211fc78345d16b0c3f9da4ef96b8a1ff6c79bbd 100644 (file)
@@ -102,21 +102,21 @@ void macide_init(void)
                                0, 0, macide_ack_intr,
 //                             quadra_ide_iops,
                                IRQ_NUBUS_F);
-               index = ide_register_hw(&hw, &hwif);
+               index = ide_register_hw(&hw, 1, &hwif);
                break;
        case MAC_IDE_PB:
                ide_setup_ports(&hw, IDE_BASE, macide_offsets,
                                0, 0, macide_ack_intr,
 //                             macide_pb_iops,
                                IRQ_NUBUS_C);
-               index = ide_register_hw(&hw, &hwif);
+               index = ide_register_hw(&hw, 1, &hwif);
                break;
        case MAC_IDE_BABOON:
                ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
                                0, 0, NULL,
 //                             macide_baboon_iops,
                                IRQ_BABOON_1);
-               index = ide_register_hw(&hw, &hwif);
+               index = ide_register_hw(&hw, 1, &hwif);
                if (index == -1) break;
                if (macintosh_config->ident == MAC_MODEL_PB190) {
 
index 74f08124eabb772f2d5f80abff23e4b11bfafecf..e628a983ce3395706cdf905c52a37eab15abc9d9 100644 (file)
@@ -142,7 +142,7 @@ void q40ide_init(void)
                        0, NULL,
 //                     m68kide_iops,
                        q40ide_default_irq(pcide_bases[i]));
-       index = ide_register_hw(&hw, &hwif);
+       index = ide_register_hw(&hw, 1, &hwif);
        // **FIXME**
        if (index != -1)
                hwif->mmio = 1;
index 2fb8f50f1293e66df0008c9d0d44b4d6f39e43f4..d1414a75b52371d707aa5375ec5ee4b1221e2ca5 100644 (file)
@@ -427,7 +427,7 @@ static int __init qd_probe(int base)
                qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
                         &qd6500_tune_drive);
 
-               create_proc_ide_interfaces();
+               ide_proc_register_port(hwif);
 
                return 1;
        }
@@ -459,7 +459,7 @@ static int __init qd_probe(int base)
                                 &qd6580_tune_drive);
                        qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
-                       create_proc_ide_interfaces();
+                       ide_proc_register_port(hwif);
 
                        return 1;
                } else {
@@ -479,7 +479,8 @@ static int __init qd_probe(int base)
                                 &qd6580_tune_drive);
                        qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
-                       create_proc_ide_interfaces();
+                       ide_proc_register_port(hwif);
+                       ide_proc_register_port(mate);
 
                        return 0; /* no other qd65xx possible */
                }
index ca7974455578005242b4ec79bdcbffae174835c7..ddc403a0bd829dee9fef1c0fd4ca2f2afb3ce4c9 100644 (file)
@@ -160,7 +160,8 @@ static int __init umc8672_probe(void)
        probe_hwif_init(hwif);
        probe_hwif_init(mate);
 
-       create_proc_ide_interfaces();
+       ide_proc_register_port(hwif);
+       ide_proc_register_port(mate);
 
        return 0;
 }
index d54d9fe92a7d548324b38809d360fe1c280722fa..ca95e990862ebdf36df33f936e47709b8d1ace6a 100644 (file)
@@ -760,6 +760,9 @@ static int au_ide_probe(struct device *dev)
 #endif
 
        probe_hwif_init(hwif);
+
+       ide_proc_register_port(hwif);
+
        dev_set_drvdata(dev, hwif);
 
        printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
index 81fa06851b27dadfd5c4d34c58aa38b6a276c5f4..6e935d7c63fd987858b256ea0c786b02d737821f 100644 (file)
@@ -129,6 +129,9 @@ static int __devinit swarm_ide_probe(struct device *dev)
        hwif->irq = hwif->hw.irq;
 
        probe_hwif_init(hwif);
+
+       ide_proc_register_port(hwif);
+
        dev_set_drvdata(dev, hwif);
 
        return 0;
index 73bdf64dbbfcd07ae4f7bec783abba06c5cc5d90..b173bc66ce1e19ae25efef18e8361864c850a877 100644 (file)
@@ -87,38 +87,12 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
        return chipset_table->ultra_settings;
 }
 
-static u8 aec62xx_ratemask (ide_drive_t *drive)
-{
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 mode;
-
-       switch(hwif->pci_dev->device) {
-               case PCI_DEVICE_ID_ARTOP_ATP865:
-               case PCI_DEVICE_ID_ARTOP_ATP865R:
-                       mode = (inb(hwif->channel ?
-                                   hwif->mate->dma_status :
-                                   hwif->dma_status) & 0x10) ? 4 : 3;
-                       break;
-               case PCI_DEVICE_ID_ARTOP_ATP860:
-               case PCI_DEVICE_ID_ARTOP_ATP860R:
-                       mode = 2;
-                       break;
-               case PCI_DEVICE_ID_ARTOP_ATP850UF:
-               default:
-                       return 1;
-       }
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u16 d_conf              = 0;
-       u8 speed        = ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        u8 ultra = 0, ultra_conf = 0;
        u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
        unsigned long flags;
@@ -145,7 +119,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       u8 speed        = ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+       u8 speed        = ide_rate_filter(drive, xferspeed);
        u8 unit         = (drive->select.b.unit & 0x01);
        u8 tmp1 = 0, tmp2 = 0;
        u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -181,17 +155,6 @@ static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
        }
 }
 
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));       
-
-       if (!(speed))
-               return 0;
-
-       (void) aec62xx_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 {
        pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -200,7 +163,7 @@ static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
 
 static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
 {
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
@@ -261,11 +224,13 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
 
 static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
 {
+       struct pci_dev *dev = hwif->pci_dev;
+
        hwif->autodma = 0;
        hwif->tuneproc = &aec62xx_tune_drive;
        hwif->speedproc = &aec62xx_tune_chipset;
 
-       if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
+       if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
                hwif->serialized = hwif->channel;
 
        if (hwif->mate)
@@ -277,7 +242,15 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
                return;
        }
 
-       hwif->ultra_mask = 0x7f;
+       hwif->ultra_mask = hwif->cds->udma_mask;
+
+       /* atp865 and atp865r */
+       if (hwif->ultra_mask == 0x3f) {
+               /* check bit 0x10 of DMA status register */
+               if (inb(pci_resource_start(dev, 4) + 2) & 0x10)
+                       hwif->ultra_mask = 0x7f; /* udma0-6 */
+       }
+
        hwif->mwdma_mask = 0x07;
 
        hwif->ide_dma_check     = &aec62xx_config_drive_xfer_rate;
@@ -344,6 +317,7 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 1 */
                .name           = "AEC6260",
                .init_setup     = init_setup_aec62xx,
@@ -353,6 +327,7 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = NOAUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 2 */
                .name           = "AEC6260R",
                .init_setup     = init_setup_aec62xx,
@@ -363,6 +338,7 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = NEVER_BOARD,
+               .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "AEC6X80",
                .init_setup     = init_setup_aec6x80,
@@ -372,6 +348,7 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 4 */
                .name           = "AEC6X80R",
                .init_setup     = init_setup_aec6x80,
@@ -382,6 +359,7 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
 
index 946a12746cb5deaf45aca4abdb609368a99c9c1e..428efdae0c7b2ef4554b3d19439b3bf459012999 100644 (file)
@@ -50,7 +50,7 @@ static u8 m5229_revision;
 static u8 chip_is_1543c_e;
 static struct pci_dev *isa_dev;
 
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -278,7 +278,7 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
 
        return p-buffer; /* => must be less than 4k! */
 }
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /**
  *     ali15x3_tune_pio        -       set up chipset for PIO mode
@@ -378,74 +378,31 @@ static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
 }
 
 /**
- *     ali15x3_can_ultra       -       check for ultra DMA support
- *     @drive: drive to do the check
+ *     ali_udma_filter         -       compute UDMA mask
+ *     @drive: IDE device
  *
- *     Check the drive and controller revisions. Return 0 if UDMA is
- *     not available, or 1 if UDMA can be used. The actual rules for
- *     the ALi are
+ *     Return available UDMA modes.
+ *
+ *     The actual rules for the ALi are:
  *             No UDMA on revisions <= 0x20
  *             Disk only for revisions < 0xC2
  *             Not WDC drives for revisions < 0xC2
  *
  *     FIXME: WDC ifdef needs to die
  */
-static u8 ali15x3_can_ultra (ide_drive_t *drive)
-{
-#ifndef CONFIG_WDC_ALI15X3
-       struct hd_driveid *id   = drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
 
-       if (m5229_revision <= 0x20) {
-               return 0;
-       } else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-                  ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-                   (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-                  (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-               return 0;
-       } else {
-               return 1;
-       }
-}
-
-/**
- *     ali15x3_ratemask        -       generate DMA mode list
- *     @drive: drive to compute against
- *
- *     Generate a list of the available DMA modes for the drive. 
- *     FIXME: this function contains lots of bogus masking we can dump
- *
- *     Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
- */
-static u8 ali15x3_ratemask (ide_drive_t *drive)
+static u8 ali_udma_filter(ide_drive_t *drive)
 {
-       u8 mode = 0, can_ultra  = ali15x3_can_ultra(drive);
-
-       if (m5229_revision > 0xC4 && can_ultra) {
-               mode = 4;
-       } else if (m5229_revision == 0xC4 && can_ultra) {
-               mode = 3;
-       } else if (m5229_revision >= 0xC2 && can_ultra) {
-               mode = 2;
-       } else if (can_ultra) {
-               return 1;
-       } else {
-               return 0;
+       if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
+               if (drive->media != ide_disk)
+                       return 0;
+#ifndef CONFIG_WDC_ALI15X3
+               if (chip_is_1543c_e && strstr(drive->id->model, "WDC "))
+                       return 0;
+#endif
        }
 
-       /*
-        *      If the drive sees no suitable cable then UDMA 33
-        *      is the highest permitted mode
-        */
-        
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
+       return drive->hwif->ultra_mask;
 }
 
 /**
@@ -461,7 +418,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       u8 speed                = ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        u8 speed1               = speed;
        u8 unit                 = (drive->select.b.unit & 0x01);
        u8 tmpbyte              = 0x00;
@@ -511,7 +468,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
  
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!(speed))
                return 0;
@@ -609,13 +566,13 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
 
        isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
 
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
        if (!ali_proc) {
                ali_proc = 1;
                bmide_dev = dev;
                ide_pci_create_host_proc("ali", ali_get_info);
        }
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
        local_irq_save(flags);
 
@@ -771,6 +728,7 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
        hwif->autodma = 0;
        hwif->tuneproc = &ali15x3_tune_drive;
        hwif->speedproc = &ali15x3_tune_chipset;
+       hwif->udma_filter = &ali_udma_filter;
 
        /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
        hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0;
@@ -783,8 +741,17 @@ static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
 
        hwif->atapi_dma = 1;
 
-       if (m5229_revision > 0x20)
-               hwif->ultra_mask = 0x7f;
+       if (m5229_revision <= 0x20)
+               hwif->ultra_mask = 0x00; /* no udma */
+       else if (m5229_revision < 0xC2)
+               hwif->ultra_mask = 0x07; /* udma0-2 */
+       else if (m5229_revision == 0xC2 || m5229_revision == 0xC3)
+               hwif->ultra_mask = 0x1f; /* udma0-4 */
+       else if (m5229_revision == 0xC4)
+               hwif->ultra_mask = 0x3f; /* udma0-5 */
+       else
+               hwif->ultra_mask = 0x7f; /* udma0-6 */
+
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
index 7989bdd842a2312ae0ca21640c1bbfcf029338fb..becb1a5648b0858643a8da7846cec022b82fd522 100644 (file)
@@ -92,7 +92,7 @@ static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3
  * AMD /proc entry.
  */
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
@@ -402,14 +402,14 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
  * Register /proc/ide/amd74xx entry
  */
 
-#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
         if (!amd74xx_proc) {
                 amd_base = pci_resource_start(dev, 4);
                 bmide_dev = dev;
                ide_pci_create_host_proc("amd74xx", amd74xx_get_info);
                 amd74xx_proc = 1;
         }
-#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
+#endif /* DISPLAY_AMD_TIMINGS && CONFIG_IDE_PROC_FS */
 
        return dev->irq;
 }
index 2d48af32e3f455dc7a67eed2e84418e4b6ae1234..0e52ad722a72ab23bf7e399a210fa87052f8dddb 100644 (file)
@@ -48,22 +48,6 @@ static int save_mdma_mode[4];
 
 static DEFINE_SPINLOCK(atiixp_lock);
 
-/**
- *     atiixp_ratemask         -       compute rate mask for ATIIXP IDE
- *     @drive: IDE drive to compute for
- *
- *     Returns the available modes for the ATIIXP IDE controller.
- */
-
-static u8 atiixp_ratemask(ide_drive_t *drive)
-{
-       u8 mode = 3;
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 /**
  *     atiixp_dma_2_pio                -       return the PIO mode matching DMA
  *     @xfer_rate: transfer speed
@@ -189,7 +173,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
        u16 tmp16;
        u8 speed, pio;
 
-       speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed);
+       speed = ide_rate_filter(drive, xferspeed);
 
        spin_lock_irqsave(&atiixp_lock, flags);
 
@@ -222,26 +206,6 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
        return ide_config_drive_speed(drive, speed);
 }
 
-/**
- *     atiixp_config_drive_for_dma     -       configure drive for DMA
- *     @drive: IDE drive to configure
- *
- *     Set up a ATIIXP interface channel for the best available speed.
- *     We prefer UDMA if it is available and then MWDMA. If DMA is
- *     not available we switch to PIO and return 0.
- */
-
-static int atiixp_config_drive_for_dma(ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       (void) atiixp_speedproc(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 /**
  *     atiixp_dma_check        -       set up an IDE device
  *     @drive: IDE drive to configure
@@ -256,7 +220,7 @@ static int atiixp_dma_check(ide_drive_t *drive)
 
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && atiixp_config_drive_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive)) {
index 77f51ab6d439ce767a846b9b525fb7c2680b7835..61ea96b5555c1636f6ffc22fad657fe40224e8d3 100644 (file)
@@ -74,7 +74,7 @@
 #define UDIDETCR1      0x7B
 #define DTPR1          0x7C
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -165,7 +165,7 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
        return p-buffer;        /* => must be less than 4k! */
 }
 
-#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 static u8 quantize_timing(int timing, int quant)
 {
@@ -292,55 +292,6 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
        (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static u8 cmd64x_ratemask (ide_drive_t *drive)
-{
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 mode = 0;
-
-       switch(dev->device) {
-               case PCI_DEVICE_ID_CMD_649:
-                       mode = 3;
-                       break;
-               case PCI_DEVICE_ID_CMD_648:
-                       mode = 2;
-                       break;
-               case PCI_DEVICE_ID_CMD_643:
-                       return 0;
-
-               case PCI_DEVICE_ID_CMD_646:
-               {
-                       unsigned int class_rev  = 0;
-                       pci_read_config_dword(dev,
-                               PCI_CLASS_REVISION, &class_rev);
-                       class_rev &= 0xff;
-               /*
-                * UltraDMA only supported on PCI646U and PCI646U2, which
-                * correspond to revisions 0x03, 0x05 and 0x07 respectively.
-                * Actually, although the CMD tech support people won't
-                * tell me the details, the 0x03 revision cannot support
-                * UDMA correctly without hardware modifications, and even
-                * then it only works with Quantum disks due to some
-                * hold time assumptions in the 646U part which are fixed
-                * in the 646U2.
-                *
-                * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-                */
-                       switch(class_rev) {
-                               case 0x07:
-                               case 0x05:
-                                       return 1;
-                               case 0x03:
-                               case 0x01:
-                               default:
-                                       return 0;
-                       }
-               }
-       }
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
@@ -348,7 +299,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
        u8 unit                 = drive->dn & 0x01;
        u8 regU = 0, pciU       = hwif->channel ? UDIDETCR1 : UDIDETCR0;
 
-       speed = ide_rate_filter(cmd64x_ratemask(drive), speed);
+       speed = ide_rate_filter(drive, speed);
 
        if (speed >= XFER_SW_DMA_0) {
                (void) pci_read_config_byte(dev, pciU, &regU);
@@ -403,7 +354,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed        = ide_dma_speed(drive, cmd64x_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!speed)
                return 0;
@@ -597,7 +548,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
        (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
 #endif /* CONFIG_PPC */
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 
        cmd_devs[n_cmd_devs++] = dev;
 
@@ -605,7 +556,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
                cmd64x_proc = 1;
                ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
        }
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
 
        return 0;
 }
@@ -644,15 +595,24 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
 
        hwif->atapi_dma = 1;
 
-       hwif->ultra_mask = 0x3f;
-       hwif->mwdma_mask = 0x07;
+       hwif->ultra_mask = hwif->cds->udma_mask;
+
+       /*
+        * UltraDMA only supported on PCI646U and PCI646U2, which
+        * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+        * Actually, although the CMD tech support people won't
+        * tell me the details, the 0x03 revision cannot support
+        * UDMA correctly without hardware modifications, and even
+        * then it only works with Quantum disks due to some
+        * hold time assumptions in the 646U part which are fixed
+        * in the 646U2.
+        *
+        * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+        */
+       if (dev->device == PCI_DEVICE_ID_CMD_646 && class_rev < 5)
+               hwif->ultra_mask = 0x00;
 
-       if (dev->device == PCI_DEVICE_ID_CMD_643)
-               hwif->ultra_mask = 0x80;
-       if (dev->device == PCI_DEVICE_ID_CMD_646)
-               hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
-       if (dev->device == PCI_DEVICE_ID_CMD_648)
-               hwif->ultra_mask = 0x1f;
+       hwif->mwdma_mask = 0x07;
 
        hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
        if (!(hwif->udma_four))
@@ -716,6 +676,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .udma_mask      = 0x00, /* no udma */
        },{     /* 1 */
                .name           = "CMD646",
                .init_setup     = init_setup_cmd646,
@@ -725,6 +686,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 2 */
                .name           = "CMD648",
                .init_setup     = init_setup_cmd64x,
@@ -734,6 +696,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "CMD649",
                .init_setup     = init_setup_cmd64x,
@@ -743,6 +706,7 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
                .bootable       = ON_BOARD,
+               .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
 
index 400859a839f7dcd9b1fb4c25b1796a98e87a12cb..3b88a3a561167c3986b8a0815c1b3161fec8ba7f 100644 (file)
@@ -213,6 +213,7 @@ static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
  
 static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
+       ide_hwif_t *hwif = NULL, *mate = NULL;
        ata_index_t index;
        ide_pci_device_t *d = &cyrix_chipsets[id->driver_data];
 
@@ -239,10 +240,21 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
 
        ide_pci_setup_ports(dev, d, 14, &index);
 
-       if((index.b.low & 0xf0) != 0xf0)
-               probe_hwif_init(&ide_hwifs[index.b.low]);
-       if((index.b.high & 0xf0) != 0xf0)
-               probe_hwif_init(&ide_hwifs[index.b.high]);
+       if ((index.b.low & 0xf0) != 0xf0)
+               hwif = &ide_hwifs[index.b.low];
+       if ((index.b.high & 0xf0) != 0xf0)
+               mate = &ide_hwifs[index.b.high];
+
+       if (hwif)
+               probe_hwif_init(hwif);
+       if (mate)
+               probe_hwif_init(mate);
+
+       if (hwif)
+               ide_proc_register_port(hwif);
+       if (mate)
+               ide_proc_register_port(mate);
+
        return 0;
 }
 
index 45f43efbf92c856b4aaabf967cbab9ee87d33c9f..41925c47ef05968d484107b34b7c22b1e53373c4 100644 (file)
@@ -127,20 +127,6 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
        }
 }
 
-static u8 cs5535_ratemask(ide_drive_t *drive)
-{
-       /* eighty93 will return 1 if it's 80core and capable of
-       exceeding udma2, 0 otherwise. we need ratemask to set
-       the max speed and if we can > udma2 then we return 2
-       which selects speed_max as udma4 which is the 5535's max
-       speed, and 1 selects udma2 which is the max for 40c */
-       if (!eighty_ninty_three(drive))
-               return 1;
-
-       return 2;
-}
-
-
 /****
  *     cs5535_set_drive         -     Configure the drive to the new speed
  *     @drive: Drive to set up
@@ -151,7 +137,7 @@ static u8 cs5535_ratemask(ide_drive_t *drive)
  */
 static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
 {
-       speed = ide_rate_filter(cs5535_ratemask(drive), speed);
+       speed = ide_rate_filter(drive, speed);
        ide_config_drive_speed(drive, speed);
        cs5535_set_speed(drive, speed);
 
@@ -178,28 +164,13 @@ static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
        cs5535_set_speed(drive, xferspeed);
 }
 
-static int cs5535_config_drive_for_dma(ide_drive_t *drive)
-{
-       u8 speed;
-
-       speed = ide_dma_speed(drive, cs5535_ratemask(drive));
-
-       /* If no DMA speed was available then let dma_check hit pio */
-       if (!speed) {
-               return 0;
-       }
-
-       cs5535_set_drive(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int cs5535_dma_check(ide_drive_t *drive)
 {
        u8 speed;
 
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && cs5535_config_drive_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive)) {
index dd7ec37fdeab2d14ea76e855f7dd57e0961c84b1..46f4a888c03711c341eddaeea2be7933e3bcbf57 100644 (file)
@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
        hw.irq = dev->irq;
        hw.chipset = ide_pci;           /* this enables IRQ sharing */
 
-       rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+       rc = ide_register_hw_with_fixup(&hw, 0, &hwif, ide_undecoded_slave);
        if (rc < 0) {
                printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
                pci_disable_device(dev);
index 924eaa3a5708890e592dce1d7d130b769c37f25b..2c24c3de8846f0aaee3dafee2d6c3d0730077ac0 100644 (file)
 
 #define HPT343_DEBUG_DRIVE_INFO                0
 
-static u8 hpt34x_ratemask (ide_drive_t *drive)
-{
-       return 1;
-}
-
 static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 speed        = ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+       u8 speed = ide_rate_filter(drive, xferspeed);
        u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
        u8                      hi_speed, lo_speed;
 
@@ -89,29 +84,11 @@ static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
        (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
 }
 
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
-
-       if (!(speed))
-               return 0;
-
-       (void) hpt34x_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
 {
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
 #ifndef CONFIG_HPT34X_AUTODMA
                return -1;
 #else
index cf9d344d19f828f73d92691e4740b35dde9b1ec4..fcbc5605b38ef28210d11bdf7f33051bad56312d 100644 (file)
@@ -514,43 +514,31 @@ static int check_in_drive_list(ide_drive_t *drive, const char **list)
        return 0;
 }
 
-static u8 hpt3xx_ratemask(ide_drive_t *drive)
-{
-       struct hpt_info *info   = pci_get_drvdata(HWIF(drive)->pci_dev);
-       u8 mode                 = info->max_mode;
-
-       if (!eighty_ninty_three(drive) && mode)
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 /*
  *     Note for the future; the SATA hpt37x we must set
  *     either PIO or UDMA modes 0,4,5
  */
-static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
+
+static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 {
        struct hpt_info *info   = pci_get_drvdata(HWIF(drive)->pci_dev);
        u8 chip_type            = info->chip_type;
-       u8 mode                 = hpt3xx_ratemask(drive);
-
-       if (drive->media != ide_disk)
-               return min(speed, (u8)XFER_PIO_4);
+       u8 mode                 = info->max_mode;
+       u8 mask;
 
        switch (mode) {
                case 0x04:
-                       speed = min_t(u8, speed, XFER_UDMA_6);
+                       mask = 0x7f;
                        break;
                case 0x03:
-                       speed = min_t(u8, speed, XFER_UDMA_5);
+                       mask = 0x3f;
                        if (chip_type >= HPT374)
                                break;
                        if (!check_in_drive_list(drive, bad_ata100_5))
                                goto check_bad_ata33;
                        /* fall thru */
                case 0x02:
-                       speed = min_t(u8, speed, XFER_UDMA_4);
+                       mask = 0x1f;
 
                        /*
                         * CHECK ME, Does this need to be changed to HPT374 ??
@@ -561,13 +549,13 @@ static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
                            !check_in_drive_list(drive, bad_ata66_4))
                                goto check_bad_ata33;
 
-                       speed = min_t(u8, speed, XFER_UDMA_3);
+                       mask = 0x0f;
                        if (HPT366_ALLOW_ATA66_3 &&
                            !check_in_drive_list(drive, bad_ata66_3))
                                goto check_bad_ata33;
                        /* fall thru */
                case 0x01:
-                       speed = min_t(u8, speed, XFER_UDMA_2);
+                       mask = 0x07;
 
                check_bad_ata33:
                        if (chip_type >= HPT370A)
@@ -577,10 +565,10 @@ static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
                        /* fall thru */
                case 0x00:
                default:
-                       speed = min_t(u8, speed, XFER_MW_DMA_2);
+                       mask = 0x00;
                        break;
        }
-       return speed;
+       return mask;
 }
 
 static u32 get_speed_setting(u8 speed, struct hpt_info *info)
@@ -608,12 +596,19 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev  *dev    = hwif->pci_dev;
        struct hpt_info *info   = pci_get_drvdata(dev);
-       u8  speed               = hpt3xx_ratefilter(drive, xferspeed);
+       u8  speed               = ide_rate_filter(drive, xferspeed);
        u8  itr_addr            = drive->dn ? 0x44 : 0x40;
-       u32 itr_mask            = speed < XFER_MW_DMA_0 ? 0x30070000 :
-                                (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
-       u32 new_itr             = get_speed_setting(speed, info);
        u32 old_itr             = 0;
+       u32 itr_mask, new_itr;
+
+       /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
+       if (drive->media != ide_disk)
+               speed = min_t(u8, speed, XFER_PIO_4);
+
+       itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+                 (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+
+       new_itr = get_speed_setting(speed, info);
 
        /*
         * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
@@ -633,12 +628,19 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev  *dev    = hwif->pci_dev;
        struct hpt_info *info   = pci_get_drvdata(dev);
-       u8  speed               = hpt3xx_ratefilter(drive, xferspeed);
+       u8  speed               = ide_rate_filter(drive, xferspeed);
        u8  itr_addr            = 0x40 + (drive->dn * 4);
-       u32 itr_mask            = speed < XFER_MW_DMA_0 ? 0x303c0000 :
-                                (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
-       u32 new_itr             = get_speed_setting(speed, info);
        u32 old_itr             = 0;
+       u32 itr_mask, new_itr;
+
+       /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
+       if (drive->media != ide_disk)
+               speed = min_t(u8, speed, XFER_PIO_4);
+
+       itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+                 (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+
+       new_itr = get_speed_setting(speed, info);
 
        pci_read_config_dword(dev, itr_addr, &old_itr);
        new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
@@ -667,24 +669,6 @@ static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
        (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- */
-static int config_chipset_for_dma(ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       (void) hpt3xx_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int hpt3xx_quirkproc(ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
@@ -739,7 +723,7 @@ static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
 {
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
@@ -1271,6 +1255,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        hwif->intrproc                  = &hpt3xx_intrproc;
        hwif->maskproc                  = &hpt3xx_maskproc;
        hwif->busproc                   = &hpt3xx_busproc;
+       hwif->udma_filter               = &hpt3xx_udma_filter;
 
        /*
         * HPT3xxN chips have some complications:
index 424f00bb160d6210047805002b101ca7ba3bac21..c04a02687b95ec91c3687761c6f3e4e318b380c5 100644 (file)
 
 #include <asm/io.h>
 
-/*
- *     it8213_ratemask -       Compute available modes
- *     @drive: IDE drive
- *
- *     Compute the available speeds for the devices on the interface. This
- *     is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 it8213_ratemask (ide_drive_t *drive)
-{
-       u8 mode = 4;
-       if (!eighty_ninty_three(drive))
-               mode = min_t(u8, mode, 1);
-       return mode;
-}
-
 /**
  *     it8213_dma_2_pio                -       return the PIO mode matching DMA
  *     @xfer_rate: transfer speed
@@ -145,7 +129,7 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u8 maslave              = 0x40;
-       u8 speed                = ide_rate_filter(it8213_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        int a_speed             = 3 << (drive->dn * 4);
        int u_flag              = 1 << drive->dn;
        int v_flag              = 0x01 << drive->dn;
@@ -213,25 +197,6 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return ide_config_drive_speed(drive, speed);
 }
 
-/*
- *     config_chipset_for_dma  -       configure for DMA
- *     @drive: drive to configure
- *
- *     Called by the IDE layer when it wants the timings set up.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       it8213_tune_chipset(drive, speed);
-
-       return ide_dma_enable(drive);
-}
-
 /**
  *     it8213_configure_drive_for_dma  -       set up for DMA transfers
  *     @drive: drive we are going to set up
@@ -246,7 +211,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive)
 {
        u8 pio;
 
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
index 4e1254813ee0c215a2bbf44ff8a922b6d3c985fd..442f658c6ae7bc0bc757aa597aee5e82e3599345 100644 (file)
@@ -228,22 +228,6 @@ static void it821x_clock_strategy(ide_drive_t *drive)
        }
 }
 
-/**
- *     it821x_ratemask -       Compute available modes
- *     @drive: IDE drive
- *
- *     Compute the available speeds for the devices on the interface. This
- *     is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 it821x_ratemask (ide_drive_t *drive)
-{
-       u8 mode = 4;
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 /**
  *     it821x_tunepio  -       tune a drive
  *     @drive: drive to tune
@@ -438,7 +422,7 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
 
        ide_hwif_t *hwif        = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       u8 speed                = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
 
        switch (speed) {
        case XFER_PIO_4:
@@ -488,7 +472,7 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed        = ide_dma_speed(drive, it821x_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (speed == 0)
                return 0;
index be4fc96c29e0ded22f1629b9cfd046031e95e9d3..76ed251472298682a516c0b6699dc0c07a7618d4 100644 (file)
@@ -21,22 +21,6 @@ typedef enum {
        PORT_SATA = 2,
 } port_type;
 
-/**
- *     jmicron_ratemask        -       Compute available modes
- *     @drive: IDE drive
- *
- *     Compute the available speeds for the devices on the interface. This
- *     is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 jmicron_ratemask(ide_drive_t *drive)
-{
-       u8 mode = 4;
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 /**
  *     ata66_jmicron           -       Cable check
  *     @hwif: IDE port
@@ -129,31 +113,11 @@ static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
 
 static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
 {
-
-       u8 speed                = ide_rate_filter(jmicron_ratemask(drive), xferspeed);
+       u8 speed = ide_rate_filter(drive, xferspeed);
 
        return ide_config_drive_speed(drive, speed);
 }
 
-/**
- *     config_chipset_for_dma  -       configure for DMA
- *     @drive: drive to configure
- *
- *     As the JMicron snoops for timings all we actually need to do is
- *     make sure we don't set an invalid mode.
- */
-
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed        = ide_dma_speed(drive, jmicron_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       jmicron_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 /**
  *     jmicron_configure_drive_for_dma -       set up for DMA transfers
  *     @drive: drive we are going to set up
@@ -164,7 +128,7 @@ static int config_chipset_for_dma (ide_drive_t *drive)
 
 static int jmicron_config_drive_for_dma (ide_drive_t *drive)
 {
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        config_jmicron_chipset_for_pio(drive, 1);
index 2cdd629c653db9f2a61438d02b3e49d68e93ac8f..65b1e124edf773731cd21250b03a3780d8674bfb 100644 (file)
@@ -37,8 +37,6 @@
 #include <asm/pci-bridge.h>
 #endif
 
-#define PDC202_DEBUG_CABLE     0
-
 #undef DEBUG
 
 #ifdef DEBUG
@@ -82,16 +80,6 @@ static u8 max_dma_rate(struct pci_dev *pdev)
        return mode;
 }
 
-static u8 pdcnew_ratemask(ide_drive_t *drive)
-{
-       u8 mode = max_dma_rate(HWIF(drive)->pci_dev);
-
-       if (!eighty_ninty_three(drive))
-               mode = min_t(u8, mode, 1);
-
-       return  mode;
-}
-
 /**
  * get_indexed_reg - Get indexed register
  * @hwif: for the port address
@@ -164,7 +152,7 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
        u8 adj                  = (drive->dn & 1) ? 0x08 : 0x00;
        int                     err;
 
-       speed = ide_rate_filter(pdcnew_ratemask(drive), speed);
+       speed = ide_rate_filter(drive, speed);
 
        /*
         * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
@@ -244,17 +232,8 @@ static int config_chipset_for_dma(ide_drive_t *drive)
 {
        struct hd_driveid *id   = drive->id;
        ide_hwif_t *hwif        = HWIF(drive);
-       u8 ultra_66             = (id->dma_ultra & 0x0078) ? 1 : 0;
-       u8 cable                = pdcnew_cable_detect(hwif);
        u8 speed;
 
-       if (ultra_66 && cable) {
-               printk(KERN_WARNING "Warning: %s channel "
-                      "requires an 80-pin cable for operation.\n",
-                      hwif->channel ? "Secondary" : "Primary");
-               printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
-       }
-
        if (id->capability & 4) {
                /*
                 * Set IORDY_EN & PREFETCH_EN (this seems to have
@@ -267,7 +246,7 @@ static int config_chipset_for_dma(ide_drive_t *drive)
                set_indexed_reg(hwif, 0x13 + adj, tmp | 0x03);
        }
 
-       speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+       speed = ide_max_dma_mode(drive);
 
        if (!speed)
                return 0;
@@ -543,7 +522,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
        hwif->atapi_dma  = 1;
-       hwif->ultra_mask = 0x7f;
+
+       hwif->ultra_mask = hwif->cds->udma_mask;
        hwif->mwdma_mask = 0x07;
 
        hwif->err_stops_fifo = 1;
@@ -556,11 +536,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        if (!noautodma)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-
-#if PDC202_DEBUG_CABLE
-       printk(KERN_DEBUG "%s: %s-pin cable\n",
-               hwif->name, hwif->udma_four ? "80" : "40");
-#endif /* PDC202_DEBUG_CABLE */
 }
 
 static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d)
@@ -619,6 +594,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 1 */
                .name           = "PDC20269",
                .init_setup     = init_setup_pdcnew,
@@ -627,6 +603,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 2 */
                .name           = "PDC20270",
                .init_setup     = init_setup_pdc20270,
@@ -635,6 +612,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 3 */
                .name           = "PDC20271",
                .init_setup     = init_setup_pdcnew,
@@ -643,6 +621,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 4 */
                .name           = "PDC20275",
                .init_setup     = init_setup_pdcnew,
@@ -651,6 +630,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 5 */
                .name           = "PDC20276",
                .init_setup     = init_setup_pdc20276,
@@ -659,6 +639,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x7f, /* udma0-6*/
        },{     /* 6 */
                .name           = "PDC20277",
                .init_setup     = init_setup_pdcnew,
@@ -667,6 +648,7 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
                .channels       = 2,
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
+               .udma_mask      = 0x7f, /* udma0-6*/
        }
 };
 
index a7a639fe1eaff2b4540f52160afc8163f1eef35f..7146fe3f6ba7bdffd0bc9bafaea0afd2e8b8ab64 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define PDC202_DEBUG_CABLE             0
 #define PDC202XX_DEBUG_DRIVE_INFO      0
 
 static const char *pdc_quirk_drives[] = {
@@ -101,35 +100,12 @@ static const char *pdc_quirk_drives[] = {
 #define        MC1             0x02    /* DMA"C" timing */
 #define        MC0             0x01    /* DMA"C" timing */
 
-static u8 pdc202xx_ratemask (ide_drive_t *drive)
-{
-       u8 mode;
-
-       switch(HWIF(drive)->pci_dev->device) {
-               case PCI_DEVICE_ID_PROMISE_20267:
-               case PCI_DEVICE_ID_PROMISE_20265:
-                       mode = 3;
-                       break;
-               case PCI_DEVICE_ID_PROMISE_20263:
-               case PCI_DEVICE_ID_PROMISE_20262:
-                       mode = 2;
-                       break;
-               case PCI_DEVICE_ID_PROMISE_20246:
-                       return 1;
-               default:
-                       return 0;
-       }
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u8 drive_pci            = 0x60 + (drive->dn << 2);
-       u8 speed        = ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
 
        u32                     drive_conf;
        u8                      AP, BP, CP, DP;
@@ -261,20 +237,7 @@ static int config_chipset_for_dma (ide_drive_t *drive)
        u32 drive_conf          = 0;
        u8 drive_pci            = 0x60 + (drive->dn << 2);
        u8 test1 = 0, test2 = 0, speed = -1;
-       u8 AP = 0, cable = 0;
-
-       u8 ultra_66             = ((id->dma_ultra & 0x0010) ||
-                                  (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-       if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
-               cable = pdc202xx_old_cable_detect(hwif);
-       else
-               ultra_66 = 0;
-
-       if (ultra_66 && cable) {
-               printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
-               printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
-       }
+       u8 AP = 0;
 
        if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
                pdc_old_disable_66MHz_clock(drive->hwif);
@@ -308,7 +271,7 @@ chipset_is_set:
        if (drive->media == ide_disk)   /* PREFETCH_EN */
                pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
-       speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+       speed = ide_max_dma_mode(drive);
 
        if (!(speed)) {
                /* restore original pci-config space */
@@ -478,7 +441,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
 
        hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
-       hwif->ultra_mask = 0x3f;
+       hwif->ultra_mask = hwif->cds->udma_mask;
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
        hwif->atapi_dma = 1;
@@ -500,10 +463,6 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
        if (!noautodma)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-#if PDC202_DEBUG_CABLE
-       printk(KERN_DEBUG "%s: %s-pin cable\n",
-               hwif->name, hwif->udma_four ? "80" : "40");
-#endif /* PDC202_DEBUG_CABLE */        
 }
 
 static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
@@ -587,6 +546,7 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 16,
+               .udma_mask      = 0x07, /* udma0-2 */
        },{     /* 1 */
                .name           = "PDC20262",
                .init_setup     = init_setup_pdc202ata4,
@@ -597,6 +557,7 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 2 */
                .name           = "PDC20263",
                .init_setup     = init_setup_pdc202ata4,
@@ -607,6 +568,7 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .udma_mask      = 0x1f, /* udma0-4 */
        },{     /* 3 */
                .name           = "PDC20265",
                .init_setup     = init_setup_pdc20265,
@@ -617,6 +579,7 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .udma_mask      = 0x3f, /* udma0-5 */
        },{     /* 4 */
                .name           = "PDC20267",
                .init_setup     = init_setup_pdc202xx,
@@ -627,6 +590,7 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
                .autodma        = AUTODMA,
                .bootable       = OFF_BOARD,
                .extra          = 48,
+               .udma_mask      = 0x3f, /* udma0-5 */
        }
 };
 
index 061d300ab8be7dfc3ddada57c904e40aedd54bbc..8b219dd630241f4285512e61a9b417872c5147e8 100644 (file)
 
 static int no_piix_dma;
 
-/**
- *     piix_ratemask           -       compute rate mask for PIIX IDE
- *     @drive: IDE drive to compute for
- *
- *     Returns the available modes for the PIIX IDE controller.
- */
-static u8 piix_ratemask (ide_drive_t *drive)
-{
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 mode;
-
-       switch(dev->device) {
-               case PCI_DEVICE_ID_INTEL_82801EB_1:
-                       mode = 3;
-                       break;
-               /* UDMA 100 capable */
-               case PCI_DEVICE_ID_INTEL_82801BA_8:
-               case PCI_DEVICE_ID_INTEL_82801BA_9:
-               case PCI_DEVICE_ID_INTEL_82801CA_10:
-               case PCI_DEVICE_ID_INTEL_82801CA_11:
-               case PCI_DEVICE_ID_INTEL_82801E_11:
-               case PCI_DEVICE_ID_INTEL_82801DB_1:
-               case PCI_DEVICE_ID_INTEL_82801DB_10:
-               case PCI_DEVICE_ID_INTEL_82801DB_11:
-               case PCI_DEVICE_ID_INTEL_82801EB_11:
-               case PCI_DEVICE_ID_INTEL_ESB_2:
-               case PCI_DEVICE_ID_INTEL_ICH6_19:
-               case PCI_DEVICE_ID_INTEL_ICH7_21:
-               case PCI_DEVICE_ID_INTEL_ESB2_18:
-               case PCI_DEVICE_ID_INTEL_ICH8_6:
-                       mode = 3;
-                       break;
-               /* UDMA 66 capable */
-               case PCI_DEVICE_ID_INTEL_82801AA_1:
-               case PCI_DEVICE_ID_INTEL_82372FB_1:
-                       mode = 2;
-                       break;
-               /* UDMA 33 capable */
-               case PCI_DEVICE_ID_INTEL_82371AB:
-               case PCI_DEVICE_ID_INTEL_82443MX_1:
-               case PCI_DEVICE_ID_INTEL_82451NX:
-               case PCI_DEVICE_ID_INTEL_82801AB_1:
-                       return 1;
-               /* Non UDMA capable (MWDMA2) */
-               case PCI_DEVICE_ID_INTEL_82371SB_1:
-               case PCI_DEVICE_ID_INTEL_82371FB_1:
-               case PCI_DEVICE_ID_INTEL_82371FB_0:
-               case PCI_DEVICE_ID_INTEL_82371MX:
-               default:
-                       return 0;
-       }
-       
-       /*
-        *      If we are UDMA66 capable fall back to UDMA33 
-        *      if the drive cannot see an 80pin cable.
-        */
-       if (!eighty_ninty_three(drive))
-               mode = min_t(u8, mode, 1);
-       return mode;
-}
-
 /**
  *     piix_dma_2_pio          -       return the PIO mode matching DMA
  *     @xfer_rate: transfer speed
@@ -301,7 +239,7 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u8 maslave              = hwif->channel ? 0x42 : 0x40;
-       u8 speed                = ide_rate_filter(piix_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        int a_speed             = 3 << (drive->dn * 4);
        int u_flag              = 1 << drive->dn;
        int v_flag              = 0x01 << drive->dn;
@@ -365,30 +303,6 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return ide_config_drive_speed(drive, speed);
 }
 
-/**
- *     piix_config_drive_for_dma       -       configure drive for DMA
- *     @drive: IDE drive to configure
- *
- *     Set up a PIIX interface channel for the best available speed.
- *     We prefer UDMA if it is available and then MWDMA.  If DMA is
- *     not available we switch to PIO and return 0.
- */
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
-
-       /*
-        * If no DMA speed was available or the chipset has DMA bugs
-        * then disable DMA and use PIO
-        */
-       if (!speed)
-               return 0;
-
-       (void) piix_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 /**
  *     piix_config_drive_xfer_rate     -       set up an IDE device
  *     @drive: IDE drive to configure
@@ -401,7 +315,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive)
 {
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && piix_config_drive_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
@@ -524,26 +438,14 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
                hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
 
        hwif->atapi_dma = 1;
-       hwif->ultra_mask = 0x3f;
+
+       hwif->ultra_mask = hwif->cds->udma_mask;
        hwif->mwdma_mask = 0x06;
        hwif->swdma_mask = 0x04;
 
-       switch(hwif->pci_dev->device) {
-               case PCI_DEVICE_ID_INTEL_82371FB_0:
-               case PCI_DEVICE_ID_INTEL_82371FB_1:
-               case PCI_DEVICE_ID_INTEL_82371SB_1:
-                       hwif->ultra_mask = 0x80;
-                       break;
-               case PCI_DEVICE_ID_INTEL_82371AB:
-               case PCI_DEVICE_ID_INTEL_82443MX_1:
-               case PCI_DEVICE_ID_INTEL_82451NX:
-               case PCI_DEVICE_ID_INTEL_82801AB_1:
-                       hwif->ultra_mask = 0x07;
-                       break;
-               default:
-                       if (!hwif->udma_four)
-                               hwif->udma_four = piix_cable_detect(hwif);
-                       break;
+       if (hwif->ultra_mask & 0x78) {
+               if (!hwif->udma_four)
+                       hwif->udma_four = piix_cable_detect(hwif);
        }
 
        if (no_piix_dma)
@@ -557,7 +459,7 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
        hwif->drives[0].autodma = hwif->autodma;
 }
 
-#define DECLARE_PIIX_DEV(name_str) \
+#define DECLARE_PIIX_DEV(name_str, udma) \
        {                                               \
                .name           = name_str,             \
                .init_chipset   = init_chipset_piix,    \
@@ -566,11 +468,12 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
                .autodma        = AUTODMA,              \
                .enablebits     = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
                .bootable       = ON_BOARD,             \
+               .udma_mask      = udma,                 \
        }
 
 static ide_pci_device_t piix_pci_info[] __devinitdata = {
-       /*  0 */ DECLARE_PIIX_DEV("PIIXa"),
-       /*  1 */ DECLARE_PIIX_DEV("PIIXb"),
+       /*  0 */ DECLARE_PIIX_DEV("PIIXa", 0x00),       /* no udma */
+       /*  1 */ DECLARE_PIIX_DEV("PIIXb", 0x00),       /* no udma */
 
        /*  2 */
        {       /*
@@ -587,28 +490,28 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
                .flags          = IDEPCI_FLAG_ISA_PORTS
        },
 
-       /*  3 */ DECLARE_PIIX_DEV("PIIX3"),
-       /*  4 */ DECLARE_PIIX_DEV("PIIX4"),
-       /*  5 */ DECLARE_PIIX_DEV("ICH0"),
-       /*  6 */ DECLARE_PIIX_DEV("PIIX4"),
-       /*  7 */ DECLARE_PIIX_DEV("ICH"),
-       /*  8 */ DECLARE_PIIX_DEV("PIIX4"),
-       /*  9 */ DECLARE_PIIX_DEV("PIIX4"),
-       /* 10 */ DECLARE_PIIX_DEV("ICH2"),
-       /* 11 */ DECLARE_PIIX_DEV("ICH2M"),
-       /* 12 */ DECLARE_PIIX_DEV("ICH3M"),
-       /* 13 */ DECLARE_PIIX_DEV("ICH3"),
-       /* 14 */ DECLARE_PIIX_DEV("ICH4"),
-       /* 15 */ DECLARE_PIIX_DEV("ICH5"),
-       /* 16 */ DECLARE_PIIX_DEV("C-ICH"),
-       /* 17 */ DECLARE_PIIX_DEV("ICH4"),
-       /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA"),
-       /* 19 */ DECLARE_PIIX_DEV("ICH5"),
-       /* 20 */ DECLARE_PIIX_DEV("ICH6"),
-       /* 21 */ DECLARE_PIIX_DEV("ICH7"),
-       /* 22 */ DECLARE_PIIX_DEV("ICH4"),
-       /* 23 */ DECLARE_PIIX_DEV("ESB2"),
-       /* 24 */ DECLARE_PIIX_DEV("ICH8M"),
+       /*  3 */ DECLARE_PIIX_DEV("PIIX3", 0x00),       /* no udma */
+       /*  4 */ DECLARE_PIIX_DEV("PIIX4", 0x07),       /* udma0-2 */
+       /*  5 */ DECLARE_PIIX_DEV("ICH0",  0x07),       /* udma0-2 */
+       /*  6 */ DECLARE_PIIX_DEV("PIIX4", 0x07),       /* udma0-2 */
+       /*  7 */ DECLARE_PIIX_DEV("ICH",   0x1f),       /* udma0-4 */
+       /*  8 */ DECLARE_PIIX_DEV("PIIX4", 0x1f),       /* udma0-4 */
+       /*  9 */ DECLARE_PIIX_DEV("PIIX4", 0x07),       /* udma0-2 */
+       /* 10 */ DECLARE_PIIX_DEV("ICH2",  0x3f),       /* udma0-5 */
+       /* 11 */ DECLARE_PIIX_DEV("ICH2M", 0x3f),       /* udma0-5 */
+       /* 12 */ DECLARE_PIIX_DEV("ICH3M", 0x3f),       /* udma0-5 */
+       /* 13 */ DECLARE_PIIX_DEV("ICH3",  0x3f),       /* udma0-5 */
+       /* 14 */ DECLARE_PIIX_DEV("ICH4",  0x3f),       /* udma0-5 */
+       /* 15 */ DECLARE_PIIX_DEV("ICH5",  0x3f),       /* udma0-5 */
+       /* 16 */ DECLARE_PIIX_DEV("C-ICH", 0x3f),       /* udma0-5 */
+       /* 17 */ DECLARE_PIIX_DEV("ICH4",  0x3f),       /* udma0-5 */
+       /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA", 0x3f),   /* udma0-5 */
+       /* 19 */ DECLARE_PIIX_DEV("ICH5",  0x3f),       /* udma0-5 */
+       /* 20 */ DECLARE_PIIX_DEV("ICH6",  0x3f),       /* udma0-5 */
+       /* 21 */ DECLARE_PIIX_DEV("ICH7",  0x3f),       /* udma0-5 */
+       /* 22 */ DECLARE_PIIX_DEV("ICH4",  0x3f),       /* udma0-5 */
+       /* 23 */ DECLARE_PIIX_DEV("ESB2",  0x3f),       /* udma0-5 */
+       /* 24 */ DECLARE_PIIX_DEV("ICH8M", 0x3f),       /* udma0-5 */
 };
 
 /**
index f84bf791f72e901605594a79cb0f61491a8faac4..cbf936325355d65fdc5c2357bdd9a1832e50346e 100644 (file)
@@ -189,23 +189,6 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
        }
 }
 
-/**
- *     scc_ratemask    -       Compute available modes
- *     @drive: IDE drive
- *
- *     Compute the available speeds for the devices on the interface.
- *     Enforce UDMA33 as a limit if there is no 80pin cable present.
- */
-
-static u8 scc_ratemask(ide_drive_t *drive)
-{
-       u8 mode = 4;
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
 /**
  *     scc_tuneproc    -       tune a drive PIO mode
  *     @drive: drive to tune
@@ -273,7 +256,7 @@ static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
 static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       u8 speed = ide_rate_filter(scc_ratemask(drive), xferspeed);
+       u8 speed = ide_rate_filter(drive, xferspeed);
        struct scc_ports *ports = ide_get_hwifdata(hwif);
        unsigned long ctl_base = ports->ctl;
        unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -347,7 +330,7 @@ static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
 
 static int scc_config_chipset_for_dma(ide_drive_t *drive)
 {
-       u8 speed = ide_dma_speed(drive, scc_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!speed)
                return 0;
index dbcd37a0c65217138100ad6beac91fab1cb8b306..2fa6d92d16cc40428d1c82b45e917e6fe83723bb 100644 (file)
@@ -65,16 +65,16 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list)
        return 0;
 }
 
-static u8 svwks_ratemask (ide_drive_t *drive)
+static u8 svwks_udma_filter(ide_drive_t *drive)
 {
        struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 mode = 0;
+       u8 mask = 0;
 
        if (!svwks_revision)
                pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
 
        if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
-               return 2;
+               return 0x1f;
        if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
                u32 reg = 0;
                if (isa_dev)
@@ -86,25 +86,31 @@ static u8 svwks_ratemask (ide_drive_t *drive)
                if(drive->media == ide_disk)
                        return 0;
                /* Check the OSB4 DMA33 enable bit */
-               return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+               return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0;
        } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
-               return 1;
+               return 0x07;
        } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
-               u8 btr = 0;
+               u8 btr = 0, mode;
                pci_read_config_byte(dev, 0x5A, &btr);
                mode = btr & 0x3;
-               if (!eighty_ninty_three(drive))
-                       mode = min(mode, (u8)1);
+
                /* If someone decides to do UDMA133 on CSB5 the same
                   issue will bite so be inclusive */
                if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
                        mode = 2;
+
+               switch(mode) {
+               case 2:  mask = 0x1f; break;
+               case 1:  mask = 0x07; break;
+               default: mask = 0x00; break;
+               }
        }
        if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
             (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
            (!(PCI_FUNC(dev->devfn) & 1)))
-               mode = 2;
-       return mode;
+               mask = 0x1f;
+
+       return mask;
 }
 
 static u8 svwks_csb_check (struct pci_dev *dev)
@@ -141,7 +147,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        if (xferspeed == 255)   /* PIO auto-tuning */
                speed = XFER_PIO_0 + pio;
        else
-               speed = ide_rate_filter(svwks_ratemask(drive), xferspeed);
+               speed = ide_rate_filter(drive, xferspeed);
 
        /* If we are about to put a disk into UDMA mode we screwed up.
           Our code assumes we never _ever_ do this on an OSB4 */
@@ -304,7 +310,7 @@ static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!(speed))
                speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
@@ -500,6 +506,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 
        hwif->tuneproc = &svwks_tune_drive;
        hwif->speedproc = &svwks_tune_chipset;
+       hwif->udma_filter = &svwks_udma_filter;
 
        hwif->atapi_dma = 1;
 
index fd09b295a69dd0b86c004ada223d03b289b18a14..d3185e29a38eef3c6763c68ef390e4b3aaa0ec69 100644 (file)
@@ -692,7 +692,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
                return -EIO;
 
        /* Create /proc/ide entries */
-       create_proc_ide_interfaces();
+       ide_proc_register_port(hwif);
 
        return 0;
 }
index c0188de3cc66509fc07a6ba886bb3599a6533ebb..d09e74c2996ed67fe54bfd0b2f471bbda83821c9 100644 (file)
@@ -122,45 +122,41 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
 }
 
 /**
- *     siimage_ratemask        -       Compute available modes
- *     @drive: IDE drive
+ *     sil_udma_filter         -       compute UDMA mask
+ *     @drive: IDE device
+ *
+ *     Compute the available UDMA speeds for the device on the interface.
  *
- *     Compute the available speeds for the devices on the interface.
  *     For the CMD680 this depends on the clocking mode (scsc), for the
- *     SI3312 SATA controller life is a bit simpler. Enforce UDMA33
- *     as a limit if there is no 80pin cable present.
+ *     SI3112 SATA controller life is a bit simpler.
  */
-static byte siimage_ratemask (ide_drive_t *drive)
+
+static u8 sil_udma_filter(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 mode = 0, scsc = 0;
+       ide_hwif_t *hwif = drive->hwif;
        unsigned long base = (unsigned long) hwif->hwif_data;
+       u8 mask = 0, scsc = 0;
 
        if (hwif->mmio)
                scsc = hwif->INB(base + 0x4A);
        else
                pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-       if(is_sata(hwif))
-       {
-               if(strstr(drive->id->model, "Maxtor"))
-                       return 3;
-               return 4;
+       if (is_sata(hwif)) {
+               mask = strstr(drive->id->model, "Maxtor") ? 0x3f : 0x7f;
+               goto out;
        }
-       
+
        if ((scsc & 0x30) == 0x10)      /* 133 */
-               mode = 4;
+               mask = 0x7f;
        else if ((scsc & 0x30) == 0x20) /* 2xPCI */
-               mode = 4;
+               mask = 0x7f;
        else if ((scsc & 0x30) == 0x00) /* 100 */
-               mode = 3;
+               mask = 0x3f;
        else    /* Disabled ? */
                BUG();
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
+out:
+       return mask;
 }
 
 /**
@@ -306,7 +302,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        u16 ultra = 0, multi    = 0;
        u8 mode = 0, unit       = drive->select.b.unit;
-       u8 speed                = ide_rate_filter(siimage_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        unsigned long base      = (unsigned long)hwif->hwif_data;
        u8 scsc = 0, addr_mask  = ((hwif->channel) ?
                                    ((hwif->mmio) ? 0xF4 : 0x84) :
@@ -389,7 +385,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
  
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed        = ide_dma_speed(drive, siimage_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
 
        if (!speed)
                return 0;
@@ -831,7 +827,7 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 
        /*
         *      Now set up the hw. We have to do this ourselves as
-        *      the MMIO layout isnt the same as the the standard port
+        *      the MMIO layout isnt the same as the standard port
         *      based I/O
         */
 
@@ -989,6 +985,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        hwif->tuneproc  = &siimage_tuneproc;
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
+       hwif->udma_filter = &sil_udma_filter;
 
        if(is_sata(hwif)) {
                static int first = 1;
index 2ba0669f36a17bd066546a56f7e49324162c91d8..2bde1b92784a723f89d2bfafb69d58d3a1d9d6f1 100644 (file)
@@ -191,7 +191,7 @@ static char* chipset_capability[] = {
        "ATA 133 (1st gen)", "ATA 133 (2nd gen)"
 };
 
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
@@ -426,17 +426,7 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
 
        return len > count ? count : len;
 }
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static u8 sis5513_ratemask (ide_drive_t *drive)
-{
-       u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
-       u8 mode = rates[chipset_family];
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /*
  * Configuration functions
@@ -563,7 +553,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        u8 drive_pci, reg, speed;
        u32 regdw;
 
-       speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+       speed = ide_rate_filter(drive, xferspeed);
 
        /* See config_art_rwp_pio for drive pci config registers */
        drive_pci = 0x40;
@@ -648,32 +638,13 @@ static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
        (void) config_chipset_for_pio(drive, pio);
 }
 
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed        = ide_dma_speed(drive, sis5513_ratemask(drive));
-
-#ifdef DEBUG
-       printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
-              drive->dn, drive->id->dma_ultra);
-#endif
-
-       if (!(speed))
-               return 0;
-
-       sis5513_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int sis5513_config_xfer_rate(ide_drive_t *drive)
 {
        config_art_rwp_pio(drive, 5);
 
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
@@ -826,7 +797,7 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
                                break;
                }
 
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
                if (!sis_proc) {
                        sis_proc = 1;
                        bmide_dev = dev;
@@ -858,6 +829,8 @@ static unsigned int __devinit ata66_sis5513 (ide_hwif_t *hwif)
 
 static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
 {
+       u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
+
        hwif->autodma = 0;
 
        if (!hwif->irq)
@@ -873,7 +846,8 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
        }
 
        hwif->atapi_dma = 1;
-       hwif->ultra_mask = 0x7f;
+
+       hwif->ultra_mask = udma_rates[chipset_family];
        hwif->mwdma_mask = 0x07;
        hwif->swdma_mask = 0x07;
 
index 852ccb36da1df943045b9b7775ec13ebfe235170..c40f291f91e04c62cce013882abcc67ef53ad05d 100644 (file)
 
 #include <asm/io.h>
 
-static u8 slc90e66_ratemask (ide_drive_t *drive)
-{
-       u8 mode = 2;
-
-       if (!eighty_ninty_three(drive))
-               mode = min_t(u8, mode, 1);
-       return mode;
-}
-
 static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
        switch(xfer_rate) {
                case XFER_UDMA_4:
@@ -122,7 +113,7 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
        u8 maslave              = hwif->channel ? 0x42 : 0x40;
-       u8 speed        = ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        int sitre = 0, a_speed  = 7 << (drive->dn * 4);
        int u_speed = 0, u_flag = 1 << drive->dn;
        u16                     reg4042, reg44, reg48, reg4a;
@@ -169,22 +160,11 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
        return ide_config_drive_speed(drive, speed);
 }
 
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       (void) slc90e66_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
 {
        drive->init_speed = 0;
 
-       if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
index 0b6d81d6ce488926dd01bcc87996559423d94bfd..cee619bb2eaf8a7713ccc7582acb48b22f4c10e8 100644 (file)
 #include <linux/pci.h>
 #include <linux/ide.h>
 
-static inline u8 tc86c001_ratemask(ide_drive_t *drive)
-{
-       return eighty_ninty_three(drive) ? 2 : 1;
-}
-
 static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        unsigned long scr_port  = hwif->config_data + (drive->dn ? 0x02 : 0x00);
        u16 mode, scr           = hwif->INW(scr_port);
 
-       speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+       speed = ide_rate_filter(drive, speed);
 
        switch (speed) {
                case XFER_UDMA_4:       mode = 0x00c0; break;
@@ -172,20 +167,9 @@ static int tc86c001_busproc(ide_drive_t *drive, int state)
        return 0;
 }
 
-static int config_chipset_for_dma(ide_drive_t *drive)
-{
-       u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
-
-       if (!speed)
-               return 0;
-
-       (void) tc86c001_tune_chipset(drive, speed);
-       return ide_dma_enable(drive);
-}
-
 static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
 {
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
index 5e06179c3469ed4a1fc7956d60fd95e389a630a2..35e8c612638f687509c42311c38d13973f92752c 100644 (file)
@@ -48,7 +48,7 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
        u16 timing = 0;
        u32 triflex_timings = 0;
        u8 unit = (drive->select.b.unit & 0x01);
-       u8 speed = ide_rate_filter(0, xferspeed);
+       u8 speed = ide_rate_filter(drive, xferspeed);
        
        pci_read_config_dword(dev, channel_offset, &triflex_timings);
        
@@ -100,20 +100,9 @@ static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
        (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
 }
 
-static int triflex_config_drive_for_dma(ide_drive_t *drive)
-{
-       int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
-
-       if (!speed)
-               return 0;
-
-       (void) triflex_tune_chipset(drive, speed);
-        return ide_dma_enable(drive);
-}
-
 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
 {
-       if (ide_use_dma(drive) && triflex_config_drive_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        triflex_tune_drive(drive, 255);
index a49ebe44babd1d5f0d97c92b3fdd963be0fc7f70..45fc36f0f219feaba9649978c69d697966e2ba57 100644 (file)
@@ -1276,6 +1276,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
        /* We probe the hwif now */
        probe_hwif_init(hwif);
 
+       ide_proc_register_port(hwif);
+
        return 0;
 }
 
index 118fb3205ca81cda6f4f260bedeea806883ffa4d..67035ba4bf5e2c3000bc2d1026352fad02cc8137 100644 (file)
@@ -702,6 +702,7 @@ out:
 
 int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
 {
+       ide_hwif_t *hwif = NULL, *mate = NULL;
        ata_index_t index_list;
        int ret;
 
@@ -710,11 +711,19 @@ int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
                goto out;
 
        if ((index_list.b.low & 0xf0) != 0xf0)
-               probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.low], d->fixup);
+               hwif = &ide_hwifs[index_list.b.low];
        if ((index_list.b.high & 0xf0) != 0xf0)
-               probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.high], d->fixup);
+               mate = &ide_hwifs[index_list.b.high];
 
-       create_proc_ide_interfaces();
+       if (hwif)
+               probe_hwif_init_with_fixup(hwif, d->fixup);
+       if (mate)
+               probe_hwif_init_with_fixup(mate, d->fixup);
+
+       if (hwif)
+               ide_proc_register_port(hwif);
+       if (mate)
+               ide_proc_register_port(mate);
 out:
        return ret;
 }
@@ -748,13 +757,22 @@ int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
                }
        }
 
-       create_proc_ide_interfaces();
+       for (i = 0; i < 2; i++) {
+               u8 idx[2] = { index_list[i].b.low, index_list[i].b.high };
+               int j;
+
+               for (j = 0; j < 2; j++) {
+                       if ((idx[j] & 0xf0) != 0xf0)
+                               ide_proc_register_port(ide_hwifs + idx[j]);
+               }
+       }
 out:
        return ret;
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
 
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 /*
  *     Module interfaces
  */
@@ -861,3 +879,4 @@ void __init ide_scan_pcibus (int scan_direction)
                __pci_register_driver(d, d->driver.owner, d->driver.mod_name);
        }
 }
+#endif
index 61d7809a5a262340864f5012835b7a75636493cd..8012b3b0ce75b83c23ae81f872fadb645167e3f1 100644 (file)
@@ -1,4 +1,7 @@
 menu "IEEE 1394 (FireWire) support"
+       depends on PCI || BROKEN
+
+source "drivers/firewire/Kconfig"
 
 config IEEE1394
        tristate "IEEE 1394 (FireWire) support"
index 6a1a0572275e96a8a72fbc87c730c9ce200f5544..835937e385292d648ba3d2b131e906d66bbb5f09 100644 (file)
@@ -1702,7 +1702,7 @@ static int nodemgr_host_thread(void *__hi)
                        generation = get_hpsb_generation(host);
 
                        /* If we get a reset before we are done waiting, then
-                        * start the the waiting over again */
+                        * start the waiting over again */
                        if (generation != g)
                                g = generation, i = 0;
                }
index 66b36de9fa6f531a3a9b329ac3177ad0cceead68..994decc7bcf2afd9c2c129fb6556af935ad8ce73 100644 (file)
@@ -1,4 +1,5 @@
 menu "InfiniBand support"
+       depends on HAS_IOMEM
 
 config INFINIBAND
        depends on PCI || BROKEN
@@ -29,6 +30,11 @@ config INFINIBAND_USER_ACCESS
          libibverbs, libibcm and a hardware driver library from
          <http://www.openib.org>.
 
+config INFINIBAND_USER_MEM
+       bool
+       depends on INFINIBAND_USER_ACCESS != n
+       default y
+
 config INFINIBAND_ADDR_TRANS
        bool
        depends on INFINIBAND && INET
@@ -40,6 +46,8 @@ source "drivers/infiniband/hw/ehca/Kconfig"
 source "drivers/infiniband/hw/amso1100/Kconfig"
 source "drivers/infiniband/hw/cxgb3/Kconfig"
 
+source "drivers/infiniband/hw/mlx4/Kconfig"
+
 source "drivers/infiniband/ulp/ipoib/Kconfig"
 
 source "drivers/infiniband/ulp/srp/Kconfig"
index da2066c4f22c03da192a390a5d5893226f6ff7f6..75f325e40b54516e44e65934885053fae2782993 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_INFINIBAND_IPATH)          += hw/ipath/
 obj-$(CONFIG_INFINIBAND_EHCA)          += hw/ehca/
 obj-$(CONFIG_INFINIBAND_AMSO1100)      += hw/amso1100/
 obj-$(CONFIG_INFINIBAND_CXGB3)         += hw/cxgb3/
+obj-$(CONFIG_MLX4_INFINIBAND)          += hw/mlx4/
 obj-$(CONFIG_INFINIBAND_IPOIB)         += ulp/ipoib/
 obj-$(CONFIG_INFINIBAND_SRP)           += ulp/srp/
 obj-$(CONFIG_INFINIBAND_ISER)          += ulp/iser/
index 189e5d4b9b17ed271027e2c015b252f929fbd32d..cb1ab3ea49986f448474ce941c8e2f9cf7418b64 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \
 
 ib_core-y :=                   packer.o ud_header.o verbs.o sysfs.o \
                                device.o fmr_pool.o cache.o
+ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
 
 ib_mad-y :=                    mad.o smi.o agent.o mad_rmpp.o
 
@@ -28,5 +29,4 @@ ib_umad-y :=                  user_mad.o
 
 ib_ucm-y :=                    ucm.o
 
-ib_uverbs-y :=                 uverbs_main.o uverbs_cmd.o uverbs_mem.o \
-                               uverbs_marshall.o
+ib_uverbs-y :=                 uverbs_main.o uverbs_cmd.o uverbs_marshall.o
index 7fabb425b033a2de2243d50b24164937c0e99e49..592c90aa31830eea4b5856f6a150178b4c636958 100644 (file)
@@ -613,6 +613,8 @@ static void __exit ib_core_cleanup(void)
 {
        ib_cache_cleanup();
        ib_sysfs_cleanup();
+       /* Make sure that any pending umem accounting work is done. */
+       flush_scheduled_work();
 }
 
 module_init(ib_core_init);
similarity index 59%
rename from drivers/infiniband/core/uverbs_mem.c
rename to drivers/infiniband/core/umem.c
index c95fe952abd5e8e7b47bd5bc92c9bcbfa8d74cfb..f32ca5fbb26bcc56b02cd8c97bfa39bce1f3c63b 100644 (file)
 
 #include "uverbs.h"
 
-struct ib_umem_account_work {
-       struct work_struct work;
-       struct mm_struct  *mm;
-       unsigned long      diff;
-};
-
-
 static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
 {
        struct ib_umem_chunk *chunk, *tmp;
@@ -64,35 +57,56 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
        }
 }
 
-int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
-               void *addr, size_t size, int write)
+/**
+ * ib_umem_get - Pin and DMA map userspace memory.
+ * @context: userspace context to pin memory for
+ * @addr: userspace virtual address to start at
+ * @size: length of region to pin
+ * @access: IB_ACCESS_xxx flags for memory being pinned
+ */
+struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
+                           size_t size, int access)
 {
+       struct ib_umem *umem;
        struct page **page_list;
        struct ib_umem_chunk *chunk;
        unsigned long locked;
        unsigned long lock_limit;
        unsigned long cur_base;
        unsigned long npages;
-       int ret = 0;
+       int ret;
        int off;
        int i;
 
        if (!can_do_mlock())
-               return -EPERM;
+               return ERR_PTR(-EPERM);
 
-       page_list = (struct page **) __get_free_page(GFP_KERNEL);
-       if (!page_list)
-               return -ENOMEM;
+       umem = kmalloc(sizeof *umem, GFP_KERNEL);
+       if (!umem)
+               return ERR_PTR(-ENOMEM);
+
+       umem->context   = context;
+       umem->length    = size;
+       umem->offset    = addr & ~PAGE_MASK;
+       umem->page_size = PAGE_SIZE;
+       /*
+        * We ask for writable memory if any access flags other than
+        * "remote read" are set.  "Local write" and "remote write"
+        * obviously require write access.  "Remote atomic" can do
+        * things like fetch and add, which will modify memory, and
+        * "MW bind" can change permissions by binding a window.
+        */
+       umem->writable  = !!(access & ~IB_ACCESS_REMOTE_READ);
 
-       mem->user_base = (unsigned long) addr;
-       mem->length    = size;
-       mem->offset    = (unsigned long) addr & ~PAGE_MASK;
-       mem->page_size = PAGE_SIZE;
-       mem->writable  = write;
+       INIT_LIST_HEAD(&umem->chunk_list);
 
-       INIT_LIST_HEAD(&mem->chunk_list);
+       page_list = (struct page **) __get_free_page(GFP_KERNEL);
+       if (!page_list) {
+               kfree(umem);
+               return ERR_PTR(-ENOMEM);
+       }
 
-       npages = PAGE_ALIGN(size + mem->offset) >> PAGE_SHIFT;
+       npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT;
 
        down_write(&current->mm->mmap_sem);
 
@@ -104,13 +118,13 @@ int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
                goto out;
        }
 
-       cur_base = (unsigned long) addr & PAGE_MASK;
+       cur_base = addr & PAGE_MASK;
 
        while (npages) {
                ret = get_user_pages(current, current->mm, cur_base,
                                     min_t(int, npages,
                                           PAGE_SIZE / sizeof (struct page *)),
-                                    1, !write, page_list, NULL);
+                                    1, !umem->writable, page_list, NULL);
 
                if (ret < 0)
                        goto out;
@@ -136,7 +150,7 @@ int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
                                chunk->page_list[i].length = PAGE_SIZE;
                        }
 
-                       chunk->nmap = ib_dma_map_sg(dev,
+                       chunk->nmap = ib_dma_map_sg(context->device,
                                                    &chunk->page_list[0],
                                                    chunk->nents,
                                                    DMA_BIDIRECTIONAL);
@@ -151,75 +165,94 @@ int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
 
                        ret -= chunk->nents;
                        off += chunk->nents;
-                       list_add_tail(&chunk->list, &mem->chunk_list);
+                       list_add_tail(&chunk->list, &umem->chunk_list);
                }
 
                ret = 0;
        }
 
 out:
-       if (ret < 0)
-               __ib_umem_release(dev, mem, 0);
-       else
+       if (ret < 0) {
+               __ib_umem_release(context->device, umem, 0);
+               kfree(umem);
+       } else
                current->mm->locked_vm = locked;
 
        up_write(&current->mm->mmap_sem);
        free_page((unsigned long) page_list);
 
-       return ret;
+       return ret < 0 ? ERR_PTR(ret) : umem;
 }
+EXPORT_SYMBOL(ib_umem_get);
 
-void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
+static void ib_umem_account(struct work_struct *work)
 {
-       __ib_umem_release(dev, umem, 1);
-
-       down_write(&current->mm->mmap_sem);
-       current->mm->locked_vm -=
-               PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
-       up_write(&current->mm->mmap_sem);
-}
+       struct ib_umem *umem = container_of(work, struct ib_umem, work);
 
-static void ib_umem_account(struct work_struct *_work)
-{
-       struct ib_umem_account_work *work =
-               container_of(_work, struct ib_umem_account_work, work);
-
-       down_write(&work->mm->mmap_sem);
-       work->mm->locked_vm -= work->diff;
-       up_write(&work->mm->mmap_sem);
-       mmput(work->mm);
-       kfree(work);
+       down_write(&umem->mm->mmap_sem);
+       umem->mm->locked_vm -= umem->diff;
+       up_write(&umem->mm->mmap_sem);
+       mmput(umem->mm);
+       kfree(umem);
 }
 
-void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem)
+/**
+ * ib_umem_release - release memory pinned with ib_umem_get
+ * @umem: umem struct to release
+ */
+void ib_umem_release(struct ib_umem *umem)
 {
-       struct ib_umem_account_work *work;
+       struct ib_ucontext *context = umem->context;
        struct mm_struct *mm;
+       unsigned long diff;
 
-       __ib_umem_release(dev, umem, 1);
+       __ib_umem_release(umem->context->device, umem, 1);
 
        mm = get_task_mm(current);
        if (!mm)
                return;
 
+       diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+
        /*
         * We may be called with the mm's mmap_sem already held.  This
         * can happen when a userspace munmap() is the call that drops
         * the last reference to our file and calls our release
         * method.  If there are memory regions to destroy, we'll end
-        * up here and not be able to take the mmap_sem.  Therefore we
-        * defer the vm_locked accounting to the system workqueue.
+        * up here and not be able to take the mmap_sem.  In that case
+        * we defer the vm_locked accounting to the system workqueue.
         */
+       if (context->closing && !down_write_trylock(&mm->mmap_sem)) {
+               INIT_WORK(&umem->work, ib_umem_account);
+               umem->mm   = mm;
+               umem->diff = diff;
 
-       work = kmalloc(sizeof *work, GFP_KERNEL);
-       if (!work) {
-               mmput(mm);
+               schedule_work(&umem->work);
                return;
-       }
+       } else
+               down_write(&mm->mmap_sem);
+
+       current->mm->locked_vm -= diff;
+       up_write(&mm->mmap_sem);
+       mmput(mm);
+       kfree(umem);
+}
+EXPORT_SYMBOL(ib_umem_release);
+
+int ib_umem_page_count(struct ib_umem *umem)
+{
+       struct ib_umem_chunk *chunk;
+       int shift;
+       int i;
+       int n;
+
+       shift = ilog2(umem->page_size);
 
-       INIT_WORK(&work->work, ib_umem_account);
-       work->mm   = mm;
-       work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+       n = 0;
+       list_for_each_entry(chunk, &umem->chunk_list, list)
+               for (i = 0; i < chunk->nmap; ++i)
+                       n += sg_dma_len(&chunk->page_list[i]) >> shift;
 
-       schedule_work(&work->work);
+       return n;
 }
+EXPORT_SYMBOL(ib_umem_page_count);
index 102a59c033ff9fe3b0f79b8aedc66ced43515eb4..c33546f9e96199b28811ed5396c3daabda27e8c4 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/completion.h>
 
 #include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
 
 /*
@@ -163,11 +164,6 @@ void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
 void ib_uverbs_event_handler(struct ib_event_handler *handler,
                             struct ib_event *event);
 
-int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
-               void *addr, size_t size, int write);
-void ib_umem_release(struct ib_device *dev, struct ib_umem *umem);
-void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem);
-
 #define IB_UVERBS_DECLARE_CMD(name)                                    \
        ssize_t ib_uverbs_##name(struct ib_uverbs_file *file,           \
                                 const char __user *buf, int in_len,    \
index bab66769be14a2ae6b422113e80b038a35f4b988..01d70084aebe8c0737dc685c0bf3c4db3a57b4ec 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
  *
@@ -295,6 +295,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
        INIT_LIST_HEAD(&ucontext->qp_list);
        INIT_LIST_HEAD(&ucontext->srq_list);
        INIT_LIST_HEAD(&ucontext->ah_list);
+       ucontext->closing = 0;
 
        resp.num_comp_vectors = file->device->num_comp_vectors;
 
@@ -573,7 +574,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
        struct ib_uverbs_reg_mr      cmd;
        struct ib_uverbs_reg_mr_resp resp;
        struct ib_udata              udata;
-       struct ib_umem_object       *obj;
+       struct ib_uobject           *uobj;
        struct ib_pd                *pd;
        struct ib_mr                *mr;
        int                          ret;
@@ -599,35 +600,21 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
            !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE))
                return -EINVAL;
 
-       obj = kmalloc(sizeof *obj, GFP_KERNEL);
-       if (!obj)
+       uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+       if (!uobj)
                return -ENOMEM;
 
-       init_uobj(&obj->uobject, 0, file->ucontext, &mr_lock_key);
-       down_write(&obj->uobject.mutex);
-
-       /*
-        * We ask for writable memory if any access flags other than
-        * "remote read" are set.  "Local write" and "remote write"
-        * obviously require write access.  "Remote atomic" can do
-        * things like fetch and add, which will modify memory, and
-        * "MW bind" can change permissions by binding a window.
-        */
-       ret = ib_umem_get(file->device->ib_dev, &obj->umem,
-                         (void *) (unsigned long) cmd.start, cmd.length,
-                         !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ));
-       if (ret)
-               goto err_free;
-
-       obj->umem.virt_base = cmd.hca_va;
+       init_uobj(uobj, 0, file->ucontext, &mr_lock_key);
+       down_write(&uobj->mutex);
 
        pd = idr_read_pd(cmd.pd_handle, file->ucontext);
        if (!pd) {
                ret = -EINVAL;
-               goto err_release;
+               goto err_free;
        }
 
-       mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
+       mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va,
+                                    cmd.access_flags, &udata);
        if (IS_ERR(mr)) {
                ret = PTR_ERR(mr);
                goto err_put;
@@ -635,19 +622,19 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 
        mr->device  = pd->device;
        mr->pd      = pd;
-       mr->uobject = &obj->uobject;
+       mr->uobject = uobj;
        atomic_inc(&pd->usecnt);
        atomic_set(&mr->usecnt, 0);
 
-       obj->uobject.object = mr;
-       ret = idr_add_uobj(&ib_uverbs_mr_idr, &obj->uobject);
+       uobj->object = mr;
+       ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj);
        if (ret)
                goto err_unreg;
 
        memset(&resp, 0, sizeof resp);
        resp.lkey      = mr->lkey;
        resp.rkey      = mr->rkey;
-       resp.mr_handle = obj->uobject.id;
+       resp.mr_handle = uobj->id;
 
        if (copy_to_user((void __user *) (unsigned long) cmd.response,
                         &resp, sizeof resp)) {
@@ -658,17 +645,17 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
        put_pd_read(pd);
 
        mutex_lock(&file->mutex);
-       list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
+       list_add_tail(&uobj->list, &file->ucontext->mr_list);
        mutex_unlock(&file->mutex);
 
-       obj->uobject.live = 1;
+       uobj->live = 1;
 
-       up_write(&obj->uobject.mutex);
+       up_write(&uobj->mutex);
 
        return in_len;
 
 err_copy:
-       idr_remove_uobj(&ib_uverbs_mr_idr, &obj->uobject);
+       idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
 
 err_unreg:
        ib_dereg_mr(mr);
@@ -676,11 +663,8 @@ err_unreg:
 err_put:
        put_pd_read(pd);
 
-err_release:
-       ib_umem_release(file->device->ib_dev, &obj->umem);
-
 err_free:
-       put_uobj_write(&obj->uobject);
+       put_uobj_write(uobj);
        return ret;
 }
 
@@ -691,7 +675,6 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
        struct ib_uverbs_dereg_mr cmd;
        struct ib_mr             *mr;
        struct ib_uobject        *uobj;
-       struct ib_umem_object    *memobj;
        int                       ret = -EINVAL;
 
        if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -701,8 +684,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
        if (!uobj)
                return -EINVAL;
 
-       memobj = container_of(uobj, struct ib_umem_object, uobject);
-       mr     = uobj->object;
+       mr = uobj->object;
 
        ret = ib_dereg_mr(mr);
        if (!ret)
@@ -719,8 +701,6 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
        list_del(&uobj->list);
        mutex_unlock(&file->mutex);
 
-       ib_umem_release(file->device->ib_dev, &memobj->umem);
-
        put_uobj(uobj);
 
        return in_len;
index d44e54799651b68645f1643a2f520f2fea90348d..14d7ccd8919534d646814fb7cf58c89a81f07bc0 100644 (file)
@@ -183,6 +183,8 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
        if (!context)
                return 0;
 
+       context->closing = 1;
+
        list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
                struct ib_ah *ah = uobj->object;
 
@@ -230,16 +232,10 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
 
        list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
                struct ib_mr *mr = uobj->object;
-               struct ib_device *mrdev = mr->device;
-               struct ib_umem_object *memobj;
 
                idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
                ib_dereg_mr(mr);
-
-               memobj = container_of(uobj, struct ib_umem_object, uobject);
-               ib_umem_release_on_close(mrdev, &memobj->umem);
-
-               kfree(memobj);
+               kfree(uobj);
        }
 
        list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
@@ -906,7 +902,6 @@ static void __exit ib_uverbs_cleanup(void)
        unregister_filesystem(&uverbs_event_fs);
        class_destroy(uverbs_class);
        unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
-       flush_scheduled_work();
        idr_destroy(&ib_uverbs_pd_idr);
        idr_destroy(&ib_uverbs_mr_idr);
        idr_destroy(&ib_uverbs_mw_idr);
index 109166223c09159ad0e85efdb6073006ad81da92..997cf1530762458f80e285cd8f6297a5d8eeb94e 100644 (file)
@@ -56,6 +56,7 @@
 #include <asm/byteorder.h>
 
 #include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
 #include "c2.h"
 #include "c2_provider.h"
@@ -396,6 +397,7 @@ static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
        }
 
        mr->pd = to_c2pd(ib_pd);
+       mr->umem = NULL;
        pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
                "*iova_start %llx, first pa %llx, last pa %llx\n",
                __FUNCTION__, page_shift, pbl_depth, total_len,
@@ -428,8 +430,8 @@ static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
        return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
 }
 
-static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
-                                   int acc, struct ib_udata *udata)
+static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                   u64 virt, int acc, struct ib_udata *udata)
 {
        u64 *pages;
        u64 kva = 0;
@@ -441,15 +443,23 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        struct c2_mr *c2mr;
 
        pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
-       shift = ffs(region->page_size) - 1;
 
        c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
        if (!c2mr)
                return ERR_PTR(-ENOMEM);
        c2mr->pd = c2pd;
 
+       c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+       if (IS_ERR(c2mr->umem)) {
+               err = PTR_ERR(c2mr->umem);
+               kfree(c2mr);
+               return ERR_PTR(err);
+       }
+
+       shift = ffs(c2mr->umem->page_size) - 1;
+
        n = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &c2mr->umem->chunk_list, list)
                n += chunk->nents;
 
        pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
@@ -459,35 +469,34 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        }
 
        i = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list) {
+       list_for_each_entry(chunk, &c2mr->umem->chunk_list, list) {
                for (j = 0; j < chunk->nmap; ++j) {
                        len = sg_dma_len(&chunk->page_list[j]) >> shift;
                        for (k = 0; k < len; ++k) {
                                pages[i++] =
                                        sg_dma_address(&chunk->page_list[j]) +
-                                       (region->page_size * k);
+                                       (c2mr->umem->page_size * k);
                        }
                }
        }
 
-       kva = (u64)region->virt_base;
+       kva = virt;
        err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
                                         pages,
-                                        region->page_size,
+                                        c2mr->umem->page_size,
                                         i,
-                                        region->length,
-                                        region->offset,
+                                        length,
+                                        c2mr->umem->offset,
                                         &kva,
                                         c2_convert_access(acc),
                                         c2mr);
        kfree(pages);
-       if (err) {
-               kfree(c2mr);
-               return ERR_PTR(err);
-       }
+       if (err)
+               goto err;
        return &c2mr->ibmr;
 
 err:
+       ib_umem_release(c2mr->umem);
        kfree(c2mr);
        return ERR_PTR(err);
 }
@@ -502,8 +511,11 @@ static int c2_dereg_mr(struct ib_mr *ib_mr)
        err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
        if (err)
                pr_debug("c2_stag_dealloc failed: %d\n", err);
-       else
+       else {
+               if (mr->umem)
+                       ib_umem_release(mr->umem);
                kfree(mr);
+       }
 
        return err;
 }
index fc906223220fcafba269028995b86e0df5ab98b1..1076df2ee96ae3bc0cdd1869b2a35ca4f7e35952 100644 (file)
@@ -73,6 +73,7 @@ struct c2_pd {
 struct c2_mr {
        struct ib_mr ibmr;
        struct c2_pd *pd;
+       struct ib_umem *umem;
 };
 
 struct c2_av;
index a891493fd34017adbab711ce5a3cd0125c074c24..e7c2c3948037e6853586be07e01f2c1f3b5731bb 100644 (file)
@@ -47,6 +47,7 @@
 #include <rdma/iw_cm.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
 
 #include "cxio_hal.h"
@@ -443,6 +444,8 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr)
        remove_handle(rhp, &rhp->mmidr, mmid);
        if (mhp->kva)
                kfree((void *) (unsigned long) mhp->kva);
+       if (mhp->umem)
+               ib_umem_release(mhp->umem);
        PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp);
        kfree(mhp);
        return 0;
@@ -577,8 +580,8 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
 }
 
 
-static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
-                                     int acc, struct ib_udata *udata)
+static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                     u64 virt, int acc, struct ib_udata *udata)
 {
        __be64 *pages;
        int shift, n, len;
@@ -591,7 +594,6 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        struct iwch_reg_user_mr_resp uresp;
 
        PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
-       shift = ffs(region->page_size) - 1;
 
        php = to_iwch_pd(pd);
        rhp = php->rhp;
@@ -599,8 +601,17 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        if (!mhp)
                return ERR_PTR(-ENOMEM);
 
+       mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+       if (IS_ERR(mhp->umem)) {
+               err = PTR_ERR(mhp->umem);
+               kfree(mhp);
+               return ERR_PTR(err);
+       }
+
+       shift = ffs(mhp->umem->page_size) - 1;
+
        n = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
                n += chunk->nents;
 
        pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
@@ -611,13 +622,13 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
 
        i = n = 0;
 
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
                for (j = 0; j < chunk->nmap; ++j) {
                        len = sg_dma_len(&chunk->page_list[j]) >> shift;
                        for (k = 0; k < len; ++k) {
                                pages[i++] = cpu_to_be64(sg_dma_address(
                                        &chunk->page_list[j]) +
-                                       region->page_size * k);
+                                       mhp->umem->page_size * k);
                        }
                }
 
@@ -625,9 +636,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        mhp->attr.pdid = php->pdid;
        mhp->attr.zbva = 0;
        mhp->attr.perms = iwch_ib_to_tpt_access(acc);
-       mhp->attr.va_fbo = region->virt_base;
+       mhp->attr.va_fbo = virt;
        mhp->attr.page_size = shift - 12;
-       mhp->attr.len = (u32) region->length;
+       mhp->attr.len = (u32) length;
        mhp->attr.pbl_size = i;
        err = iwch_register_mem(rhp, php, mhp, shift, pages);
        kfree(pages);
@@ -650,6 +661,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        return &mhp->ibmr;
 
 err:
+       ib_umem_release(mhp->umem);
        kfree(mhp);
        return ERR_PTR(err);
 }
index 93bcc56756bd42a14cce112f51b1a7ba2b3f8797..48833f3f3bd03779e4139b6db8e91166af0fff04 100644 (file)
@@ -73,6 +73,7 @@ struct tpt_attributes {
 
 struct iwch_mr {
        struct ib_mr ibmr;
+       struct ib_umem *umem;
        struct iwch_dev *rhp;
        u64 kva;
        struct tpt_attributes attr;
index 10fb8fbafa0c4cd31457ae3d511586b0a7e54c20..f64d42b08674a9f60fad0aa2635e9f585b747b57 100644 (file)
@@ -176,6 +176,7 @@ struct ehca_mr {
                struct ib_mr ib_mr;     /* must always be first in ehca_mr */
                struct ib_fmr ib_fmr;   /* must always be first in ehca_mr */
        } ib;
+       struct ib_umem *umem;
        spinlock_t mrlock;
 
        enum ehca_mr_flag flags;
index f284be1c916645067aa3b6659925e81040c55fe4..82dda2faf4d0b6b271193b92ec421f60151801b3 100644 (file)
@@ -745,6 +745,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
                if(!create_comp_task(pool, cpu)) {
                        ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
@@ -752,24 +753,29 @@ static int comp_pool_callback(struct notifier_block *nfb,
                }
                break;
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
                cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
                kthread_bind(cct->task, any_online_cpu(cpu_online_map));
                destroy_comp_task(pool, cpu);
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
                cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
                kthread_bind(cct->task, cpu);
                wake_up_process(cct->task);
                break;
        case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
                break;
        case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
                destroy_comp_task(pool, cpu);
                take_over_work(pool, cpu);
index e14b029332c8a59d23be4399003ec54bc31b39ba..37e7fe0908cfad268e8da90142f9d6f8aeaa85ec 100644 (file)
@@ -78,8 +78,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
                               int num_phys_buf,
                               int mr_access_flags, u64 *iova_start);
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
-                              struct ib_umem *region,
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
                               int mr_access_flags, struct ib_udata *udata);
 
 int ehca_rereg_phys_mr(struct ib_mr *mr,
index d22ab563633f0ed10c7cb476e5ebe5deec452ed0..84c5bb4985634a47f0e2bec5cf8b54038f32c95d 100644 (file)
@@ -39,6 +39,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <rdma/ib_umem.h>
+
 #include <asm/current.h>
 
 #include "ehca_iverbs.h"
@@ -238,10 +240,8 @@ reg_phys_mr_exit0:
 
 /*----------------------------------------------------------------------*/
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
-                              struct ib_umem *region,
-                              int mr_access_flags,
-                              struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
+                              int mr_access_flags, struct ib_udata *udata)
 {
        struct ib_mr *ib_mr;
        struct ehca_mr *e_mr;
@@ -257,11 +257,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
                ehca_gen_err("bad pd=%p", pd);
                return ERR_PTR(-EFAULT);
        }
-       if (!region) {
-               ehca_err(pd->device, "bad input values: region=%p", region);
-               ib_mr = ERR_PTR(-EINVAL);
-               goto reg_user_mr_exit0;
-       }
+
        if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
             !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
            ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
@@ -275,17 +271,10 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
                ib_mr = ERR_PTR(-EINVAL);
                goto reg_user_mr_exit0;
        }
-       if (region->page_size != PAGE_SIZE) {
-               ehca_err(pd->device, "page size not supported, "
-                        "region->page_size=%x", region->page_size);
-               ib_mr = ERR_PTR(-EINVAL);
-               goto reg_user_mr_exit0;
-       }
 
-       if ((region->length == 0) ||
-           ((region->virt_base + region->length) < region->virt_base)) {
+       if (length == 0 || virt + length < virt) {
                ehca_err(pd->device, "bad input values: length=%lx "
-                        "virt_base=%lx", region->length, region->virt_base);
+                        "virt_base=%lx", length, virt);
                ib_mr = ERR_PTR(-EINVAL);
                goto reg_user_mr_exit0;
        }
@@ -297,40 +286,55 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
                goto reg_user_mr_exit0;
        }
 
+       e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
+                                mr_access_flags);
+       if (IS_ERR(e_mr->umem)) {
+               ib_mr = (void *) e_mr->umem;
+               goto reg_user_mr_exit1;
+       }
+
+       if (e_mr->umem->page_size != PAGE_SIZE) {
+               ehca_err(pd->device, "page size not supported, "
+                        "e_mr->umem->page_size=%x", e_mr->umem->page_size);
+               ib_mr = ERR_PTR(-EINVAL);
+               goto reg_user_mr_exit2;
+       }
+
        /* determine number of MR pages */
-       num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length +
-                        PAGE_SIZE - 1) / PAGE_SIZE);
-       num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length +
-                        EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+       num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
+                       PAGE_SIZE);
+       num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
+                       EHCA_PAGESIZE);
 
        /* register MR on HCA */
        pginfo.type       = EHCA_MR_PGI_USER;
        pginfo.num_pages  = num_pages_mr;
        pginfo.num_4k     = num_pages_4k;
-       pginfo.region     = region;
-       pginfo.next_4k    = region->offset / EHCA_PAGESIZE;
+       pginfo.region     = e_mr->umem;
+       pginfo.next_4k    = e_mr->umem->offset / EHCA_PAGESIZE;
        pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
-                                              (&region->chunk_list),
+                                              (&e_mr->umem->chunk_list),
                                               list);
 
-       ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base,
-                         region->length, mr_access_flags, e_pd, &pginfo,
-                         &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+       ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
+                         &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
        if (ret) {
                ib_mr = ERR_PTR(ret);
-               goto reg_user_mr_exit1;
+               goto reg_user_mr_exit2;
        }
 
        /* successful registration of all pages */
        return &e_mr->ib.ib_mr;
 
+reg_user_mr_exit2:
+       ib_umem_release(e_mr->umem);
 reg_user_mr_exit1:
        ehca_mr_delete(e_mr);
 reg_user_mr_exit0:
        if (IS_ERR(ib_mr))
-               ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x"
+               ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x"
                         " udata=%p",
-                        PTR_ERR(ib_mr), pd, region, mr_access_flags, udata);
+                        PTR_ERR(ib_mr), pd, mr_access_flags, udata);
        return ib_mr;
 } /* end ehca_reg_user_mr() */
 
@@ -596,6 +600,9 @@ int ehca_dereg_mr(struct ib_mr *mr)
                goto dereg_mr_exit0;
        }
 
+       if (e_mr->umem)
+               ib_umem_release(e_mr->umem);
+
        /* successful deregistration */
        ehca_mr_delete(e_mr);
 
index 31e70732e36950bc4d765a74779c6a86ded4cf3a..bdeef8d4f279cb5abb8c5954e15dda65a461128d 100644 (file)
@@ -31,6 +31,7 @@
  * SOFTWARE.
  */
 
+#include <rdma/ib_umem.h>
 #include <rdma/ib_pack.h>
 #include <rdma/ib_smi.h>
 
@@ -147,6 +148,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
        mr->mr.offset = 0;
        mr->mr.access_flags = acc;
        mr->mr.max_segs = num_phys_buf;
+       mr->umem = NULL;
 
        m = 0;
        n = 0;
@@ -170,46 +172,56 @@ bail:
 /**
  * ipath_reg_user_mr - register a userspace memory region
  * @pd: protection domain for this memory region
- * @region: the user memory region
+ * @start: starting userspace address
+ * @length: length of region to register
+ * @virt_addr: virtual address to use (from HCA's point of view)
  * @mr_access_flags: access flags for this memory region
  * @udata: unused by the InfiniPath driver
  *
  * Returns the memory region on success, otherwise returns an errno.
  */
-struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
-                               int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                               u64 virt_addr, int mr_access_flags,
+                               struct ib_udata *udata)
 {
        struct ipath_mr *mr;
+       struct ib_umem *umem;
        struct ib_umem_chunk *chunk;
        int n, m, i;
        struct ib_mr *ret;
 
-       if (region->length == 0) {
+       if (length == 0) {
                ret = ERR_PTR(-EINVAL);
                goto bail;
        }
 
+       umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags);
+       if (IS_ERR(umem))
+               return (void *) umem;
+
        n = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &umem->chunk_list, list)
                n += chunk->nents;
 
        mr = alloc_mr(n, &to_idev(pd->device)->lk_table);
        if (!mr) {
                ret = ERR_PTR(-ENOMEM);
+               ib_umem_release(umem);
                goto bail;
        }
 
        mr->mr.pd = pd;
-       mr->mr.user_base = region->user_base;
-       mr->mr.iova = region->virt_base;
-       mr->mr.length = region->length;
-       mr->mr.offset = region->offset;
+       mr->mr.user_base = start;
+       mr->mr.iova = virt_addr;
+       mr->mr.length = length;
+       mr->mr.offset = umem->offset;
        mr->mr.access_flags = mr_access_flags;
        mr->mr.max_segs = n;
+       mr->umem = umem;
 
        m = 0;
        n = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list) {
+       list_for_each_entry(chunk, &umem->chunk_list, list) {
                for (i = 0; i < chunk->nents; i++) {
                        void *vaddr;
 
@@ -219,7 +231,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
                                goto bail;
                        }
                        mr->mr.map[m]->segs[n].vaddr = vaddr;
-                       mr->mr.map[m]->segs[n].length = region->page_size;
+                       mr->mr.map[m]->segs[n].length = umem->page_size;
                        n++;
                        if (n == IPATH_SEGSZ) {
                                m++;
@@ -253,6 +265,10 @@ int ipath_dereg_mr(struct ib_mr *ibmr)
                i--;
                kfree(mr->mr.map[i]);
        }
+
+       if (mr->umem)
+               ib_umem_release(mr->umem);
+
        kfree(mr);
        return 0;
 }
index 7064fc22272765c8f943de8a7a5f35b176120f17..088b837ebea8f2c22770f1d578e778d378696224 100644 (file)
@@ -251,6 +251,7 @@ struct ipath_sge {
 /* Memory region */
 struct ipath_mr {
        struct ib_mr ibmr;
+       struct ib_umem *umem;
        struct ipath_mregion mr;        /* must be last */
 };
 
@@ -751,8 +752,8 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
                                struct ib_phys_buf *buffer_list,
                                int num_phys_buf, int acc, u64 *iova_start);
 
-struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
-                               int mr_access_flags,
+struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                               u64 virt_addr, int mr_access_flags,
                                struct ib_udata *udata);
 
 int ipath_dereg_mr(struct ib_mr *ibmr);
diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig
new file mode 100644 (file)
index 0000000..b8912cd
--- /dev/null
@@ -0,0 +1,9 @@
+config MLX4_INFINIBAND
+       tristate "Mellanox ConnectX HCA support"
+       depends on INFINIBAND
+       select MLX4_CORE
+       ---help---
+         This driver provides low-level InfiniBand support for
+         Mellanox ConnectX PCI Express host channel adapters (HCAs).
+         This is required to use InfiniBand protocols such as
+         IP-over-IB or SRP with these devices.
diff --git a/drivers/infiniband/hw/mlx4/Makefile b/drivers/infiniband/hw/mlx4/Makefile
new file mode 100644 (file)
index 0000000..70f09c7
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MLX4_INFINIBAND)  += mlx4_ib.o
+
+mlx4_ib-y :=   ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o
diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c
new file mode 100644 (file)
index 0000000..c75ac94
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx4_ib.h"
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+       struct mlx4_dev *dev = to_mdev(pd->device)->dev;
+       struct mlx4_ib_ah *ah;
+
+       ah = kmalloc(sizeof *ah, GFP_ATOMIC);
+       if (!ah)
+               return ERR_PTR(-ENOMEM);
+
+       memset(&ah->av, 0, sizeof ah->av);
+
+       ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+       ah->av.g_slid  = ah_attr->src_path_bits;
+       ah->av.dlid    = cpu_to_be16(ah_attr->dlid);
+       if (ah_attr->static_rate) {
+               ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+               while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+                      !(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
+                       --ah->av.stat_rate;
+       }
+       ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+       if (ah_attr->ah_flags & IB_AH_GRH) {
+               ah->av.g_slid   |= 0x80;
+               ah->av.gid_index = ah_attr->grh.sgid_index;
+               ah->av.hop_limit = ah_attr->grh.hop_limit;
+               ah->av.sl_tclass_flowlabel |=
+                       cpu_to_be32((ah_attr->grh.traffic_class << 20) |
+                                   ah_attr->grh.flow_label);
+               memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
+       }
+
+       return &ah->ibah;
+}
+
+int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
+{
+       struct mlx4_ib_ah *ah = to_mah(ibah);
+
+       memset(ah_attr, 0, sizeof *ah_attr);
+       ah_attr->dlid          = be16_to_cpu(ah->av.dlid);
+       ah_attr->sl            = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
+       ah_attr->port_num      = be32_to_cpu(ah->av.port_pd) >> 24;
+       if (ah->av.stat_rate)
+               ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
+       ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
+
+       if (mlx4_ib_ah_grh_present(ah)) {
+               ah_attr->ah_flags = IB_AH_GRH;
+
+               ah_attr->grh.traffic_class =
+                       be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20;
+               ah_attr->grh.flow_label =
+                       be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
+               ah_attr->grh.hop_limit  = ah->av.hop_limit;
+               ah_attr->grh.sgid_index = ah->av.gid_index;
+               memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
+       }
+
+       return 0;
+}
+
+int mlx4_ib_destroy_ah(struct ib_ah *ah)
+{
+       kfree(to_mah(ah));
+       return 0;
+}
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
new file mode 100644 (file)
index 0000000..b2a290c
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx4/cq.h>
+#include <linux/mlx4/qp.h>
+
+#include "mlx4_ib.h"
+#include "user.h"
+
+static void mlx4_ib_cq_comp(struct mlx4_cq *cq)
+{
+       struct ib_cq *ibcq = &to_mibcq(cq)->ibcq;
+       ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+static void mlx4_ib_cq_event(struct mlx4_cq *cq, enum mlx4_event type)
+{
+       struct ib_event event;
+       struct ib_cq *ibcq;
+
+       if (type != MLX4_EVENT_TYPE_CQ_ERROR) {
+               printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+                      "on CQ %06x\n", type, cq->cqn);
+               return;
+       }
+
+       ibcq = &to_mibcq(cq)->ibcq;
+       if (ibcq->event_handler) {
+               event.device     = ibcq->device;
+               event.event      = IB_EVENT_CQ_ERR;
+               event.element.cq = ibcq;
+               ibcq->event_handler(&event, ibcq->cq_context);
+       }
+}
+
+static void *get_cqe_from_buf(struct mlx4_ib_cq_buf *buf, int n)
+{
+       int offset = n * sizeof (struct mlx4_cqe);
+
+       if (buf->buf.nbufs == 1)
+               return buf->buf.u.direct.buf + offset;
+       else
+               return buf->buf.u.page_list[offset >> PAGE_SHIFT].buf +
+                       (offset & (PAGE_SIZE - 1));
+}
+
+static void *get_cqe(struct mlx4_ib_cq *cq, int n)
+{
+       return get_cqe_from_buf(&cq->buf, n);
+}
+
+static void *get_sw_cqe(struct mlx4_ib_cq *cq, int n)
+{
+       struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibcq.cqe);
+
+       return (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
+               !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe;
+}
+
+static struct mlx4_cqe *next_cqe_sw(struct mlx4_ib_cq *cq)
+{
+       return get_sw_cqe(cq, cq->mcq.cons_index);
+}
+
+struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector,
+                               struct ib_ucontext *context,
+                               struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+       struct mlx4_ib_cq *cq;
+       struct mlx4_uar *uar;
+       int buf_size;
+       int err;
+
+       if (entries < 1 || entries > dev->dev->caps.max_cqes)
+               return ERR_PTR(-EINVAL);
+
+       cq = kmalloc(sizeof *cq, GFP_KERNEL);
+       if (!cq)
+               return ERR_PTR(-ENOMEM);
+
+       entries      = roundup_pow_of_two(entries + 1);
+       cq->ibcq.cqe = entries - 1;
+       buf_size     = entries * sizeof (struct mlx4_cqe);
+       spin_lock_init(&cq->lock);
+
+       if (context) {
+               struct mlx4_ib_create_cq ucmd;
+
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+                       err = -EFAULT;
+                       goto err_cq;
+               }
+
+               cq->umem = ib_umem_get(context, ucmd.buf_addr, buf_size,
+                                      IB_ACCESS_LOCAL_WRITE);
+               if (IS_ERR(cq->umem)) {
+                       err = PTR_ERR(cq->umem);
+                       goto err_cq;
+               }
+
+               err = mlx4_mtt_init(dev->dev, ib_umem_page_count(cq->umem),
+                                   ilog2(cq->umem->page_size), &cq->buf.mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_ib_umem_write_mtt(dev, &cq->buf.mtt, cq->umem);
+               if (err)
+                       goto err_mtt;
+
+               err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr,
+                                         &cq->db);
+               if (err)
+                       goto err_mtt;
+
+               uar = &to_mucontext(context)->uar;
+       } else {
+               err = mlx4_ib_db_alloc(dev, &cq->db, 1);
+               if (err)
+                       goto err_cq;
+
+               cq->mcq.set_ci_db  = cq->db.db;
+               cq->mcq.arm_db     = cq->db.db + 1;
+               *cq->mcq.set_ci_db = 0;
+               *cq->mcq.arm_db    = 0;
+
+               if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &cq->buf.buf)) {
+                       err = -ENOMEM;
+                       goto err_db;
+               }
+
+               err = mlx4_mtt_init(dev->dev, cq->buf.buf.npages, cq->buf.buf.page_shift,
+                                   &cq->buf.mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_buf_write_mtt(dev->dev, &cq->buf.mtt, &cq->buf.buf);
+               if (err)
+                       goto err_mtt;
+
+               uar = &dev->priv_uar;
+       }
+
+       err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
+                           cq->db.dma, &cq->mcq);
+       if (err)
+               goto err_dbmap;
+
+       cq->mcq.comp  = mlx4_ib_cq_comp;
+       cq->mcq.event = mlx4_ib_cq_event;
+
+       if (context)
+               if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) {
+                       err = -EFAULT;
+                       goto err_dbmap;
+               }
+
+       return &cq->ibcq;
+
+err_dbmap:
+       if (context)
+               mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db);
+
+err_mtt:
+       mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt);
+
+err_buf:
+       if (context)
+               ib_umem_release(cq->umem);
+       else
+               mlx4_buf_free(dev->dev, entries * sizeof (struct mlx4_cqe),
+                             &cq->buf.buf);
+
+err_db:
+       if (!context)
+               mlx4_ib_db_free(dev, &cq->db);
+
+err_cq:
+       kfree(cq);
+
+       return ERR_PTR(err);
+}
+
+int mlx4_ib_destroy_cq(struct ib_cq *cq)
+{
+       struct mlx4_ib_dev *dev = to_mdev(cq->device);
+       struct mlx4_ib_cq *mcq = to_mcq(cq);
+
+       mlx4_cq_free(dev->dev, &mcq->mcq);
+       mlx4_mtt_cleanup(dev->dev, &mcq->buf.mtt);
+
+       if (cq->uobject) {
+               mlx4_ib_db_unmap_user(to_mucontext(cq->uobject->context), &mcq->db);
+               ib_umem_release(mcq->umem);
+       } else {
+               mlx4_buf_free(dev->dev, (cq->cqe + 1) * sizeof (struct mlx4_cqe),
+                             &mcq->buf.buf);
+               mlx4_ib_db_free(dev, &mcq->db);
+       }
+
+       kfree(mcq);
+
+       return 0;
+}
+
+static void dump_cqe(void *cqe)
+{
+       __be32 *buf = cqe;
+
+       printk(KERN_DEBUG "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+              be32_to_cpu(buf[0]), be32_to_cpu(buf[1]), be32_to_cpu(buf[2]),
+              be32_to_cpu(buf[3]), be32_to_cpu(buf[4]), be32_to_cpu(buf[5]),
+              be32_to_cpu(buf[6]), be32_to_cpu(buf[7]));
+}
+
+static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe,
+                                    struct ib_wc *wc)
+{
+       if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) {
+               printk(KERN_DEBUG "local QP operation err "
+                      "(QPN %06x, WQE index %x, vendor syndrome %02x, "
+                      "opcode = %02x)\n",
+                      be32_to_cpu(cqe->my_qpn), be16_to_cpu(cqe->wqe_index),
+                      cqe->vendor_err_syndrome,
+                      cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK);
+               dump_cqe(cqe);
+       }
+
+       switch (cqe->syndrome) {
+       case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR:
+               wc->status = IB_WC_LOC_LEN_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR:
+               wc->status = IB_WC_LOC_QP_OP_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR:
+               wc->status = IB_WC_LOC_PROT_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_WR_FLUSH_ERR:
+               wc->status = IB_WC_WR_FLUSH_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_MW_BIND_ERR:
+               wc->status = IB_WC_MW_BIND_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_BAD_RESP_ERR:
+               wc->status = IB_WC_BAD_RESP_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR:
+               wc->status = IB_WC_LOC_ACCESS_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR:
+               wc->status = IB_WC_REM_INV_REQ_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR:
+               wc->status = IB_WC_REM_ACCESS_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_REMOTE_OP_ERR:
+               wc->status = IB_WC_REM_OP_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR:
+               wc->status = IB_WC_RETRY_EXC_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR:
+               wc->status = IB_WC_RNR_RETRY_EXC_ERR;
+               break;
+       case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR:
+               wc->status = IB_WC_REM_ABORT_ERR;
+               break;
+       default:
+               wc->status = IB_WC_GENERAL_ERR;
+               break;
+       }
+
+       wc->vendor_err = cqe->vendor_err_syndrome;
+}
+
+static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
+                           struct mlx4_ib_qp **cur_qp,
+                           struct ib_wc *wc)
+{
+       struct mlx4_cqe *cqe;
+       struct mlx4_qp *mqp;
+       struct mlx4_ib_wq *wq;
+       struct mlx4_ib_srq *srq;
+       int is_send;
+       int is_error;
+       u16 wqe_ctr;
+
+       cqe = next_cqe_sw(cq);
+       if (!cqe)
+               return -EAGAIN;
+
+       ++cq->mcq.cons_index;
+
+       /*
+        * Make sure we read CQ entry contents after we've checked the
+        * ownership bit.
+        */
+       rmb();
+
+       is_send  = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK;
+       is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
+               MLX4_CQE_OPCODE_ERROR;
+
+       if (!*cur_qp ||
+           (be32_to_cpu(cqe->my_qpn) & 0xffffff) != (*cur_qp)->mqp.qpn) {
+               /*
+                * We do not have to take the QP table lock here,
+                * because CQs will be locked while QPs are removed
+                * from the table.
+                */
+               mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev,
+                                      be32_to_cpu(cqe->my_qpn));
+               if (unlikely(!mqp)) {
+                       printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n",
+                              cq->mcq.cqn, be32_to_cpu(cqe->my_qpn) & 0xffffff);
+                       return -EINVAL;
+               }
+
+               *cur_qp = to_mibqp(mqp);
+       }
+
+       wc->qp = &(*cur_qp)->ibqp;
+
+       if (is_send) {
+               wq = &(*cur_qp)->sq;
+               wqe_ctr = be16_to_cpu(cqe->wqe_index);
+               wq->tail += wqe_ctr - (u16) wq->tail;
+               wc->wr_id = wq->wrid[wq->tail & (wq->max - 1)];
+               ++wq->tail;
+       } else if ((*cur_qp)->ibqp.srq) {
+               srq = to_msrq((*cur_qp)->ibqp.srq);
+               wqe_ctr = be16_to_cpu(cqe->wqe_index);
+               wc->wr_id = srq->wrid[wqe_ctr];
+               mlx4_ib_free_srq_wqe(srq, wqe_ctr);
+       } else {
+               wq        = &(*cur_qp)->rq;
+               wc->wr_id = wq->wrid[wq->tail & (wq->max - 1)];
+               ++wq->tail;
+       }
+
+       if (unlikely(is_error)) {
+               mlx4_ib_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc);
+               return 0;
+       }
+
+       wc->status = IB_WC_SUCCESS;
+
+       if (is_send) {
+               wc->wc_flags = 0;
+               switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) {
+               case MLX4_OPCODE_RDMA_WRITE_IMM:
+                       wc->wc_flags |= IB_WC_WITH_IMM;
+               case MLX4_OPCODE_RDMA_WRITE:
+                       wc->opcode    = IB_WC_RDMA_WRITE;
+                       break;
+               case MLX4_OPCODE_SEND_IMM:
+                       wc->wc_flags |= IB_WC_WITH_IMM;
+               case MLX4_OPCODE_SEND:
+                       wc->opcode    = IB_WC_SEND;
+                       break;
+               case MLX4_OPCODE_RDMA_READ:
+                       wc->opcode    = IB_WC_SEND;
+                       wc->byte_len  = be32_to_cpu(cqe->byte_cnt);
+                       break;
+               case MLX4_OPCODE_ATOMIC_CS:
+                       wc->opcode    = IB_WC_COMP_SWAP;
+                       wc->byte_len  = 8;
+                       break;
+               case MLX4_OPCODE_ATOMIC_FA:
+                       wc->opcode    = IB_WC_FETCH_ADD;
+                       wc->byte_len  = 8;
+                       break;
+               case MLX4_OPCODE_BIND_MW:
+                       wc->opcode    = IB_WC_BIND_MW;
+                       break;
+               }
+       } else {
+               wc->byte_len = be32_to_cpu(cqe->byte_cnt);
+
+               switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) {
+               case MLX4_RECV_OPCODE_RDMA_WRITE_IMM:
+                       wc->opcode   = IB_WC_RECV_RDMA_WITH_IMM;
+                       wc->wc_flags = IB_WC_WITH_IMM;
+                       wc->imm_data = cqe->immed_rss_invalid;
+                       break;
+               case MLX4_RECV_OPCODE_SEND:
+                       wc->opcode   = IB_WC_RECV;
+                       wc->wc_flags = 0;
+                       break;
+               case MLX4_RECV_OPCODE_SEND_IMM:
+                       wc->opcode   = IB_WC_RECV;
+                       wc->wc_flags = IB_WC_WITH_IMM;
+                       wc->imm_data = cqe->immed_rss_invalid;
+                       break;
+               }
+
+               wc->slid           = be16_to_cpu(cqe->rlid);
+               wc->sl             = cqe->sl >> 4;
+               wc->src_qp         = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff;
+               wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f;
+               wc->wc_flags      |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ?
+                       IB_WC_GRH : 0;
+               wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) >> 16;
+       }
+
+       return 0;
+}
+
+int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+       struct mlx4_ib_cq *cq = to_mcq(ibcq);
+       struct mlx4_ib_qp *cur_qp = NULL;
+       unsigned long flags;
+       int npolled;
+       int err = 0;
+
+       spin_lock_irqsave(&cq->lock, flags);
+
+       for (npolled = 0; npolled < num_entries; ++npolled) {
+               err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled);
+               if (err)
+                       break;
+       }
+
+       if (npolled)
+               mlx4_cq_set_ci(&cq->mcq);
+
+       spin_unlock_irqrestore(&cq->lock, flags);
+
+       if (err == 0 || err == -EAGAIN)
+               return npolled;
+       else
+               return err;
+}
+
+int mlx4_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+       mlx4_cq_arm(&to_mcq(ibcq)->mcq,
+                   (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+                   MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT,
+                   to_mdev(ibcq->device)->uar_map,
+                   MLX4_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->uar_lock));
+
+       return 0;
+}
+
+void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq)
+{
+       u32 prod_index;
+       int nfreed = 0;
+       struct mlx4_cqe *cqe;
+
+       /*
+        * First we need to find the current producer index, so we
+        * know where to start cleaning from.  It doesn't matter if HW
+        * adds new entries after this loop -- the QP we're worried
+        * about is already in RESET, so the new entries won't come
+        * from our QP and therefore don't need to be checked.
+        */
+       for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); ++prod_index)
+               if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe)
+                       break;
+
+       /*
+        * Now sweep backwards through the CQ, removing CQ entries
+        * that match our QP by copying older entries on top of them.
+        */
+       while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) {
+               cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
+               if ((be32_to_cpu(cqe->my_qpn) & 0xffffff) == qpn) {
+                       if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK))
+                               mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index));
+                       ++nfreed;
+               } else if (nfreed)
+                       memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe),
+                              cqe, sizeof *cqe);
+       }
+
+       if (nfreed) {
+               cq->mcq.cons_index += nfreed;
+               /*
+                * Make sure update of buffer contents is done before
+                * updating consumer index.
+                */
+               wmb();
+               mlx4_cq_set_ci(&cq->mcq);
+       }
+}
+
+void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq)
+{
+       spin_lock_irq(&cq->lock);
+       __mlx4_ib_cq_clean(cq, qpn, srq);
+       spin_unlock_irq(&cq->lock);
+}
diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c
new file mode 100644 (file)
index 0000000..1c36087
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/slab.h>
+
+#include "mlx4_ib.h"
+
+struct mlx4_ib_db_pgdir {
+       struct list_head        list;
+       DECLARE_BITMAP(order0, MLX4_IB_DB_PER_PAGE);
+       DECLARE_BITMAP(order1, MLX4_IB_DB_PER_PAGE / 2);
+       unsigned long          *bits[2];
+       __be32                 *db_page;
+       dma_addr_t              db_dma;
+};
+
+static struct mlx4_ib_db_pgdir *mlx4_ib_alloc_db_pgdir(struct mlx4_ib_dev *dev)
+{
+       struct mlx4_ib_db_pgdir *pgdir;
+
+       pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL);
+       if (!pgdir)
+               return NULL;
+
+       bitmap_fill(pgdir->order1, MLX4_IB_DB_PER_PAGE / 2);
+       pgdir->bits[0] = pgdir->order0;
+       pgdir->bits[1] = pgdir->order1;
+       pgdir->db_page = dma_alloc_coherent(dev->ib_dev.dma_device,
+                                           PAGE_SIZE, &pgdir->db_dma,
+                                           GFP_KERNEL);
+       if (!pgdir->db_page) {
+               kfree(pgdir);
+               return NULL;
+       }
+
+       return pgdir;
+}
+
+static int mlx4_ib_alloc_db_from_pgdir(struct mlx4_ib_db_pgdir *pgdir,
+                                      struct mlx4_ib_db *db, int order)
+{
+       int o;
+       int i;
+
+       for (o = order; o <= 1; ++o) {
+               i = find_first_bit(pgdir->bits[o], MLX4_IB_DB_PER_PAGE >> o);
+               if (i < MLX4_IB_DB_PER_PAGE >> o)
+                       goto found;
+       }
+
+       return -ENOMEM;
+
+found:
+       clear_bit(i, pgdir->bits[o]);
+
+       i <<= o;
+
+       if (o > order)
+               set_bit(i ^ 1, pgdir->bits[order]);
+
+       db->u.pgdir = pgdir;
+       db->index   = i;
+       db->db      = pgdir->db_page + db->index;
+       db->dma     = pgdir->db_dma  + db->index * 4;
+       db->order   = order;
+
+       return 0;
+}
+
+int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order)
+{
+       struct mlx4_ib_db_pgdir *pgdir;
+       int ret = 0;
+
+       mutex_lock(&dev->pgdir_mutex);
+
+       list_for_each_entry(pgdir, &dev->pgdir_list, list)
+               if (!mlx4_ib_alloc_db_from_pgdir(pgdir, db, order))
+                       goto out;
+
+       pgdir = mlx4_ib_alloc_db_pgdir(dev);
+       if (!pgdir) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       list_add(&pgdir->list, &dev->pgdir_list);
+
+       /* This should never fail -- we just allocated an empty page: */
+       WARN_ON(mlx4_ib_alloc_db_from_pgdir(pgdir, db, order));
+
+out:
+       mutex_unlock(&dev->pgdir_mutex);
+
+       return ret;
+}
+
+void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db)
+{
+       int o;
+       int i;
+
+       mutex_lock(&dev->pgdir_mutex);
+
+       o = db->order;
+       i = db->index;
+
+       if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) {
+               clear_bit(i ^ 1, db->u.pgdir->order0);
+               ++o;
+       }
+
+       i >>= o;
+       set_bit(i, db->u.pgdir->bits[o]);
+
+       if (bitmap_full(db->u.pgdir->order1, MLX4_IB_DB_PER_PAGE / 2)) {
+               dma_free_coherent(dev->ib_dev.dma_device, PAGE_SIZE,
+                                 db->u.pgdir->db_page, db->u.pgdir->db_dma);
+               list_del(&db->u.pgdir->list);
+               kfree(db->u.pgdir);
+       }
+
+       mutex_unlock(&dev->pgdir_mutex);
+}
+
+struct mlx4_ib_user_db_page {
+       struct list_head        list;
+       struct ib_umem         *umem;
+       unsigned long           user_virt;
+       int                     refcnt;
+};
+
+int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
+                       struct mlx4_ib_db *db)
+{
+       struct mlx4_ib_user_db_page *page;
+       struct ib_umem_chunk *chunk;
+       int err = 0;
+
+       mutex_lock(&context->db_page_mutex);
+
+       list_for_each_entry(page, &context->db_page_list, list)
+               if (page->user_virt == (virt & PAGE_MASK))
+                       goto found;
+
+       page = kmalloc(sizeof *page, GFP_KERNEL);
+       if (!page) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       page->user_virt = (virt & PAGE_MASK);
+       page->refcnt    = 0;
+       page->umem      = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
+                                     PAGE_SIZE, 0);
+       if (IS_ERR(page->umem)) {
+               err = PTR_ERR(page->umem);
+               kfree(page);
+               goto out;
+       }
+
+       list_add(&page->list, &context->db_page_list);
+
+found:
+       chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list);
+       db->dma         = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK);
+       db->u.user_page = page;
+       ++page->refcnt;
+
+out:
+       mutex_unlock(&context->db_page_mutex);
+
+       return err;
+}
+
+void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db)
+{
+       mutex_lock(&context->db_page_mutex);
+
+       if (!--db->u.user_page->refcnt) {
+               list_del(&db->u.user_page->list);
+               ib_umem_release(db->u.user_page->umem);
+               kfree(db->u.user_page);
+       }
+
+       mutex_unlock(&context->db_page_mutex);
+}
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
new file mode 100644 (file)
index 0000000..3330917
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <rdma/ib_mad.h>
+#include <rdma/ib_smi.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4_ib.h"
+
+enum {
+       MLX4_IB_VENDOR_CLASS1 = 0x9,
+       MLX4_IB_VENDOR_CLASS2 = 0xa
+};
+
+int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+                int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+                void *in_mad, void *response_mad)
+{
+       struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
+       void *inbox;
+       int err;
+       u32 in_modifier = port;
+       u8 op_modifier = 0;
+
+       inmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
+       if (IS_ERR(inmailbox))
+               return PTR_ERR(inmailbox);
+       inbox = inmailbox->buf;
+
+       outmailbox = mlx4_alloc_cmd_mailbox(dev->dev);
+       if (IS_ERR(outmailbox)) {
+               mlx4_free_cmd_mailbox(dev->dev, inmailbox);
+               return PTR_ERR(outmailbox);
+       }
+
+       memcpy(inbox, in_mad, 256);
+
+       /*
+        * Key check traps can't be generated unless we have in_wc to
+        * tell us where to send the trap.
+        */
+       if (ignore_mkey || !in_wc)
+               op_modifier |= 0x1;
+       if (ignore_bkey || !in_wc)
+               op_modifier |= 0x2;
+
+       if (in_wc) {
+               struct {
+                       __be32          my_qpn;
+                       u32             reserved1;
+                       __be32          rqpn;
+                       u8              sl;
+                       u8              g_path;
+                       u16             reserved2[2];
+                       __be16          pkey;
+                       u32             reserved3[11];
+                       u8              grh[40];
+               } *ext_info;
+
+               memset(inbox + 256, 0, 256);
+               ext_info = inbox + 256;
+
+               ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num);
+               ext_info->rqpn   = cpu_to_be32(in_wc->src_qp);
+               ext_info->sl     = in_wc->sl << 4;
+               ext_info->g_path = in_wc->dlid_path_bits |
+                       (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
+               ext_info->pkey   = cpu_to_be16(in_wc->pkey_index);
+
+               if (in_grh)
+                       memcpy(ext_info->grh, in_grh, 40);
+
+               op_modifier |= 0x4;
+
+               in_modifier |= in_wc->slid << 16;
+       }
+
+       err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma,
+                          in_modifier, op_modifier,
+                          MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
+
+       if (!err);
+               memcpy(response_mad, outmailbox->buf, 256);
+
+       mlx4_free_cmd_mailbox(dev->dev, inmailbox);
+       mlx4_free_cmd_mailbox(dev->dev, outmailbox);
+
+       return err;
+}
+
+static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
+{
+       struct ib_ah *new_ah;
+       struct ib_ah_attr ah_attr;
+
+       if (!dev->send_agent[port_num - 1][0])
+               return;
+
+       memset(&ah_attr, 0, sizeof ah_attr);
+       ah_attr.dlid     = lid;
+       ah_attr.sl       = sl;
+       ah_attr.port_num = port_num;
+
+       new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd,
+                             &ah_attr);
+       if (IS_ERR(new_ah))
+               return;
+
+       spin_lock(&dev->sm_lock);
+       if (dev->sm_ah[port_num - 1])
+               ib_destroy_ah(dev->sm_ah[port_num - 1]);
+       dev->sm_ah[port_num - 1] = new_ah;
+       spin_unlock(&dev->sm_lock);
+}
+
+/*
+ * Snoop SM MADs for port info and P_Key table sets, so we can
+ * synthesize LID change and P_Key change events.
+ */
+static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad)
+{
+       struct ib_event event;
+
+       if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+            mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+           mad->mad_hdr.method == IB_MGMT_METHOD_SET) {
+               if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) {
+                       struct ib_port_info *pinfo =
+                               (struct ib_port_info *) ((struct ib_smp *) mad)->data;
+
+                       update_sm_ah(to_mdev(ibdev), port_num,
+                                    be16_to_cpu(pinfo->sm_lid),
+                                    pinfo->neighbormtu_mastersmsl & 0xf);
+
+                       event.device           = ibdev;
+                       event.element.port_num = port_num;
+
+                       if(pinfo->clientrereg_resv_subnetto & 0x80)
+                               event.event    = IB_EVENT_CLIENT_REREGISTER;
+                       else
+                               event.event    = IB_EVENT_LID_CHANGE;
+
+                       ib_dispatch_event(&event);
+               }
+
+               if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) {
+                       event.device           = ibdev;
+                       event.event            = IB_EVENT_PKEY_CHANGE;
+                       event.element.port_num = port_num;
+                       ib_dispatch_event(&event);
+               }
+       }
+}
+
+static void node_desc_override(struct ib_device *dev,
+                              struct ib_mad *mad)
+{
+       if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+            mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
+           mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
+           mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
+               spin_lock(&to_mdev(dev)->sm_lock);
+               memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
+               spin_unlock(&to_mdev(dev)->sm_lock);
+       }
+}
+
+static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad)
+{
+       int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED;
+       struct ib_mad_send_buf *send_buf;
+       struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
+       int ret;
+
+       if (agent) {
+               send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
+                                             IB_MGMT_MAD_DATA, GFP_ATOMIC);
+               /*
+                * We rely here on the fact that MLX QPs don't use the
+                * address handle after the send is posted (this is
+                * wrong following the IB spec strictly, but we know
+                * it's OK for our devices).
+                */
+               spin_lock(&dev->sm_lock);
+               memcpy(send_buf->mad, mad, sizeof *mad);
+               if ((send_buf->ah = dev->sm_ah[port_num - 1]))
+                       ret = ib_post_send_mad(send_buf, NULL);
+               else
+                       ret = -EINVAL;
+               spin_unlock(&dev->sm_lock);
+
+               if (ret)
+                       ib_free_send_mad(send_buf);
+       }
+}
+
+int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags,        u8 port_num,
+                       struct ib_wc *in_wc, struct ib_grh *in_grh,
+                       struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+       u16 slid;
+       int err;
+
+       slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE);
+
+       if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) {
+               forward_trap(to_mdev(ibdev), port_num, in_mad);
+               return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+       }
+
+       if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
+           in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+               if (in_mad->mad_hdr.method   != IB_MGMT_METHOD_GET &&
+                   in_mad->mad_hdr.method   != IB_MGMT_METHOD_SET &&
+                   in_mad->mad_hdr.method   != IB_MGMT_METHOD_TRAP_REPRESS)
+                       return IB_MAD_RESULT_SUCCESS;
+
+               /*
+                * Don't process SMInfo queries or vendor-specific
+                * MADs -- the SMA can't handle them.
+                */
+               if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO ||
+                   ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) ==
+                    IB_SMP_ATTR_VENDOR_MASK))
+                       return IB_MAD_RESULT_SUCCESS;
+       } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT ||
+                  in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1   ||
+                  in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2) {
+               if (in_mad->mad_hdr.method  != IB_MGMT_METHOD_GET &&
+                   in_mad->mad_hdr.method  != IB_MGMT_METHOD_SET)
+                       return IB_MAD_RESULT_SUCCESS;
+       } else
+               return IB_MAD_RESULT_SUCCESS;
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev),
+                          mad_flags & IB_MAD_IGNORE_MKEY,
+                          mad_flags & IB_MAD_IGNORE_BKEY,
+                          port_num, in_wc, in_grh, in_mad, out_mad);
+       if (err)
+               return IB_MAD_RESULT_FAILURE;
+
+       if (!out_mad->mad_hdr.status) {
+               smp_snoop(ibdev, port_num, in_mad);
+               node_desc_override(ibdev, out_mad);
+       }
+
+       /* set return bit in status of directed route responses */
+       if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+               out_mad->mad_hdr.status |= cpu_to_be16(1 << 15);
+
+       if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS)
+               /* no response for trap repress */
+               return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
+
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+}
+
+static void send_handler(struct ib_mad_agent *agent,
+                        struct ib_mad_send_wc *mad_send_wc)
+{
+       ib_free_send_mad(mad_send_wc->send_buf);
+}
+
+int mlx4_ib_mad_init(struct mlx4_ib_dev *dev)
+{
+       struct ib_mad_agent *agent;
+       int p, q;
+       int ret;
+
+       for (p = 0; p < dev->dev->caps.num_ports; ++p)
+               for (q = 0; q <= 1; ++q) {
+                       agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
+                                                     q ? IB_QPT_GSI : IB_QPT_SMI,
+                                                     NULL, 0, send_handler,
+                                                     NULL, NULL);
+                       if (IS_ERR(agent)) {
+                               ret = PTR_ERR(agent);
+                               goto err;
+                       }
+                       dev->send_agent[p][q] = agent;
+               }
+
+       return 0;
+
+err:
+       for (p = 0; p < dev->dev->caps.num_ports; ++p)
+               for (q = 0; q <= 1; ++q)
+                       if (dev->send_agent[p][q])
+                               ib_unregister_mad_agent(dev->send_agent[p][q]);
+
+       return ret;
+}
+
+void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
+{
+       struct ib_mad_agent *agent;
+       int p, q;
+
+       for (p = 0; p < dev->dev->caps.num_ports; ++p) {
+               for (q = 0; q <= 1; ++q) {
+                       agent = dev->send_agent[p][q];
+                       dev->send_agent[p][q] = NULL;
+                       ib_unregister_mad_agent(agent);
+               }
+
+               if (dev->sm_ah[p])
+                       ib_destroy_ah(dev->sm_ah[p]);
+       }
+}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
new file mode 100644 (file)
index 0000000..688ecb4
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_user_verbs.h>
+
+#include <linux/mlx4/driver.h>
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4_ib.h"
+#include "user.h"
+
+#define DRV_NAME       "mlx4_ib"
+#define DRV_VERSION    "0.01"
+#define DRV_RELDATE    "May 1, 2006"
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const char mlx4_ib_version[] __devinitdata =
+       DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
+       DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static void init_query_mad(struct ib_smp *mad)
+{
+       mad->base_version  = 1;
+       mad->mgmt_class    = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+       mad->class_version = 1;
+       mad->method        = IB_MGMT_METHOD_GET;
+}
+
+static int mlx4_ib_query_device(struct ib_device *ibdev,
+                               struct ib_device_attr *props)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memset(props, 0, sizeof *props);
+
+       props->fw_ver = dev->dev->caps.fw_ver;
+       props->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT |
+               IB_DEVICE_PORT_ACTIVE_EVENT             |
+               IB_DEVICE_SYS_IMAGE_GUID                |
+               IB_DEVICE_RC_RNR_NAK_GEN;
+       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR)
+               props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
+       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR)
+               props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
+       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_APM)
+               props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
+       if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT)
+               props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
+
+       props->vendor_id           = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
+               0xffffff;
+       props->vendor_part_id      = be16_to_cpup((__be16 *) (out_mad->data + 30));
+       props->hw_ver              = be32_to_cpup((__be32 *) (out_mad->data + 32));
+       memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
+
+       props->max_mr_size         = ~0ull;
+       props->page_size_cap       = dev->dev->caps.page_size_cap;
+       props->max_qp              = dev->dev->caps.num_qps - dev->dev->caps.reserved_qps;
+       props->max_qp_wr           = dev->dev->caps.max_wqes;
+       props->max_sge             = min(dev->dev->caps.max_sq_sg,
+                                        dev->dev->caps.max_rq_sg);
+       props->max_cq              = dev->dev->caps.num_cqs - dev->dev->caps.reserved_cqs;
+       props->max_cqe             = dev->dev->caps.max_cqes;
+       props->max_mr              = dev->dev->caps.num_mpts - dev->dev->caps.reserved_mrws;
+       props->max_pd              = dev->dev->caps.num_pds - dev->dev->caps.reserved_pds;
+       props->max_qp_rd_atom      = dev->dev->caps.max_qp_dest_rdma;
+       props->max_qp_init_rd_atom = dev->dev->caps.max_qp_init_rdma;
+       props->max_res_rd_atom     = props->max_qp_rd_atom * props->max_qp;
+       props->max_srq             = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs;
+       props->max_srq_wr          = dev->dev->caps.max_srq_wqes;
+       props->max_srq_sge         = dev->dev->caps.max_srq_sge;
+       props->local_ca_ack_delay  = dev->dev->caps.local_ca_ack_delay;
+       props->atomic_cap          = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
+               IB_ATOMIC_HCA : IB_ATOMIC_NONE;
+       props->max_pkeys           = dev->dev->caps.pkey_table_len;
+       props->max_mcast_grp       = dev->dev->caps.num_mgms + dev->dev->caps.num_amgms;
+       props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm;
+       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
+                                          props->max_mcast_grp;
+       props->max_map_per_fmr = (1 << (32 - ilog2(dev->dev->caps.num_mpts))) - 1;
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+
+       return err;
+}
+
+static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
+                             struct ib_port_attr *props)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       memset(props, 0, sizeof *props);
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       props->lid              = be16_to_cpup((__be16 *) (out_mad->data + 16));
+       props->lmc              = out_mad->data[34] & 0x7;
+       props->sm_lid           = be16_to_cpup((__be16 *) (out_mad->data + 18));
+       props->sm_sl            = out_mad->data[36] & 0xf;
+       props->state            = out_mad->data[32] & 0xf;
+       props->phys_state       = out_mad->data[33] >> 4;
+       props->port_cap_flags   = be32_to_cpup((__be32 *) (out_mad->data + 20));
+       props->gid_tbl_len      = to_mdev(ibdev)->dev->caps.gid_table_len;
+       props->max_msg_sz       = 0x80000000;
+       props->pkey_tbl_len     = to_mdev(ibdev)->dev->caps.pkey_table_len;
+       props->bad_pkey_cntr    = be16_to_cpup((__be16 *) (out_mad->data + 46));
+       props->qkey_viol_cntr   = be16_to_cpup((__be16 *) (out_mad->data + 48));
+       props->active_width     = out_mad->data[31] & 0xf;
+       props->active_speed     = out_mad->data[35] >> 4;
+       props->max_mtu          = out_mad->data[41] & 0xf;
+       props->active_mtu       = out_mad->data[36] >> 4;
+       props->subnet_timeout   = out_mad->data[51] & 0x1f;
+       props->max_vl_num       = out_mad->data[37] >> 4;
+       props->init_type_reply  = out_mad->data[41] >> 4;
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+
+       return err;
+}
+
+static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+                            union ib_gid *gid)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(gid->raw, out_mad->data + 8, 8);
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
+       in_mad->attr_mod = cpu_to_be32(index / 8);
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
+                             u16 *pkey)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
+       in_mad->attr_mod = cpu_to_be32(index / 32);
+
+       err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
+                                struct ib_device_modify *props)
+{
+       if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
+               return -EOPNOTSUPP;
+
+       if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
+               spin_lock(&to_mdev(ibdev)->sm_lock);
+               memcpy(ibdev->node_desc, props->node_desc, 64);
+               spin_unlock(&to_mdev(ibdev)->sm_lock);
+       }
+
+       return 0;
+}
+
+static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols,
+                        u32 cap_mask)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       memset(mailbox->buf, 0, 256);
+       *(u8 *) mailbox->buf         = !!reset_qkey_viols << 6;
+       ((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask);
+
+       err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
+                      MLX4_CMD_TIME_CLASS_B);
+
+       mlx4_free_cmd_mailbox(dev->dev, mailbox);
+       return err;
+}
+
+static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask,
+                              struct ib_port_modify *props)
+{
+       struct ib_port_attr attr;
+       u32 cap_mask;
+       int err;
+
+       mutex_lock(&to_mdev(ibdev)->cap_mask_mutex);
+
+       err = mlx4_ib_query_port(ibdev, port, &attr);
+       if (err)
+               goto out;
+
+       cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &
+               ~props->clr_port_cap_mask;
+
+       err = mlx4_SET_PORT(to_mdev(ibdev), port,
+                           !!(mask & IB_PORT_RESET_QKEY_CNTR),
+                           cap_mask);
+
+out:
+       mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
+       return err;
+}
+
+static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev,
+                                                 struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibdev);
+       struct mlx4_ib_ucontext *context;
+       struct mlx4_ib_alloc_ucontext_resp resp;
+       int err;
+
+       resp.qp_tab_size      = dev->dev->caps.num_qps;
+       resp.bf_reg_size      = dev->dev->caps.bf_reg_size;
+       resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page;
+
+       context = kmalloc(sizeof *context, GFP_KERNEL);
+       if (!context)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx4_uar_alloc(to_mdev(ibdev)->dev, &context->uar);
+       if (err) {
+               kfree(context);
+               return ERR_PTR(err);
+       }
+
+       INIT_LIST_HEAD(&context->db_page_list);
+       mutex_init(&context->db_page_mutex);
+
+       err = ib_copy_to_udata(udata, &resp, sizeof resp);
+       if (err) {
+               mlx4_uar_free(to_mdev(ibdev)->dev, &context->uar);
+               kfree(context);
+               return ERR_PTR(-EFAULT);
+       }
+
+       return &context->ibucontext;
+}
+
+static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+       struct mlx4_ib_ucontext *context = to_mucontext(ibcontext);
+
+       mlx4_uar_free(to_mdev(ibcontext->device)->dev, &context->uar);
+       kfree(context);
+
+       return 0;
+}
+
+static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+       struct mlx4_ib_dev *dev = to_mdev(context->device);
+
+       if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+               return -EINVAL;
+
+       if (vma->vm_pgoff == 0) {
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+               if (io_remap_pfn_range(vma, vma->vm_start,
+                                      to_mucontext(context)->uar.pfn,
+                                      PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+       } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) {
+               /* FIXME want pgprot_writecombine() for BlueFlame pages */
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+               if (io_remap_pfn_range(vma, vma->vm_start,
+                                      to_mucontext(context)->uar.pfn +
+                                      dev->dev->caps.num_uars,
+                                      PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev,
+                                     struct ib_ucontext *context,
+                                     struct ib_udata *udata)
+{
+       struct mlx4_ib_pd *pd;
+       int err;
+
+       pd = kmalloc(sizeof *pd, GFP_KERNEL);
+       if (!pd)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx4_pd_alloc(to_mdev(ibdev)->dev, &pd->pdn);
+       if (err) {
+               kfree(pd);
+               return ERR_PTR(err);
+       }
+
+       if (context)
+               if (ib_copy_to_udata(udata, &pd->pdn, sizeof (__u32))) {
+                       mlx4_pd_free(to_mdev(ibdev)->dev, pd->pdn);
+                       kfree(pd);
+                       return ERR_PTR(-EFAULT);
+               }
+
+       return &pd->ibpd;
+}
+
+static int mlx4_ib_dealloc_pd(struct ib_pd *pd)
+{
+       mlx4_pd_free(to_mdev(pd->device)->dev, to_mpd(pd)->pdn);
+       kfree(pd);
+
+       return 0;
+}
+
+static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       return mlx4_multicast_attach(to_mdev(ibqp->device)->dev,
+                                    &to_mqp(ibqp)->mqp, gid->raw);
+}
+
+static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+       return mlx4_multicast_detach(to_mdev(ibqp->device)->dev,
+                                    &to_mqp(ibqp)->mqp, gid->raw);
+}
+
+static int init_node_data(struct mlx4_ib_dev *dev)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
+
+       err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(dev->ib_dev.node_desc, out_mad->data, 64);
+
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+       err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad);
+       if (err)
+               goto out;
+
+       memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
+static void *mlx4_ib_add(struct mlx4_dev *dev)
+{
+       struct mlx4_ib_dev *ibdev;
+
+       ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
+       if (!ibdev) {
+               dev_err(&dev->pdev->dev, "Device struct alloc failed\n");
+               return NULL;
+       }
+
+       if (mlx4_pd_alloc(dev, &ibdev->priv_pdn))
+               goto err_dealloc;
+
+       if (mlx4_uar_alloc(dev, &ibdev->priv_uar))
+               goto err_pd;
+
+       ibdev->uar_map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+       if (!ibdev->uar_map)
+               goto err_uar;
+
+       INIT_LIST_HEAD(&ibdev->pgdir_list);
+       mutex_init(&ibdev->pgdir_mutex);
+
+       ibdev->dev = dev;
+
+       strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX);
+       ibdev->ib_dev.owner             = THIS_MODULE;
+       ibdev->ib_dev.node_type         = RDMA_NODE_IB_CA;
+       ibdev->ib_dev.phys_port_cnt     = dev->caps.num_ports;
+       ibdev->ib_dev.num_comp_vectors  = 1;
+       ibdev->ib_dev.dma_device        = &dev->pdev->dev;
+
+       ibdev->ib_dev.uverbs_abi_ver    = MLX4_IB_UVERBS_ABI_VERSION;
+       ibdev->ib_dev.uverbs_cmd_mask   =
+               (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
+               (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
+               (1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
+               (1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
+               (1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
+               (1ull << IB_USER_VERBS_CMD_REG_MR)              |
+               (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
+               (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+               (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
+               (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
+               (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
+               (1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
+               (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
+
+       ibdev->ib_dev.query_device      = mlx4_ib_query_device;
+       ibdev->ib_dev.query_port        = mlx4_ib_query_port;
+       ibdev->ib_dev.query_gid         = mlx4_ib_query_gid;
+       ibdev->ib_dev.query_pkey        = mlx4_ib_query_pkey;
+       ibdev->ib_dev.modify_device     = mlx4_ib_modify_device;
+       ibdev->ib_dev.modify_port       = mlx4_ib_modify_port;
+       ibdev->ib_dev.alloc_ucontext    = mlx4_ib_alloc_ucontext;
+       ibdev->ib_dev.dealloc_ucontext  = mlx4_ib_dealloc_ucontext;
+       ibdev->ib_dev.mmap              = mlx4_ib_mmap;
+       ibdev->ib_dev.alloc_pd          = mlx4_ib_alloc_pd;
+       ibdev->ib_dev.dealloc_pd        = mlx4_ib_dealloc_pd;
+       ibdev->ib_dev.create_ah         = mlx4_ib_create_ah;
+       ibdev->ib_dev.query_ah          = mlx4_ib_query_ah;
+       ibdev->ib_dev.destroy_ah        = mlx4_ib_destroy_ah;
+       ibdev->ib_dev.create_srq        = mlx4_ib_create_srq;
+       ibdev->ib_dev.modify_srq        = mlx4_ib_modify_srq;
+       ibdev->ib_dev.destroy_srq       = mlx4_ib_destroy_srq;
+       ibdev->ib_dev.post_srq_recv     = mlx4_ib_post_srq_recv;
+       ibdev->ib_dev.create_qp         = mlx4_ib_create_qp;
+       ibdev->ib_dev.modify_qp         = mlx4_ib_modify_qp;
+       ibdev->ib_dev.destroy_qp        = mlx4_ib_destroy_qp;
+       ibdev->ib_dev.post_send         = mlx4_ib_post_send;
+       ibdev->ib_dev.post_recv         = mlx4_ib_post_recv;
+       ibdev->ib_dev.create_cq         = mlx4_ib_create_cq;
+       ibdev->ib_dev.destroy_cq        = mlx4_ib_destroy_cq;
+       ibdev->ib_dev.poll_cq           = mlx4_ib_poll_cq;
+       ibdev->ib_dev.req_notify_cq     = mlx4_ib_arm_cq;
+       ibdev->ib_dev.get_dma_mr        = mlx4_ib_get_dma_mr;
+       ibdev->ib_dev.reg_user_mr       = mlx4_ib_reg_user_mr;
+       ibdev->ib_dev.dereg_mr          = mlx4_ib_dereg_mr;
+       ibdev->ib_dev.attach_mcast      = mlx4_ib_mcg_attach;
+       ibdev->ib_dev.detach_mcast      = mlx4_ib_mcg_detach;
+       ibdev->ib_dev.process_mad       = mlx4_ib_process_mad;
+
+       if (init_node_data(ibdev))
+               goto err_map;
+
+       spin_lock_init(&ibdev->sm_lock);
+       mutex_init(&ibdev->cap_mask_mutex);
+
+       if (ib_register_device(&ibdev->ib_dev))
+               goto err_map;
+
+       if (mlx4_ib_mad_init(ibdev))
+               goto err_reg;
+
+       return ibdev;
+
+err_reg:
+       ib_unregister_device(&ibdev->ib_dev);
+
+err_map:
+       iounmap(ibdev->uar_map);
+
+err_uar:
+       mlx4_uar_free(dev, &ibdev->priv_uar);
+
+err_pd:
+       mlx4_pd_free(dev, ibdev->priv_pdn);
+
+err_dealloc:
+       ib_dealloc_device(&ibdev->ib_dev);
+
+       return NULL;
+}
+
+static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
+{
+       struct mlx4_ib_dev *ibdev = ibdev_ptr;
+       int p;
+
+       for (p = 1; p <= dev->caps.num_ports; ++p)
+               mlx4_CLOSE_PORT(dev, p);
+
+       mlx4_ib_mad_cleanup(ibdev);
+       ib_unregister_device(&ibdev->ib_dev);
+       iounmap(ibdev->uar_map);
+       mlx4_uar_free(dev, &ibdev->priv_uar);
+       mlx4_pd_free(dev, ibdev->priv_pdn);
+       ib_dealloc_device(&ibdev->ib_dev);
+}
+
+static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
+                         enum mlx4_dev_event event, int subtype,
+                         int port)
+{
+       struct ib_event ibev;
+
+       switch (event) {
+       case MLX4_EVENT_TYPE_PORT_CHANGE:
+               ibev.event = subtype == MLX4_PORT_CHANGE_SUBTYPE_ACTIVE ?
+                       IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
+               break;
+
+       case MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR:
+               ibev.event = IB_EVENT_DEVICE_FATAL;
+               break;
+
+       default:
+               return;
+       }
+
+       ibev.device           = ibdev_ptr;
+       ibev.element.port_num = port;
+
+       ib_dispatch_event(&ibev);
+}
+
+static struct mlx4_interface mlx4_ib_interface = {
+       .add    = mlx4_ib_add,
+       .remove = mlx4_ib_remove,
+       .event  = mlx4_ib_event
+};
+
+static int __init mlx4_ib_init(void)
+{
+       return mlx4_register_interface(&mlx4_ib_interface);
+}
+
+static void __exit mlx4_ib_cleanup(void)
+{
+       mlx4_unregister_interface(&mlx4_ib_interface);
+}
+
+module_init(mlx4_ib_init);
+module_exit(mlx4_ib_cleanup);
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
new file mode 100644 (file)
index 0000000..93dac71
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_IB_H
+#define MLX4_IB_H
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/doorbell.h>
+
+enum {
+       MLX4_IB_DB_PER_PAGE     = PAGE_SIZE / 4
+};
+
+struct mlx4_ib_db_pgdir;
+struct mlx4_ib_user_db_page;
+
+struct mlx4_ib_db {
+       __be32                 *db;
+       union {
+               struct mlx4_ib_db_pgdir        *pgdir;
+               struct mlx4_ib_user_db_page    *user_page;
+       }                       u;
+       dma_addr_t              dma;
+       int                     index;
+       int                     order;
+};
+
+struct mlx4_ib_ucontext {
+       struct ib_ucontext      ibucontext;
+       struct mlx4_uar         uar;
+       struct list_head        db_page_list;
+       struct mutex            db_page_mutex;
+};
+
+struct mlx4_ib_pd {
+       struct ib_pd            ibpd;
+       u32                     pdn;
+};
+
+struct mlx4_ib_cq_buf {
+       struct mlx4_buf         buf;
+       struct mlx4_mtt         mtt;
+};
+
+struct mlx4_ib_cq {
+       struct ib_cq            ibcq;
+       struct mlx4_cq          mcq;
+       struct mlx4_ib_cq_buf   buf;
+       struct mlx4_ib_db       db;
+       spinlock_t              lock;
+       struct ib_umem         *umem;
+};
+
+struct mlx4_ib_mr {
+       struct ib_mr            ibmr;
+       struct mlx4_mr          mmr;
+       struct ib_umem         *umem;
+};
+
+struct mlx4_ib_wq {
+       u64                    *wrid;
+       spinlock_t              lock;
+       int                     max;
+       int                     max_gs;
+       int                     offset;
+       int                     wqe_shift;
+       unsigned                head;
+       unsigned                tail;
+};
+
+struct mlx4_ib_qp {
+       struct ib_qp            ibqp;
+       struct mlx4_qp          mqp;
+       struct mlx4_buf         buf;
+
+       struct mlx4_ib_db       db;
+       struct mlx4_ib_wq       rq;
+
+       u32                     doorbell_qpn;
+       __be32                  sq_signal_bits;
+       struct mlx4_ib_wq       sq;
+
+       struct ib_umem         *umem;
+       struct mlx4_mtt         mtt;
+       int                     buf_size;
+       struct mutex            mutex;
+       u8                      port;
+       u8                      alt_port;
+       u8                      atomic_rd_en;
+       u8                      resp_depth;
+       u8                      state;
+};
+
+struct mlx4_ib_srq {
+       struct ib_srq           ibsrq;
+       struct mlx4_srq         msrq;
+       struct mlx4_buf         buf;
+       struct mlx4_ib_db       db;
+       u64                    *wrid;
+       spinlock_t              lock;
+       int                     head;
+       int                     tail;
+       u16                     wqe_ctr;
+       struct ib_umem         *umem;
+       struct mlx4_mtt         mtt;
+       struct mutex            mutex;
+};
+
+struct mlx4_ib_ah {
+       struct ib_ah            ibah;
+       struct mlx4_av          av;
+};
+
+struct mlx4_ib_dev {
+       struct ib_device        ib_dev;
+       struct mlx4_dev        *dev;
+       void __iomem           *uar_map;
+
+       struct list_head        pgdir_list;
+       struct mutex            pgdir_mutex;
+
+       struct mlx4_uar         priv_uar;
+       u32                     priv_pdn;
+       MLX4_DECLARE_DOORBELL_LOCK(uar_lock);
+
+       struct ib_mad_agent    *send_agent[MLX4_MAX_PORTS][2];
+       struct ib_ah           *sm_ah[MLX4_MAX_PORTS];
+       spinlock_t              sm_lock;
+
+       struct mutex            cap_mask_mutex;
+};
+
+static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev)
+{
+       return container_of(ibdev, struct mlx4_ib_dev, ib_dev);
+}
+
+static inline struct mlx4_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+       return container_of(ibucontext, struct mlx4_ib_ucontext, ibucontext);
+}
+
+static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd)
+{
+       return container_of(ibpd, struct mlx4_ib_pd, ibpd);
+}
+
+static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq)
+{
+       return container_of(ibcq, struct mlx4_ib_cq, ibcq);
+}
+
+static inline struct mlx4_ib_cq *to_mibcq(struct mlx4_cq *mcq)
+{
+       return container_of(mcq, struct mlx4_ib_cq, mcq);
+}
+
+static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr)
+{
+       return container_of(ibmr, struct mlx4_ib_mr, ibmr);
+}
+
+static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp)
+{
+       return container_of(ibqp, struct mlx4_ib_qp, ibqp);
+}
+
+static inline struct mlx4_ib_qp *to_mibqp(struct mlx4_qp *mqp)
+{
+       return container_of(mqp, struct mlx4_ib_qp, mqp);
+}
+
+static inline struct mlx4_ib_srq *to_msrq(struct ib_srq *ibsrq)
+{
+       return container_of(ibsrq, struct mlx4_ib_srq, ibsrq);
+}
+
+static inline struct mlx4_ib_srq *to_mibsrq(struct mlx4_srq *msrq)
+{
+       return container_of(msrq, struct mlx4_ib_srq, msrq);
+}
+
+static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah)
+{
+       return container_of(ibah, struct mlx4_ib_ah, ibah);
+}
+
+int mlx4_ib_db_alloc(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db, int order);
+void mlx4_ib_db_free(struct mlx4_ib_dev *dev, struct mlx4_ib_db *db);
+int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt,
+                       struct mlx4_ib_db *db);
+void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_ib_db *db);
+
+struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc);
+int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
+                          struct ib_umem *umem);
+struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                 u64 virt_addr, int access_flags,
+                                 struct ib_udata *udata);
+int mlx4_ib_dereg_mr(struct ib_mr *mr);
+
+struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector,
+                               struct ib_ucontext *context,
+                               struct ib_udata *udata);
+int mlx4_ib_destroy_cq(struct ib_cq *cq);
+int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
+void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq);
+void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq);
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr);
+int mlx4_ib_destroy_ah(struct ib_ah *ah);
+
+struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
+                                 struct ib_srq_init_attr *init_attr,
+                                 struct ib_udata *udata);
+int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                      enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+int mlx4_ib_destroy_srq(struct ib_srq *srq);
+void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index);
+int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                         struct ib_recv_wr **bad_wr);
+
+struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
+                               struct ib_qp_init_attr *init_attr,
+                               struct ib_udata *udata);
+int mlx4_ib_destroy_qp(struct ib_qp *qp);
+int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                     int attr_mask, struct ib_udata *udata);
+int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                     struct ib_send_wr **bad_wr);
+int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                     struct ib_recv_wr **bad_wr);
+
+int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey,
+                int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
+                void *in_mad, void *response_mad);
+int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags,        u8 port_num,
+                       struct ib_wc *in_wc, struct ib_grh *in_grh,
+                       struct ib_mad *in_mad, struct ib_mad *out_mad);
+int mlx4_ib_mad_init(struct mlx4_ib_dev *dev);
+void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev);
+
+static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
+{
+       return !!(ah->av.g_slid & 0x80);
+}
+
+#endif /* MLX4_IB_H */
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
new file mode 100644 (file)
index 0000000..85ae906
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx4_ib.h"
+
+static u32 convert_access(int acc)
+{
+       return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX4_PERM_ATOMIC       : 0) |
+              (acc & IB_ACCESS_REMOTE_WRITE  ? MLX4_PERM_REMOTE_WRITE : 0) |
+              (acc & IB_ACCESS_REMOTE_READ   ? MLX4_PERM_REMOTE_READ  : 0) |
+              (acc & IB_ACCESS_LOCAL_WRITE   ? MLX4_PERM_LOCAL_WRITE  : 0) |
+              MLX4_PERM_LOCAL_READ;
+}
+
+struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc)
+{
+       struct mlx4_ib_mr *mr;
+       int err;
+
+       mr = kmalloc(sizeof *mr, GFP_KERNEL);
+       if (!mr)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx4_mr_alloc(to_mdev(pd->device)->dev, to_mpd(pd)->pdn, 0,
+                           ~0ull, convert_access(acc), 0, 0, &mr->mmr);
+       if (err)
+               goto err_free;
+
+       err = mlx4_mr_enable(to_mdev(pd->device)->dev, &mr->mmr);
+       if (err)
+               goto err_mr;
+
+       mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key;
+       mr->umem = NULL;
+
+       return &mr->ibmr;
+
+err_mr:
+       mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr);
+
+err_free:
+       kfree(mr);
+
+       return ERR_PTR(err);
+}
+
+int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
+                          struct ib_umem *umem)
+{
+       u64 *pages;
+       struct ib_umem_chunk *chunk;
+       int i, j, k;
+       int n;
+       int len;
+       int err = 0;
+
+       pages = (u64 *) __get_free_page(GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       i = n = 0;
+
+       list_for_each_entry(chunk, &umem->chunk_list, list)
+               for (j = 0; j < chunk->nmap; ++j) {
+                       len = sg_dma_len(&chunk->page_list[j]) >> mtt->page_shift;
+                       for (k = 0; k < len; ++k) {
+                               pages[i++] = sg_dma_address(&chunk->page_list[j]) +
+                                       umem->page_size * k;
+                               /*
+                                * Be friendly to WRITE_MTT firmware
+                                * command, and pass it chunks of
+                                * appropriate size.
+                                */
+                               if (i == PAGE_SIZE / sizeof (u64) - 2) {
+                                       err = mlx4_write_mtt(dev->dev, mtt, n,
+                                                            i, pages);
+                                       if (err)
+                                               goto out;
+                                       n += i;
+                                       i = 0;
+                               }
+                       }
+               }
+
+       if (i)
+               err = mlx4_write_mtt(dev->dev, mtt, n, i, pages);
+
+out:
+       free_page((unsigned long) pages);
+       return err;
+}
+
+struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                 u64 virt_addr, int access_flags,
+                                 struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(pd->device);
+       struct mlx4_ib_mr *mr;
+       int shift;
+       int err;
+       int n;
+
+       mr = kmalloc(sizeof *mr, GFP_KERNEL);
+       if (!mr)
+               return ERR_PTR(-ENOMEM);
+
+       mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags);
+       if (IS_ERR(mr->umem)) {
+               err = PTR_ERR(mr->umem);
+               goto err_free;
+       }
+
+       n = ib_umem_page_count(mr->umem);
+       shift = ilog2(mr->umem->page_size);
+
+       err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, virt_addr, length,
+                           convert_access(access_flags), n, shift, &mr->mmr);
+       if (err)
+               goto err_umem;
+
+       err = mlx4_ib_umem_write_mtt(dev, &mr->mmr.mtt, mr->umem);
+       if (err)
+               goto err_mr;
+
+       err = mlx4_mr_enable(dev->dev, &mr->mmr);
+       if (err)
+               goto err_mr;
+
+       mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key;
+
+       return &mr->ibmr;
+
+err_mr:
+       mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr);
+
+err_umem:
+       ib_umem_release(mr->umem);
+
+err_free:
+       kfree(mr);
+
+       return ERR_PTR(err);
+}
+
+int mlx4_ib_dereg_mr(struct ib_mr *ibmr)
+{
+       struct mlx4_ib_mr *mr = to_mmr(ibmr);
+
+       mlx4_mr_free(to_mdev(ibmr->device)->dev, &mr->mmr);
+       if (mr->umem)
+               ib_umem_release(mr->umem);
+       kfree(mr);
+
+       return 0;
+}
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
new file mode 100644 (file)
index 0000000..5cd7069
--- /dev/null
@@ -0,0 +1,1294 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <rdma/ib_cache.h>
+#include <rdma/ib_pack.h>
+
+#include <linux/mlx4/qp.h>
+
+#include "mlx4_ib.h"
+#include "user.h"
+
+enum {
+       MLX4_IB_ACK_REQ_FREQ    = 8,
+};
+
+enum {
+       MLX4_IB_DEFAULT_SCHED_QUEUE     = 0x83,
+       MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f
+};
+
+enum {
+       /*
+        * Largest possible UD header: send with GRH and immediate data.
+        */
+       MLX4_IB_UD_HEADER_SIZE          = 72
+};
+
+struct mlx4_ib_sqp {
+       struct mlx4_ib_qp       qp;
+       int                     pkey_index;
+       u32                     qkey;
+       u32                     send_psn;
+       struct ib_ud_header     ud_header;
+       u8                      header_buf[MLX4_IB_UD_HEADER_SIZE];
+};
+
+static const __be32 mlx4_ib_opcode[] = {
+       [IB_WR_SEND]                    = __constant_cpu_to_be32(MLX4_OPCODE_SEND),
+       [IB_WR_SEND_WITH_IMM]           = __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM),
+       [IB_WR_RDMA_WRITE]              = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE),
+       [IB_WR_RDMA_WRITE_WITH_IMM]     = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM),
+       [IB_WR_RDMA_READ]               = __constant_cpu_to_be32(MLX4_OPCODE_RDMA_READ),
+       [IB_WR_ATOMIC_CMP_AND_SWP]      = __constant_cpu_to_be32(MLX4_OPCODE_ATOMIC_CS),
+       [IB_WR_ATOMIC_FETCH_AND_ADD]    = __constant_cpu_to_be32(MLX4_OPCODE_ATOMIC_FA),
+};
+
+static struct mlx4_ib_sqp *to_msqp(struct mlx4_ib_qp *mqp)
+{
+       return container_of(mqp, struct mlx4_ib_sqp, qp);
+}
+
+static int is_sqp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
+{
+       return qp->mqp.qpn >= dev->dev->caps.sqp_start &&
+               qp->mqp.qpn <= dev->dev->caps.sqp_start + 3;
+}
+
+static int is_qp0(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
+{
+       return qp->mqp.qpn >= dev->dev->caps.sqp_start &&
+               qp->mqp.qpn <= dev->dev->caps.sqp_start + 1;
+}
+
+static void *get_wqe(struct mlx4_ib_qp *qp, int offset)
+{
+       if (qp->buf.nbufs == 1)
+               return qp->buf.u.direct.buf + offset;
+       else
+               return qp->buf.u.page_list[offset >> PAGE_SHIFT].buf +
+                       (offset & (PAGE_SIZE - 1));
+}
+
+static void *get_recv_wqe(struct mlx4_ib_qp *qp, int n)
+{
+       return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift));
+}
+
+static void *get_send_wqe(struct mlx4_ib_qp *qp, int n)
+{
+       return get_wqe(qp, qp->sq.offset + (n << qp->sq.wqe_shift));
+}
+
+static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type)
+{
+       struct ib_event event;
+       struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
+
+       if (type == MLX4_EVENT_TYPE_PATH_MIG)
+               to_mibqp(qp)->port = to_mibqp(qp)->alt_port;
+
+       if (ibqp->event_handler) {
+               event.device     = ibqp->device;
+               event.element.qp = ibqp;
+               switch (type) {
+               case MLX4_EVENT_TYPE_PATH_MIG:
+                       event.event = IB_EVENT_PATH_MIG;
+                       break;
+               case MLX4_EVENT_TYPE_COMM_EST:
+                       event.event = IB_EVENT_COMM_EST;
+                       break;
+               case MLX4_EVENT_TYPE_SQ_DRAINED:
+                       event.event = IB_EVENT_SQ_DRAINED;
+                       break;
+               case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
+                       event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+                       break;
+               case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
+                       event.event = IB_EVENT_QP_FATAL;
+                       break;
+               case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
+                       event.event = IB_EVENT_PATH_MIG_ERR;
+                       break;
+               case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+                       event.event = IB_EVENT_QP_REQ_ERR;
+                       break;
+               case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
+                       event.event = IB_EVENT_QP_ACCESS_ERR;
+                       break;
+               default:
+                       printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+                              "on QP %06x\n", type, qp->qpn);
+                       return;
+               }
+
+               ibqp->event_handler(&event, ibqp->qp_context);
+       }
+}
+
+static int send_wqe_overhead(enum ib_qp_type type)
+{
+       /*
+        * UD WQEs must have a datagram segment.
+        * RC and UC WQEs might have a remote address segment.
+        * MLX WQEs need two extra inline data segments (for the UD
+        * header and space for the ICRC).
+        */
+       switch (type) {
+       case IB_QPT_UD:
+               return sizeof (struct mlx4_wqe_ctrl_seg) +
+                       sizeof (struct mlx4_wqe_datagram_seg);
+       case IB_QPT_UC:
+               return sizeof (struct mlx4_wqe_ctrl_seg) +
+                       sizeof (struct mlx4_wqe_raddr_seg);
+       case IB_QPT_RC:
+               return sizeof (struct mlx4_wqe_ctrl_seg) +
+                       sizeof (struct mlx4_wqe_atomic_seg) +
+                       sizeof (struct mlx4_wqe_raddr_seg);
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+               return sizeof (struct mlx4_wqe_ctrl_seg) +
+                       ALIGN(MLX4_IB_UD_HEADER_SIZE +
+                             sizeof (struct mlx4_wqe_inline_seg),
+                             sizeof (struct mlx4_wqe_data_seg)) +
+                       ALIGN(4 +
+                             sizeof (struct mlx4_wqe_inline_seg),
+                             sizeof (struct mlx4_wqe_data_seg));
+       default:
+               return sizeof (struct mlx4_wqe_ctrl_seg);
+       }
+}
+
+static int set_qp_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
+                      enum ib_qp_type type, struct mlx4_ib_qp *qp)
+{
+       /* Sanity check QP size before proceeding */
+       if (cap->max_send_wr     > dev->dev->caps.max_wqes  ||
+           cap->max_recv_wr     > dev->dev->caps.max_wqes  ||
+           cap->max_send_sge    > dev->dev->caps.max_sq_sg ||
+           cap->max_recv_sge    > dev->dev->caps.max_rq_sg ||
+           cap->max_inline_data + send_wqe_overhead(type) +
+           sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz)
+               return -EINVAL;
+
+       /*
+        * For MLX transport we need 2 extra S/G entries:
+        * one for the header and one for the checksum at the end
+        */
+       if ((type == IB_QPT_SMI || type == IB_QPT_GSI) &&
+           cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg)
+               return -EINVAL;
+
+       qp->rq.max = cap->max_recv_wr ? roundup_pow_of_two(cap->max_recv_wr) : 0;
+       qp->sq.max = cap->max_send_wr ? roundup_pow_of_two(cap->max_send_wr) : 0;
+
+       qp->rq.wqe_shift = ilog2(roundup_pow_of_two(cap->max_recv_sge *
+                                                   sizeof (struct mlx4_wqe_data_seg)));
+       qp->rq.max_gs    = (1 << qp->rq.wqe_shift) / sizeof (struct mlx4_wqe_data_seg);
+
+       qp->sq.wqe_shift = ilog2(roundup_pow_of_two(max(cap->max_send_sge *
+                                                       sizeof (struct mlx4_wqe_data_seg),
+                                                       cap->max_inline_data +
+                                                       sizeof (struct mlx4_wqe_inline_seg)) +
+                                                   send_wqe_overhead(type)));
+       qp->sq.max_gs    = ((1 << qp->sq.wqe_shift) - send_wqe_overhead(type)) /
+               sizeof (struct mlx4_wqe_data_seg);
+
+       qp->buf_size = (qp->rq.max << qp->rq.wqe_shift) +
+               (qp->sq.max << qp->sq.wqe_shift);
+       if (qp->rq.wqe_shift > qp->sq.wqe_shift) {
+               qp->rq.offset = 0;
+               qp->sq.offset = qp->rq.max << qp->rq.wqe_shift;
+       } else {
+               qp->rq.offset = qp->sq.max << qp->sq.wqe_shift;
+               qp->sq.offset = 0;
+       }
+
+       cap->max_send_wr  = qp->sq.max;
+       cap->max_recv_wr  = qp->rq.max;
+       cap->max_send_sge = qp->sq.max_gs;
+       cap->max_recv_sge = qp->rq.max_gs;
+       cap->max_inline_data = (1 << qp->sq.wqe_shift) - send_wqe_overhead(type) -
+               sizeof (struct mlx4_wqe_inline_seg);
+
+       return 0;
+}
+
+static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
+                           struct ib_qp_init_attr *init_attr,
+                           struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp)
+{
+       struct mlx4_wqe_ctrl_seg *ctrl;
+       int err;
+       int i;
+
+       mutex_init(&qp->mutex);
+       spin_lock_init(&qp->sq.lock);
+       spin_lock_init(&qp->rq.lock);
+
+       qp->state        = IB_QPS_RESET;
+       qp->atomic_rd_en = 0;
+       qp->resp_depth   = 0;
+
+       qp->rq.head         = 0;
+       qp->rq.tail         = 0;
+       qp->sq.head         = 0;
+       qp->sq.tail         = 0;
+
+       err = set_qp_size(dev, &init_attr->cap, init_attr->qp_type, qp);
+       if (err)
+               goto err;
+
+       if (pd->uobject) {
+               struct mlx4_ib_create_qp ucmd;
+
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+                       err = -EFAULT;
+                       goto err;
+               }
+
+               qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
+                                      qp->buf_size, 0);
+               if (IS_ERR(qp->umem)) {
+                       err = PTR_ERR(qp->umem);
+                       goto err;
+               }
+
+               err = mlx4_mtt_init(dev->dev, ib_umem_page_count(qp->umem),
+                                   ilog2(qp->umem->page_size), &qp->mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem);
+               if (err)
+                       goto err_mtt;
+
+               err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context),
+                                         ucmd.db_addr, &qp->db);
+               if (err)
+                       goto err_mtt;
+       } else {
+               err = mlx4_ib_db_alloc(dev, &qp->db, 0);
+               if (err)
+                       goto err;
+
+               *qp->db.db = 0;
+
+               if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf)) {
+                       err = -ENOMEM;
+                       goto err_db;
+               }
+
+               err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift,
+                                   &qp->mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf);
+               if (err)
+                       goto err_mtt;
+
+               for (i = 0; i < qp->sq.max; ++i) {
+                       ctrl = get_send_wqe(qp, i);
+                       ctrl->owner_opcode = cpu_to_be32(1 << 31);
+               }
+
+               qp->sq.wrid  = kmalloc(qp->sq.max * sizeof (u64), GFP_KERNEL);
+               qp->rq.wrid  = kmalloc(qp->rq.max * sizeof (u64), GFP_KERNEL);
+
+               if (!qp->sq.wrid || !qp->rq.wrid) {
+                       err = -ENOMEM;
+                       goto err_wrid;
+               }
+
+               /* We don't support inline sends for kernel QPs (yet) */
+               init_attr->cap.max_inline_data = 0;
+       }
+
+       err = mlx4_qp_alloc(dev->dev, sqpn, &qp->mqp);
+       if (err)
+               goto err_wrid;
+
+       /*
+        * Hardware wants QPN written in big-endian order (after
+        * shifting) for send doorbell.  Precompute this value to save
+        * a little bit when posting sends.
+        */
+       qp->doorbell_qpn = swab32(qp->mqp.qpn << 8);
+
+       if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+               qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
+       else
+               qp->sq_signal_bits = 0;
+
+       qp->mqp.event = mlx4_ib_qp_event;
+
+       return 0;
+
+err_wrid:
+       if (pd->uobject)
+               mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
+       else {
+               kfree(qp->sq.wrid);
+               kfree(qp->rq.wrid);
+       }
+
+err_mtt:
+       mlx4_mtt_cleanup(dev->dev, &qp->mtt);
+
+err_buf:
+       if (pd->uobject)
+               ib_umem_release(qp->umem);
+       else
+               mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
+
+err_db:
+       if (!pd->uobject)
+               mlx4_ib_db_free(dev, &qp->db);
+
+err:
+       return err;
+}
+
+static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state)
+{
+       switch (state) {
+       case IB_QPS_RESET:      return MLX4_QP_STATE_RST;
+       case IB_QPS_INIT:       return MLX4_QP_STATE_INIT;
+       case IB_QPS_RTR:        return MLX4_QP_STATE_RTR;
+       case IB_QPS_RTS:        return MLX4_QP_STATE_RTS;
+       case IB_QPS_SQD:        return MLX4_QP_STATE_SQD;
+       case IB_QPS_SQE:        return MLX4_QP_STATE_SQER;
+       case IB_QPS_ERR:        return MLX4_QP_STATE_ERR;
+       default:                return -1;
+       }
+}
+
+static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
+{
+       if (send_cq == recv_cq)
+               spin_lock_irq(&send_cq->lock);
+       else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
+               spin_lock_irq(&send_cq->lock);
+               spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
+       } else {
+               spin_lock_irq(&recv_cq->lock);
+               spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
+       }
+}
+
+static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
+{
+       if (send_cq == recv_cq)
+               spin_unlock_irq(&send_cq->lock);
+       else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
+               spin_unlock(&recv_cq->lock);
+               spin_unlock_irq(&send_cq->lock);
+       } else {
+               spin_unlock(&send_cq->lock);
+               spin_unlock_irq(&recv_cq->lock);
+       }
+}
+
+static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
+                             int is_user)
+{
+       struct mlx4_ib_cq *send_cq, *recv_cq;
+
+       if (qp->state != IB_QPS_RESET)
+               if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
+                                  MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
+                       printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n",
+                              qp->mqp.qpn);
+
+       send_cq = to_mcq(qp->ibqp.send_cq);
+       recv_cq = to_mcq(qp->ibqp.recv_cq);
+
+       mlx4_ib_lock_cqs(send_cq, recv_cq);
+
+       if (!is_user) {
+               __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
+                                qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL);
+               if (send_cq != recv_cq)
+                       __mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+       }
+
+       mlx4_qp_remove(dev->dev, &qp->mqp);
+
+       mlx4_ib_unlock_cqs(send_cq, recv_cq);
+
+       mlx4_qp_free(dev->dev, &qp->mqp);
+       mlx4_mtt_cleanup(dev->dev, &qp->mtt);
+
+       if (is_user) {
+               mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context),
+                                     &qp->db);
+               ib_umem_release(qp->umem);
+       } else {
+               kfree(qp->sq.wrid);
+               kfree(qp->rq.wrid);
+               mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
+               mlx4_ib_db_free(dev, &qp->db);
+       }
+}
+
+struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
+                               struct ib_qp_init_attr *init_attr,
+                               struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(pd->device);
+       struct mlx4_ib_sqp *sqp;
+       struct mlx4_ib_qp *qp;
+       int err;
+
+       switch (init_attr->qp_type) {
+       case IB_QPT_RC:
+       case IB_QPT_UC:
+       case IB_QPT_UD:
+       {
+               qp = kmalloc(sizeof *qp, GFP_KERNEL);
+               if (!qp)
+                       return ERR_PTR(-ENOMEM);
+
+               err = create_qp_common(dev, pd, init_attr, udata, 0, qp);
+               if (err) {
+                       kfree(qp);
+                       return ERR_PTR(err);
+               }
+
+               qp->ibqp.qp_num = qp->mqp.qpn;
+
+               break;
+       }
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:
+       {
+               /* Userspace is not allowed to create special QPs: */
+               if (pd->uobject)
+                       return ERR_PTR(-EINVAL);
+
+               sqp = kmalloc(sizeof *sqp, GFP_KERNEL);
+               if (!sqp)
+                       return ERR_PTR(-ENOMEM);
+
+               qp = &sqp->qp;
+
+               err = create_qp_common(dev, pd, init_attr, udata,
+                                      dev->dev->caps.sqp_start +
+                                      (init_attr->qp_type == IB_QPT_SMI ? 0 : 2) +
+                                      init_attr->port_num - 1,
+                                      qp);
+               if (err) {
+                       kfree(sqp);
+                       return ERR_PTR(err);
+               }
+
+               qp->port        = init_attr->port_num;
+               qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
+
+               break;
+       }
+       default:
+               /* Don't support raw QPs */
+               return ERR_PTR(-EINVAL);
+       }
+
+       return &qp->ibqp;
+}
+
+int mlx4_ib_destroy_qp(struct ib_qp *qp)
+{
+       struct mlx4_ib_dev *dev = to_mdev(qp->device);
+       struct mlx4_ib_qp *mqp = to_mqp(qp);
+
+       if (is_qp0(dev, mqp))
+               mlx4_CLOSE_PORT(dev->dev, mqp->port);
+
+       destroy_qp_common(dev, mqp, !!qp->pd->uobject);
+
+       if (is_sqp(dev, mqp))
+               kfree(to_msqp(mqp));
+       else
+               kfree(mqp);
+
+       return 0;
+}
+
+static void init_port(struct mlx4_ib_dev *dev, int port)
+{
+       struct mlx4_init_port_param param;
+       int err;
+
+       memset(&param, 0, sizeof param);
+
+       param.port_width_cap = dev->dev->caps.port_width_cap;
+       param.vl_cap         = dev->dev->caps.vl_cap;
+       param.mtu            = ib_mtu_enum_to_int(dev->dev->caps.mtu_cap);
+       param.max_gid        = dev->dev->caps.gid_table_len;
+       param.max_pkey       = dev->dev->caps.pkey_table_len;
+
+       err = mlx4_INIT_PORT(dev->dev, &param, port);
+       if (err)
+               printk(KERN_WARNING "INIT_PORT failed, return code %d.\n", err);
+}
+
+static int to_mlx4_st(enum ib_qp_type type)
+{
+       switch (type) {
+       case IB_QPT_RC:         return MLX4_QP_ST_RC;
+       case IB_QPT_UC:         return MLX4_QP_ST_UC;
+       case IB_QPT_UD:         return MLX4_QP_ST_UD;
+       case IB_QPT_SMI:
+       case IB_QPT_GSI:        return MLX4_QP_ST_MLX;
+       default:                return -1;
+       }
+}
+
+static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, struct ib_qp_attr *attr,
+                                  int attr_mask)
+{
+       u8 dest_rd_atomic;
+       u32 access_flags;
+       u32 hw_access_flags = 0;
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               dest_rd_atomic = attr->max_dest_rd_atomic;
+       else
+               dest_rd_atomic = qp->resp_depth;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               access_flags = attr->qp_access_flags;
+       else
+               access_flags = qp->atomic_rd_en;
+
+       if (!dest_rd_atomic)
+               access_flags &= IB_ACCESS_REMOTE_WRITE;
+
+       if (access_flags & IB_ACCESS_REMOTE_READ)
+               hw_access_flags |= MLX4_QP_BIT_RRE;
+       if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
+               hw_access_flags |= MLX4_QP_BIT_RAE;
+       if (access_flags & IB_ACCESS_REMOTE_WRITE)
+               hw_access_flags |= MLX4_QP_BIT_RWE;
+
+       return cpu_to_be32(hw_access_flags);
+}
+
+static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, struct ib_qp_attr *attr,
+                           int attr_mask)
+{
+       if (attr_mask & IB_QP_PKEY_INDEX)
+               sqp->pkey_index = attr->pkey_index;
+       if (attr_mask & IB_QP_QKEY)
+               sqp->qkey = attr->qkey;
+       if (attr_mask & IB_QP_SQ_PSN)
+               sqp->send_psn = attr->sq_psn;
+}
+
+static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
+{
+       path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6);
+}
+
+static int mlx4_set_path(struct mlx4_ib_dev *dev, struct ib_ah_attr *ah,
+                        struct mlx4_qp_path *path, u8 port)
+{
+       path->grh_mylmc     = ah->src_path_bits & 0x7f;
+       path->rlid          = cpu_to_be16(ah->dlid);
+       if (ah->static_rate) {
+               path->static_rate = ah->static_rate + MLX4_STAT_RATE_OFFSET;
+               while (path->static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+                      !(1 << path->static_rate & dev->dev->caps.stat_rate_support))
+                       --path->static_rate;
+       } else
+               path->static_rate = 0;
+       path->counter_index = 0xff;
+
+       if (ah->ah_flags & IB_AH_GRH) {
+               if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len) {
+                       printk(KERN_ERR "sgid_index (%u) too large. max is %d\n",
+                              ah->grh.sgid_index, dev->dev->caps.gid_table_len - 1);
+                       return -1;
+               }
+
+               path->grh_mylmc |= 1 << 7;
+               path->mgid_index = ah->grh.sgid_index;
+               path->hop_limit  = ah->grh.hop_limit;
+               path->tclass_flowlabel =
+                       cpu_to_be32((ah->grh.traffic_class << 20) |
+                                   (ah->grh.flow_label));
+               memcpy(path->rgid, ah->grh.dgid.raw, 16);
+       }
+
+       path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+               ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+
+       return 0;
+}
+
+int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                     int attr_mask, struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
+       struct mlx4_ib_qp *qp = to_mqp(ibqp);
+       struct mlx4_qp_context *context;
+       enum mlx4_qp_optpar optpar = 0;
+       enum ib_qp_state cur_state, new_state;
+       int sqd_event;
+       int err = -EINVAL;
+
+       context = kzalloc(sizeof *context, GFP_KERNEL);
+       if (!context)
+               return -ENOMEM;
+
+       mutex_lock(&qp->mutex);
+
+       cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
+       new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
+
+       if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask))
+               goto out;
+
+       if ((attr_mask & IB_QP_PKEY_INDEX) &&
+            attr->pkey_index >= dev->dev->caps.pkey_table_len) {
+               goto out;
+       }
+
+       if ((attr_mask & IB_QP_PORT) &&
+           (attr->port_num == 0 || attr->port_num > dev->dev->caps.num_ports)) {
+               goto out;
+       }
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+           attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) {
+               goto out;
+       }
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+           attr->max_dest_rd_atomic > 1 << dev->dev->caps.max_qp_dest_rdma) {
+               goto out;
+       }
+
+       context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) |
+                                    (to_mlx4_st(ibqp->qp_type) << 16));
+       context->flags     |= cpu_to_be32(1 << 8); /* DE? */
+
+       if (!(attr_mask & IB_QP_PATH_MIG_STATE))
+               context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11);
+       else {
+               optpar |= MLX4_QP_OPTPAR_PM_STATE;
+               switch (attr->path_mig_state) {
+               case IB_MIG_MIGRATED:
+                       context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11);
+                       break;
+               case IB_MIG_REARM:
+                       context->flags |= cpu_to_be32(MLX4_QP_PM_REARM << 11);
+                       break;
+               case IB_MIG_ARMED:
+                       context->flags |= cpu_to_be32(MLX4_QP_PM_ARMED << 11);
+                       break;
+               }
+       }
+
+       if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI ||
+           ibqp->qp_type == IB_QPT_UD)
+               context->mtu_msgmax = (IB_MTU_4096 << 5) | 11;
+       else if (attr_mask & IB_QP_PATH_MTU) {
+               if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
+                       printk(KERN_ERR "path MTU (%u) is invalid\n",
+                              attr->path_mtu);
+                       return -EINVAL;
+               }
+               context->mtu_msgmax = (attr->path_mtu << 5) | 31;
+       }
+
+       if (qp->rq.max)
+               context->rq_size_stride = ilog2(qp->rq.max) << 3;
+       context->rq_size_stride |= qp->rq.wqe_shift - 4;
+
+       if (qp->sq.max)
+               context->sq_size_stride = ilog2(qp->sq.max) << 3;
+       context->sq_size_stride |= qp->sq.wqe_shift - 4;
+
+       if (qp->ibqp.uobject)
+               context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
+       else
+               context->usr_page = cpu_to_be32(dev->priv_uar.index);
+
+       if (attr_mask & IB_QP_DEST_QPN)
+               context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
+
+       if (attr_mask & IB_QP_PORT) {
+               if (cur_state == IB_QPS_SQD && new_state == IB_QPS_SQD &&
+                   !(attr_mask & IB_QP_AV)) {
+                       mlx4_set_sched(&context->pri_path, attr->port_num);
+                       optpar |= MLX4_QP_OPTPAR_SCHED_QUEUE;
+               }
+       }
+
+       if (attr_mask & IB_QP_PKEY_INDEX) {
+               context->pri_path.pkey_index = attr->pkey_index;
+               optpar |= MLX4_QP_OPTPAR_PKEY_INDEX;
+       }
+
+       if (attr_mask & IB_QP_RNR_RETRY) {
+               context->params1 |= cpu_to_be32(attr->rnr_retry << 13);
+               optpar |= MLX4_QP_OPTPAR_RNR_RETRY;
+       }
+
+       if (attr_mask & IB_QP_AV) {
+               if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path,
+                                 attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) {
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
+                          MLX4_QP_OPTPAR_SCHED_QUEUE);
+       }
+
+       if (attr_mask & IB_QP_TIMEOUT) {
+               context->pri_path.ackto = attr->timeout << 3;
+               optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT;
+       }
+
+       if (attr_mask & IB_QP_ALT_PATH) {
+               if (attr->alt_pkey_index >= dev->dev->caps.pkey_table_len)
+                       return -EINVAL;
+
+               if (attr->alt_port_num == 0 ||
+                   attr->alt_port_num > dev->dev->caps.num_ports)
+                       return -EINVAL;
+
+               if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
+                                 attr->alt_port_num))
+                       return -EINVAL;
+
+               context->alt_path.pkey_index = attr->alt_pkey_index;
+               context->alt_path.ackto = attr->alt_timeout << 3;
+               optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH;
+       }
+
+       context->pd         = cpu_to_be32(to_mpd(ibqp->pd)->pdn);
+       context->params1    = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28);
+       if (attr_mask & IB_QP_RETRY_CNT) {
+               context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
+               optpar |= MLX4_QP_OPTPAR_RETRY_COUNT;
+       }
+
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+               if (attr->max_rd_atomic)
+                       context->params1 |=
+                               cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
+               optpar |= MLX4_QP_OPTPAR_SRA_MAX;
+       }
+
+       if (attr_mask & IB_QP_SQ_PSN)
+               context->next_send_psn = cpu_to_be32(attr->sq_psn);
+
+       context->cqn_send = cpu_to_be32(to_mcq(ibqp->send_cq)->mcq.cqn);
+
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+               if (attr->max_dest_rd_atomic)
+                       context->params2 |=
+                               cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
+               optpar |= MLX4_QP_OPTPAR_RRA_MAX;
+       }
+
+       if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
+               context->params2 |= to_mlx4_access_flags(qp, attr, attr_mask);
+               optpar |= MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE;
+       }
+
+       if (ibqp->srq)
+               context->params2 |= cpu_to_be32(MLX4_QP_BIT_RIC);
+
+       if (attr_mask & IB_QP_MIN_RNR_TIMER) {
+               context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
+               optpar |= MLX4_QP_OPTPAR_RNR_TIMEOUT;
+       }
+       if (attr_mask & IB_QP_RQ_PSN)
+               context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
+
+       context->cqn_recv = cpu_to_be32(to_mcq(ibqp->recv_cq)->mcq.cqn);
+
+       if (attr_mask & IB_QP_QKEY) {
+               context->qkey = cpu_to_be32(attr->qkey);
+               optpar |= MLX4_QP_OPTPAR_Q_KEY;
+       }
+
+       if (ibqp->srq)
+               context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn);
+
+       if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
+               context->db_rec_addr = cpu_to_be64(qp->db.dma);
+
+       if (cur_state == IB_QPS_INIT &&
+           new_state == IB_QPS_RTR  &&
+           (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI ||
+            ibqp->qp_type == IB_QPT_UD)) {
+               context->pri_path.sched_queue = (qp->port - 1) << 6;
+               if (is_qp0(dev, qp))
+                       context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE;
+               else
+                       context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE;
+       }
+
+       if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD  &&
+           attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify)
+               sqd_event = 1;
+       else
+               sqd_event = 0;
+
+       err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state),
+                            to_mlx4_state(new_state), context, optpar,
+                            sqd_event, &qp->mqp);
+       if (err)
+               goto out;
+
+       qp->state = new_state;
+
+       if (attr_mask & IB_QP_ACCESS_FLAGS)
+               qp->atomic_rd_en = attr->qp_access_flags;
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+               qp->resp_depth = attr->max_dest_rd_atomic;
+       if (attr_mask & IB_QP_PORT)
+               qp->port = attr->port_num;
+       if (attr_mask & IB_QP_ALT_PATH)
+               qp->alt_port = attr->alt_port_num;
+
+       if (is_sqp(dev, qp))
+               store_sqp_attrs(to_msqp(qp), attr, attr_mask);
+
+       /*
+        * If we moved QP0 to RTR, bring the IB link up; if we moved
+        * QP0 to RESET or ERROR, bring the link back down.
+        */
+       if (is_qp0(dev, qp)) {
+               if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR)
+                       init_port(dev, qp->port);
+
+               if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR &&
+                   (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR))
+                       mlx4_CLOSE_PORT(dev->dev, qp->port);
+       }
+
+       /*
+        * If we moved a kernel QP to RESET, clean up all old CQ
+        * entries and reinitialize the QP.
+        */
+       if (new_state == IB_QPS_RESET && !ibqp->uobject) {
+               mlx4_ib_cq_clean(to_mcq(ibqp->recv_cq), qp->mqp.qpn,
+                                ibqp->srq ? to_msrq(ibqp->srq): NULL);
+               if (ibqp->send_cq != ibqp->recv_cq)
+                       mlx4_ib_cq_clean(to_mcq(ibqp->send_cq), qp->mqp.qpn, NULL);
+
+               qp->rq.head = 0;
+               qp->rq.tail = 0;
+               qp->sq.head = 0;
+               qp->sq.tail = 0;
+               *qp->db.db  = 0;
+       }
+
+out:
+       mutex_unlock(&qp->mutex);
+       kfree(context);
+       return err;
+}
+
+static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
+                           void *wqe)
+{
+       struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev;
+       struct mlx4_wqe_mlx_seg *mlx = wqe;
+       struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
+       struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       u16 pkey;
+       int send_size;
+       int header_size;
+       int i;
+
+       send_size = 0;
+       for (i = 0; i < wr->num_sge; ++i)
+               send_size += wr->sg_list[i].length;
+
+       ib_ud_header_init(send_size, mlx4_ib_ah_grh_present(ah), &sqp->ud_header);
+
+       sqp->ud_header.lrh.service_level   =
+               be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
+       sqp->ud_header.lrh.destination_lid = ah->av.dlid;
+       sqp->ud_header.lrh.source_lid      = cpu_to_be16(ah->av.g_slid & 0x7f);
+       if (mlx4_ib_ah_grh_present(ah)) {
+               sqp->ud_header.grh.traffic_class =
+                       (be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20) & 0xff;
+               sqp->ud_header.grh.flow_label    =
+                       ah->av.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
+               ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.port_pd) >> 24,
+                                 ah->av.gid_index, &sqp->ud_header.grh.source_gid);
+               memcpy(sqp->ud_header.grh.destination_gid.raw,
+                      ah->av.dgid, 16);
+       }
+
+       mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
+       mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
+                                 (sqp->ud_header.lrh.destination_lid ==
+                                  IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) |
+                                 (sqp->ud_header.lrh.service_level << 8));
+       mlx->rlid   = sqp->ud_header.lrh.destination_lid;
+
+       switch (wr->opcode) {
+       case IB_WR_SEND:
+               sqp->ud_header.bth.opcode        = IB_OPCODE_UD_SEND_ONLY;
+               sqp->ud_header.immediate_present = 0;
+               break;
+       case IB_WR_SEND_WITH_IMM:
+               sqp->ud_header.bth.opcode        = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
+               sqp->ud_header.immediate_present = 1;
+               sqp->ud_header.immediate_data    = wr->imm_data;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sqp->ud_header.lrh.virtual_lane    = !sqp->qp.ibqp.qp_num ? 15 : 0;
+       if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
+               sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
+       sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED);
+       if (!sqp->qp.ibqp.qp_num)
+               ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey);
+       else
+               ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->wr.ud.pkey_index, &pkey);
+       sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
+       sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+       sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
+       sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ?
+                                              sqp->qkey : wr->wr.ud.remote_qkey);
+       sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num);
+
+       header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf);
+
+       if (0) {
+               printk(KERN_ERR "built UD header of size %d:\n", header_size);
+               for (i = 0; i < header_size / 4; ++i) {
+                       if (i % 8 == 0)
+                               printk("  [%02x] ", i * 4);
+                       printk(" %08x",
+                              be32_to_cpu(((__be32 *) sqp->header_buf)[i]));
+                       if ((i + 1) % 8 == 0)
+                               printk("\n");
+               }
+               printk("\n");
+       }
+
+       inl->byte_count = cpu_to_be32(1 << 31 | header_size);
+       memcpy(inl + 1, sqp->header_buf, header_size);
+
+       return ALIGN(sizeof (struct mlx4_wqe_inline_seg) + header_size, 16);
+}
+
+static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
+{
+       unsigned cur;
+       struct mlx4_ib_cq *cq;
+
+       cur = wq->head - wq->tail;
+       if (likely(cur + nreq < wq->max))
+               return 0;
+
+       cq = to_mcq(ib_cq);
+       spin_lock(&cq->lock);
+       cur = wq->head - wq->tail;
+       spin_unlock(&cq->lock);
+
+       return cur + nreq >= wq->max;
+}
+
+int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                     struct ib_send_wr **bad_wr)
+{
+       struct mlx4_ib_qp *qp = to_mqp(ibqp);
+       void *wqe;
+       struct mlx4_wqe_ctrl_seg *ctrl;
+       unsigned long flags;
+       int nreq;
+       int err = 0;
+       int ind;
+       int size;
+       int i;
+
+       spin_lock_irqsave(&qp->rq.lock, flags);
+
+       ind = qp->sq.head;
+
+       for (nreq = 0; wr; ++nreq, wr = wr->next) {
+               if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               if (unlikely(wr->num_sge > qp->sq.max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.max - 1));
+               qp->sq.wrid[ind & (qp->sq.max - 1)] = wr->wr_id;
+
+               ctrl->srcrb_flags =
+                       (wr->send_flags & IB_SEND_SIGNALED ?
+                        cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) |
+                       (wr->send_flags & IB_SEND_SOLICITED ?
+                        cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) |
+                       qp->sq_signal_bits;
+
+               if (wr->opcode == IB_WR_SEND_WITH_IMM ||
+                   wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM)
+                       ctrl->imm = wr->imm_data;
+               else
+                       ctrl->imm = 0;
+
+               wqe += sizeof *ctrl;
+               size = sizeof *ctrl / 16;
+
+               switch (ibqp->qp_type) {
+               case IB_QPT_RC:
+               case IB_QPT_UC:
+                       switch (wr->opcode) {
+                       case IB_WR_ATOMIC_CMP_AND_SWP:
+                       case IB_WR_ATOMIC_FETCH_AND_ADD:
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
+                                       cpu_to_be64(wr->wr.atomic.remote_addr);
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
+                                       cpu_to_be32(wr->wr.atomic.rkey);
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
+
+                               wqe  += sizeof (struct mlx4_wqe_raddr_seg);
+
+                               if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
+                                               cpu_to_be64(wr->wr.atomic.swap);
+                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare =
+                                               cpu_to_be64(wr->wr.atomic.compare_add);
+                               } else {
+                                       ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
+                                               cpu_to_be64(wr->wr.atomic.compare_add);
+                                       ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
+                               }
+
+                               wqe  += sizeof (struct mlx4_wqe_atomic_seg);
+                               size += (sizeof (struct mlx4_wqe_raddr_seg) +
+                                        sizeof (struct mlx4_wqe_atomic_seg)) / 16;
+
+                               break;
+
+                       case IB_WR_RDMA_READ:
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_WRITE_WITH_IMM:
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
+                                       cpu_to_be64(wr->wr.rdma.remote_addr);
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
+                                       cpu_to_be32(wr->wr.rdma.rkey);
+                               ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
+
+                               wqe  += sizeof (struct mlx4_wqe_raddr_seg);
+                               size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
+
+                               break;
+
+                       default:
+                               /* No extra segments required for sends */
+                               break;
+                       }
+                       break;
+
+               case IB_QPT_UD:
+                       memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
+                              &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+                       ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
+                               cpu_to_be32(wr->wr.ud.remote_qpn);
+                       ((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
+                               cpu_to_be32(wr->wr.ud.remote_qkey);
+
+                       wqe  += sizeof (struct mlx4_wqe_datagram_seg);
+                       size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
+                       break;
+
+               case IB_QPT_SMI:
+               case IB_QPT_GSI:
+                       err = build_mlx_header(to_msqp(qp), wr, ctrl);
+                       if (err < 0) {
+                               *bad_wr = wr;
+                               goto out;
+                       }
+                       wqe  += err;
+                       size += err / 16;
+
+                       err = 0;
+                       break;
+
+               default:
+                       break;
+               }
+
+               for (i = 0; i < wr->num_sge; ++i) {
+                       ((struct mlx4_wqe_data_seg *) wqe)->byte_count =
+                               cpu_to_be32(wr->sg_list[i].length);
+                       ((struct mlx4_wqe_data_seg *) wqe)->lkey =
+                               cpu_to_be32(wr->sg_list[i].lkey);
+                       ((struct mlx4_wqe_data_seg *) wqe)->addr =
+                               cpu_to_be64(wr->sg_list[i].addr);
+
+                       wqe  += sizeof (struct mlx4_wqe_data_seg);
+                       size += sizeof (struct mlx4_wqe_data_seg) / 16;
+               }
+
+               /* Add one more inline data segment for ICRC for MLX sends */
+               if (qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) {
+                       ((struct mlx4_wqe_inline_seg *) wqe)->byte_count =
+                               cpu_to_be32((1 << 31) | 4);
+                       ((u32 *) wqe)[1] = 0;
+                       wqe  += sizeof (struct mlx4_wqe_data_seg);
+                       size += sizeof (struct mlx4_wqe_data_seg) / 16;
+               }
+
+               ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
+                                   MLX4_WQE_CTRL_FENCE : 0) | size;
+
+               /*
+                * Make sure descriptor is fully written before
+                * setting ownership bit (because HW can start
+                * executing as soon as we do).
+                */
+               wmb();
+
+               if (wr->opcode < 0 || wr->opcode > ARRAY_SIZE(mlx4_ib_opcode)) {
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
+                       (ind & qp->sq.max ? cpu_to_be32(1 << 31) : 0);
+
+               ++ind;
+       }
+
+out:
+       if (likely(nreq)) {
+               qp->sq.head += nreq;
+
+               /*
+                * Make sure that descriptors are written before
+                * doorbell record.
+                */
+               wmb();
+
+               writel(qp->doorbell_qpn,
+                      to_mdev(ibqp->device)->uar_map + MLX4_SEND_DOORBELL);
+
+               /*
+                * Make sure doorbells don't leak out of SQ spinlock
+                * and reach the HCA out of order.
+                */
+               mmiowb();
+       }
+
+       spin_unlock_irqrestore(&qp->rq.lock, flags);
+
+       return err;
+}
+
+int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+                     struct ib_recv_wr **bad_wr)
+{
+       struct mlx4_ib_qp *qp = to_mqp(ibqp);
+       struct mlx4_wqe_data_seg *scat;
+       unsigned long flags;
+       int err = 0;
+       int nreq;
+       int ind;
+       int i;
+
+       spin_lock_irqsave(&qp->rq.lock, flags);
+
+       ind = qp->rq.head & (qp->rq.max - 1);
+
+       for (nreq = 0; wr; ++nreq, wr = wr->next) {
+               if (mlx4_wq_overflow(&qp->rq, nreq, qp->ibqp.send_cq)) {
+                       err = -ENOMEM;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               if (unlikely(wr->num_sge > qp->rq.max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       goto out;
+               }
+
+               scat = get_recv_wqe(qp, ind);
+
+               for (i = 0; i < wr->num_sge; ++i) {
+                       scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
+                       scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
+                       scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
+               }
+
+               if (i < qp->rq.max_gs) {
+                       scat[i].byte_count = 0;
+                       scat[i].lkey       = cpu_to_be32(MLX4_INVALID_LKEY);
+                       scat[i].addr       = 0;
+               }
+
+               qp->rq.wrid[ind] = wr->wr_id;
+
+               ind = (ind + 1) & (qp->rq.max - 1);
+       }
+
+out:
+       if (likely(nreq)) {
+               qp->rq.head += nreq;
+
+               /*
+                * Make sure that descriptors are written before
+                * doorbell record.
+                */
+               wmb();
+
+               *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
+       }
+
+       spin_unlock_irqrestore(&qp->rq.lock, flags);
+
+       return err;
+}
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
new file mode 100644 (file)
index 0000000..42ab4a8
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx4/qp.h>
+#include <linux/mlx4/srq.h>
+
+#include "mlx4_ib.h"
+#include "user.h"
+
+static void *get_wqe(struct mlx4_ib_srq *srq, int n)
+{
+       int offset = n << srq->msrq.wqe_shift;
+
+       if (srq->buf.nbufs == 1)
+               return srq->buf.u.direct.buf + offset;
+       else
+               return srq->buf.u.page_list[offset >> PAGE_SHIFT].buf +
+                       (offset & (PAGE_SIZE - 1));
+}
+
+static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
+{
+       struct ib_event event;
+       struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
+
+       if (ibsrq->event_handler) {
+               event.device      = ibsrq->device;
+               event.element.srq = ibsrq;
+               switch (type) {
+               case MLX4_EVENT_TYPE_SRQ_LIMIT:
+                       event.event = IB_EVENT_SRQ_LIMIT_REACHED;
+                       break;
+               case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
+                       event.event = IB_EVENT_SRQ_ERR;
+                       break;
+               default:
+                       printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
+                              "on SRQ %06x\n", type, srq->srqn);
+                       return;
+               }
+
+               ibsrq->event_handler(&event, ibsrq->srq_context);
+       }
+}
+
+struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
+                                 struct ib_srq_init_attr *init_attr,
+                                 struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(pd->device);
+       struct mlx4_ib_srq *srq;
+       struct mlx4_wqe_srq_next_seg *next;
+       int desc_size;
+       int buf_size;
+       int err;
+       int i;
+
+       /* Sanity check SRQ size before proceeding */
+       if (init_attr->attr.max_wr  >= dev->dev->caps.max_srq_wqes ||
+           init_attr->attr.max_sge >  dev->dev->caps.max_srq_sge)
+               return ERR_PTR(-EINVAL);
+
+       srq = kmalloc(sizeof *srq, GFP_KERNEL);
+       if (!srq)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_init(&srq->mutex);
+       spin_lock_init(&srq->lock);
+       srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
+       srq->msrq.max_gs = init_attr->attr.max_sge;
+
+       desc_size = max(32UL,
+                       roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) +
+                                          srq->msrq.max_gs *
+                                          sizeof (struct mlx4_wqe_data_seg)));
+       srq->msrq.wqe_shift = ilog2(desc_size);
+
+       buf_size = srq->msrq.max * desc_size;
+
+       if (pd->uobject) {
+               struct mlx4_ib_create_srq ucmd;
+
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+                       err = -EFAULT;
+                       goto err_srq;
+               }
+
+               srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
+                                       buf_size, 0);
+               if (IS_ERR(srq->umem)) {
+                       err = PTR_ERR(srq->umem);
+                       goto err_srq;
+               }
+
+               err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem),
+                                   ilog2(srq->umem->page_size), &srq->mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem);
+               if (err)
+                       goto err_mtt;
+
+               err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context),
+                                         ucmd.db_addr, &srq->db);
+               if (err)
+                       goto err_mtt;
+       } else {
+               err = mlx4_ib_db_alloc(dev, &srq->db, 0);
+               if (err)
+                       goto err_srq;
+
+               *srq->db.db = 0;
+
+               if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
+                       err = -ENOMEM;
+                       goto err_db;
+               }
+
+               srq->head    = 0;
+               srq->tail    = srq->msrq.max - 1;
+               srq->wqe_ctr = 0;
+
+               for (i = 0; i < srq->msrq.max; ++i) {
+                       next = get_wqe(srq, i);
+                       next->next_wqe_index =
+                               cpu_to_be16((i + 1) & (srq->msrq.max - 1));
+               }
+
+               err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift,
+                                   &srq->mtt);
+               if (err)
+                       goto err_buf;
+
+               err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf);
+               if (err)
+                       goto err_mtt;
+
+               srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL);
+               if (!srq->wrid) {
+                       err = -ENOMEM;
+                       goto err_mtt;
+               }
+       }
+
+       err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, &srq->mtt,
+                            srq->db.dma, &srq->msrq);
+       if (err)
+               goto err_wrid;
+
+       srq->msrq.event = mlx4_ib_srq_event;
+
+       if (pd->uobject)
+               if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
+                       err = -EFAULT;
+                       goto err_wrid;
+               }
+
+       init_attr->attr.max_wr = srq->msrq.max - 1;
+
+       return &srq->ibsrq;
+
+err_wrid:
+       if (pd->uobject)
+               mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
+       else
+               kfree(srq->wrid);
+
+err_mtt:
+       mlx4_mtt_cleanup(dev->dev, &srq->mtt);
+
+err_buf:
+       if (pd->uobject)
+               ib_umem_release(srq->umem);
+       else
+               mlx4_buf_free(dev->dev, buf_size, &srq->buf);
+
+err_db:
+       if (!pd->uobject)
+               mlx4_ib_db_free(dev, &srq->db);
+
+err_srq:
+       kfree(srq);
+
+       return ERR_PTR(err);
+}
+
+int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+                      enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+       struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
+       struct mlx4_ib_srq *srq = to_msrq(ibsrq);
+       int ret;
+
+       /* We don't support resizing SRQs (yet?) */
+       if (attr_mask & IB_SRQ_MAX_WR)
+               return -EINVAL;
+
+       if (attr_mask & IB_SRQ_LIMIT) {
+               if (attr->srq_limit >= srq->msrq.max)
+                       return -EINVAL;
+
+               mutex_lock(&srq->mutex);
+               ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit);
+               mutex_unlock(&srq->mutex);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int mlx4_ib_destroy_srq(struct ib_srq *srq)
+{
+       struct mlx4_ib_dev *dev = to_mdev(srq->device);
+       struct mlx4_ib_srq *msrq = to_msrq(srq);
+
+       mlx4_srq_free(dev->dev, &msrq->msrq);
+       mlx4_mtt_cleanup(dev->dev, &msrq->mtt);
+
+       if (srq->uobject) {
+               mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
+               ib_umem_release(msrq->umem);
+       } else {
+               kfree(msrq->wrid);
+               mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
+                             &msrq->buf);
+               mlx4_ib_db_free(dev, &msrq->db);
+       }
+
+       kfree(msrq);
+
+       return 0;
+}
+
+void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index)
+{
+       struct mlx4_wqe_srq_next_seg *next;
+
+       /* always called with interrupts disabled. */
+       spin_lock(&srq->lock);
+
+       next = get_wqe(srq, srq->tail);
+       next->next_wqe_index = cpu_to_be16(wqe_index);
+       srq->tail = wqe_index;
+
+       spin_unlock(&srq->lock);
+}
+
+int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+                         struct ib_recv_wr **bad_wr)
+{
+       struct mlx4_ib_srq *srq = to_msrq(ibsrq);
+       struct mlx4_wqe_srq_next_seg *next;
+       struct mlx4_wqe_data_seg *scat;
+       unsigned long flags;
+       int err = 0;
+       int nreq;
+       int i;
+
+       spin_lock_irqsave(&srq->lock, flags);
+
+       for (nreq = 0; wr; ++nreq, wr = wr->next) {
+               if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
+                       err = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
+
+               srq->wrid[srq->head] = wr->wr_id;
+
+               next      = get_wqe(srq, srq->head);
+               srq->head = be16_to_cpu(next->next_wqe_index);
+               scat      = (struct mlx4_wqe_data_seg *) (next + 1);
+
+               for (i = 0; i < wr->num_sge; ++i) {
+                       scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
+                       scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
+                       scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
+               }
+
+               if (i < srq->msrq.max_gs) {
+                       scat[i].byte_count = 0;
+                       scat[i].lkey       = cpu_to_be32(MLX4_INVALID_LKEY);
+                       scat[i].addr       = 0;
+               }
+       }
+
+       if (likely(nreq)) {
+               srq->wqe_ctr += nreq;
+
+               /*
+                * Make sure that descriptors are written before
+                * doorbell record.
+                */
+               wmb();
+
+               *srq->db.db = cpu_to_be32(srq->wqe_ctr);
+       }
+
+       spin_unlock_irqrestore(&srq->lock, flags);
+
+       return err;
+}
diff --git a/drivers/infiniband/hw/mlx4/user.h b/drivers/infiniband/hw/mlx4/user.h
new file mode 100644 (file)
index 0000000..5b8eddc
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_IB_USER_H
+#define MLX4_IB_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define MLX4_IB_UVERBS_ABI_VERSION     1
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mlx4_ib_alloc_ucontext_resp {
+       __u32   qp_tab_size;
+       __u16   bf_reg_size;
+       __u16   bf_regs_per_page;
+};
+
+struct mlx4_ib_alloc_pd_resp {
+       __u32   pdn;
+       __u32   reserved;
+};
+
+struct mlx4_ib_create_cq {
+       __u64   buf_addr;
+       __u64   db_addr;
+};
+
+struct mlx4_ib_create_cq_resp {
+       __u32   cqn;
+       __u32   reserved;
+};
+
+struct mlx4_ib_resize_cq {
+       __u64   buf_addr;
+};
+
+struct mlx4_ib_create_srq {
+       __u64   buf_addr;
+       __u64   db_addr;
+};
+
+struct mlx4_ib_create_srq_resp {
+       __u32   srqn;
+       __u32   reserved;
+};
+
+struct mlx4_ib_create_qp {
+       __u64   buf_addr;
+       __u64   db_addr;
+};
+
+#endif /* MLX4_IB_USER_H */
index 1c05486c3c68b6171077b9f57fb345c2717403b5..6bcde1cb9688f9860b8116fb22526553a23d5746 100644 (file)
@@ -37,6 +37,7 @@
  */
 
 #include <rdma/ib_smi.h>
+#include <rdma/ib_umem.h>
 #include <rdma/ib_user_verbs.h>
 #include <linux/mm.h>
 
@@ -908,6 +909,8 @@ static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc)
                return ERR_PTR(err);
        }
 
+       mr->umem = NULL;
+
        return &mr->ibmr;
 }
 
@@ -1003,11 +1006,13 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
        }
 
        kfree(page_list);
+       mr->umem = NULL;
+
        return &mr->ibmr;
 }
 
-static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
-                                      int acc, struct ib_udata *udata)
+static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+                                      u64 virt, int acc, struct ib_udata *udata)
 {
        struct mthca_dev *dev = to_mdev(pd->device);
        struct ib_umem_chunk *chunk;
@@ -1018,20 +1023,26 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
        int err = 0;
        int write_mtt_size;
 
-       shift = ffs(region->page_size) - 1;
-
        mr = kmalloc(sizeof *mr, GFP_KERNEL);
        if (!mr)
                return ERR_PTR(-ENOMEM);
 
+       mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+       if (IS_ERR(mr->umem)) {
+               err = PTR_ERR(mr->umem);
+               goto err;
+       }
+
+       shift = ffs(mr->umem->page_size) - 1;
+
        n = 0;
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &mr->umem->chunk_list, list)
                n += chunk->nents;
 
        mr->mtt = mthca_alloc_mtt(dev, n);
        if (IS_ERR(mr->mtt)) {
                err = PTR_ERR(mr->mtt);
-               goto err;
+               goto err_umem;
        }
 
        pages = (u64 *) __get_free_page(GFP_KERNEL);
@@ -1044,12 +1055,12 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
 
        write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
 
-       list_for_each_entry(chunk, &region->chunk_list, list)
+       list_for_each_entry(chunk, &mr->umem->chunk_list, list)
                for (j = 0; j < chunk->nmap; ++j) {
                        len = sg_dma_len(&chunk->page_list[j]) >> shift;
                        for (k = 0; k < len; ++k) {
                                pages[i++] = sg_dma_address(&chunk->page_list[j]) +
-                                       region->page_size * k;
+                                       mr->umem->page_size * k;
                                /*
                                 * Be friendly to write_mtt and pass it chunks
                                 * of appropriate size.
@@ -1071,8 +1082,8 @@ mtt_done:
        if (err)
                goto err_mtt;
 
-       err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base,
-                            region->length, convert_access(acc), mr);
+       err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length,
+                            convert_access(acc), mr);
 
        if (err)
                goto err_mtt;
@@ -1082,6 +1093,9 @@ mtt_done:
 err_mtt:
        mthca_free_mtt(dev, mr->mtt);
 
+err_umem:
+       ib_umem_release(mr->umem);
+
 err:
        kfree(mr);
        return ERR_PTR(err);
@@ -1090,8 +1104,12 @@ err:
 static int mthca_dereg_mr(struct ib_mr *mr)
 {
        struct mthca_mr *mmr = to_mmr(mr);
+
        mthca_free_mr(to_mdev(mr->device), mmr);
+       if (mmr->umem)
+               ib_umem_release(mmr->umem);
        kfree(mmr);
+
        return 0;
 }
 
index 1d266ac2e094c404d2cd8d3167261c07e20c0f6d..262616c8ebb644d75ab603e5ce12b5f668baa5ac 100644 (file)
@@ -73,6 +73,7 @@ struct mthca_mtt;
 
 struct mthca_mr {
        struct ib_mr      ibmr;
+       struct ib_umem   *umem;
        struct mthca_mtt *mtt;
 };
 
index 0e9b69535ad6990a0766b346412b352562860375..f814fb3a469d4d181dddea4107015e7ee2c49177 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Input device support"
+       depends on !S390
 
 config INPUT
        tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
index 55a72592704cf5e1a497ae2805f6ff3c3f802c85..b234729706be800789dced2c155629e2bb448d03 100644 (file)
@@ -336,7 +336,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 
        if (compat) {
                len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
-               if (len < maxlen)
+               if (len > maxlen)
                        len = maxlen;
 
                for (i = 0; i < len / sizeof(compat_long_t); i++)
index 3d4b619dadab98105e383bc5777a2f81fdb2e4a0..e759944041abd7c3a92b0849df88e34e59a47b92 100644 (file)
@@ -51,7 +51,7 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
 
 static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
+       unsigned int pin = (unsigned int) input_get_drvdata(dev);
        unsigned int count = 0;
 
        if (type != EV_SND)
index c90afeea54aa26ede05e85f3488e93edc601c43c..d42fe89cddf6987648eddd2200c8c01f33eda709 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "ISDN subsystem"
+       depends on !S390
 
 config ISDN
        tristate "ISDN support"
index c921d6c522f50ef257d825894b0f059bc9f11044..c92f9d764fce68f52158f80eb686d92701c4078f 100644 (file)
@@ -17,7 +17,7 @@ config CAPI_TRACE
        help
          If you say Y here, the kernelcapi driver can make verbose traces
          of CAPI messages. This feature can be enabled/disabled via IOCTL for
-         every controler (default disabled).
+         every controller (default disabled).
          This will increase the size of the kernelcapi module by 20 KB.
          If unsure, say Y.
 
index c8e1c357cec88870e4984233a93af30bb3bac70e..a1263019df5edec8543d25220b1e416b45a46b9e 100644 (file)
@@ -138,8 +138,6 @@ struct usb_cardstate {
        char                    bchars[6];              /* for request 0x19 */
 };
 
-struct usb_bc_state {};
-
 static inline unsigned tiocm_to_gigaset(unsigned state)
 {
        return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
@@ -579,25 +577,21 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
 
 static int gigaset_freebcshw(struct bc_state *bcs)
 {
-       if (!bcs->hw.usb)
-               return 0;
-       //FIXME
-       kfree(bcs->hw.usb);
+       /* unused */
        return 1;
 }
 
 /* Initialize the b-channel structure */
 static int gigaset_initbcshw(struct bc_state *bcs)
 {
-       bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL);
-       if (!bcs->hw.usb)
-               return 0;
-
+       /* unused */
+       bcs->hw.usb = NULL;
        return 1;
 }
 
 static void gigaset_reinitbcshw(struct bc_state *bcs)
 {
+       /* nothing to do for M10x */
 }
 
 static void gigaset_freecshw(struct cardstate *cs)
index af3eb9e795b500faba4eaa15eca11152b54c8872..85784a7ffb25bc6d7923b8d66fd38457346d38f9 100644 (file)
@@ -216,7 +216,7 @@ typedef struct
 #define SERIAL_HOOK_RING 0x85
 #define SERIAL_HOOK_DETACH 0x8f
  unsigned char Flags;           /* function refinements   */
- /* parameters passed by the the ATTACH request      */
+ /* parameters passed by the ATTACH request      */
  SERIAL_INT_CB InterruptHandler; /* called on each interrupt  */
  SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
  void   *HandlerContext; /* context for both handlers */
index 99e70d4103b6f32303d82a38c8624ea3c89bf023..1f18f19933876d08ba94e2e4fde007cd7c52fa6a 100644 (file)
@@ -1217,11 +1217,11 @@ usb_init(hfcusb_data * hfc)
        /* aux = output, reset off */
        write_usb(hfc, HFCUSB_CIRM, 0x10);
 
-       /* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+       /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
        write_usb(hfc, HFCUSB_USB_SIZE,
                  (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
 
-       /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+       /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
        write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
 
        /* enable PCM/GCI master mode */
index 703cc88d1ef974bcf8d0b27f7625f23d079aec4c..e8e37d826478842df2d95d7f4d65db77623c8dfe 100644 (file)
@@ -2,6 +2,7 @@
 # KVM configuration
 #
 menu "Virtualization"
+       depends on X86
 
 config KVM
        tristate "Kernel-based Virtual Machine (KVM) support"
index c8b8cfa332bb9e7ac9684b12e6efe1e60d06af1f..0d892600ff00f91f48301a871712cbe8e51bb730 100644 (file)
@@ -2889,7 +2889,9 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
 
        switch (val) {
        case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
                       cpu);
                decache_vcpus_on_cpu(cpu);
@@ -2897,6 +2899,7 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
                                         NULL, 0, 1);
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
                       cpu);
                smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
index 80acd08f0e97bd3b9cf940e5a25ccb2d31fce312..87d2046f866caa29b7e1b8f541b640789be3ec63 100644 (file)
@@ -1,5 +1,6 @@
 
 menu "LED devices"
+       depends on HAS_IOMEM
 
 config NEW_LEDS
        bool "LED Support"
index 1d49d2ade5579586d7418bcccc9e3a317695c9ab..677c99325be5add863bc487c3b942ccbdd5c5cbc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/leds/h1940-leds.c
+ * drivers/leds/leds-h1940.c
  * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
  *
  * This file is subject to the terms and conditions of the GNU General Public
index a32c91e27b3c466a98e3b6ee2b66d612f3255e88..58926da0ae18c48a977b38fd6d9c67fe879ba805 100644 (file)
@@ -237,7 +237,7 @@ config PMAC_RACKMETER
        tristate "Support for Apple XServe front panel LEDs"
        depends on PPC_PMAC
        help
-         This driver procides some support to control the front panel
+         This driver provides some support to control the front panel
           blue LEDs "vu-meter" of the XServer macs.
 
 endif # MACINTOSH_DRIVERS
index 0acf2f7fd9d725a3348d583306464211683021ac..c803d2bba65db3148a3bfd3060deebf4ae9a69af 100644 (file)
@@ -563,7 +563,7 @@ static void media_bay_step(int i)
                                ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
                                hw.irq = bay->cd_irq;
                                hw.chipset = ide_pmac;
-                               bay->cd_index = ide_register_hw(&hw, NULL);
+                               bay->cd_index = ide_register_hw(&hw, 0, NULL);
                                pmu_resume();
                        }
                        if (bay->cd_index == -1) {
index da862e4632dd0535b1c6047c3be5377b8f1bf1f8..67b8e9453b191a2c701970f4ccbdd4a5207dd1e3 100644 (file)
@@ -47,19 +47,25 @@ static int mca_bus_match (struct device *dev, struct device_driver *drv)
 {
        struct mca_device *mca_dev = to_mca_device (dev);
        struct mca_driver *mca_drv = to_mca_driver (drv);
-       const short *mca_ids = mca_drv->id_table;
-       int i;
-
-       if (!mca_ids)
-               return 0;
-
-       for(i = 0; mca_ids[i]; i++) {
-               if (mca_ids[i] == mca_dev->pos_id) {
-                       mca_dev->index = i;
-                       return 1;
+       const unsigned short *mca_ids = mca_drv->id_table;
+       int i = 0;
+
+       if (mca_ids) {
+               for(i = 0; mca_ids[i]; i++) {
+                       if (mca_ids[i] == mca_dev->pos_id) {
+                               mca_dev->index = i;
+                               return 1;
+                       }
                }
        }
-
+       /* If the integrated id is present, treat it as though it were an
+        * additional id in the id_table (it can't be because by definition,
+        * integrated id's overflow a short */
+       if (mca_drv->integrated_id && mca_dev->pos_id ==
+           mca_drv->integrated_id) {
+               mca_dev->index = i;
+               return 1;
+       }
        return 0;
 }
 
index 2223466b3d8a5d325abbf22ea3df1a69346add9b..32cd39bcc7152b5704d5746e6501dbd44724a99b 100644 (file)
@@ -36,12 +36,25 @@ int mca_register_driver(struct mca_driver *mca_drv)
                mca_drv->driver.bus = &mca_bus_type;
                if ((r = driver_register(&mca_drv->driver)) < 0)
                        return r;
+               mca_drv->integrated_id = 0;
        }
 
        return 0;
 }
 EXPORT_SYMBOL(mca_register_driver);
 
+int mca_register_driver_integrated(struct mca_driver *mca_driver,
+                                  int integrated_id)
+{
+       int r = mca_register_driver(mca_driver);
+
+       if (!r)
+               mca_driver->integrated_id = integrated_id;
+
+       return r;
+}
+EXPORT_SYMBOL(mca_register_driver_integrated);
+
 void mca_unregister_driver(struct mca_driver *mca_drv)
 {
        if (MCA_bus)
index 4540ade6b6b584385b11d65d337680c59ae96fc1..7df934d69134436cc2e1f5affb7f681dc0ab1671 100644 (file)
@@ -262,6 +262,15 @@ config DM_MULTIPATH_EMC
        ---help---
          Multipath support for EMC CX/AX series hardware.
 
+config DM_DELAY
+       tristate "I/O delaying target (EXPERIMENTAL)"
+       depends on BLK_DEV_DM && EXPERIMENTAL
+       ---help---
+       A target that delays reads and/or writes and can send
+       them to different devices.  Useful for testing.
+
+       If unsure, say N.
+
 endmenu
 
 endif
index 34957a68d9215ac08061706c58b0fd66dc499d9d..38754084eac741462bc677f8c6911b662c719623 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_MD_FAULTY)               += faulty.o
 obj-$(CONFIG_BLK_DEV_MD)       += md-mod.o
 obj-$(CONFIG_BLK_DEV_DM)       += dm-mod.o
 obj-$(CONFIG_DM_CRYPT)         += dm-crypt.o
+obj-$(CONFIG_DM_DELAY)         += dm-delay.o
 obj-$(CONFIG_DM_MULTIPATH)     += dm-multipath.o dm-round-robin.o
 obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
 obj-$(CONFIG_DM_SNAPSHOT)      += dm-snapshot.o
index da4349649f7f2cd5c7c6d628f40d8bf1a1463b84..c6be88826fae4d7aaea55ea0f6f8da7bf3b747ee 100644 (file)
@@ -8,17 +8,43 @@
 #define DM_BIO_LIST_H
 
 #include <linux/bio.h>
+#include <linux/prefetch.h>
 
 struct bio_list {
        struct bio *head;
        struct bio *tail;
 };
 
+static inline int bio_list_empty(const struct bio_list *bl)
+{
+       return bl->head == NULL;
+}
+
+#define BIO_LIST_INIT { .head = NULL, .tail = NULL }
+
+#define BIO_LIST(bl) \
+       struct bio_list bl = BIO_LIST_INIT
+
 static inline void bio_list_init(struct bio_list *bl)
 {
        bl->head = bl->tail = NULL;
 }
 
+#define bio_list_for_each(bio, bl) \
+       for (bio = (bl)->head; bio && ({ prefetch(bio->bi_next); 1; }); \
+            bio = bio->bi_next)
+
+static inline unsigned bio_list_size(const struct bio_list *bl)
+{
+       unsigned sz = 0;
+       struct bio *bio;
+
+       bio_list_for_each(bio, bl)
+               sz++;
+
+       return sz;
+}
+
 static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
 {
        bio->bi_next = NULL;
index d8121234c3471e9a4f1b609e1890f02e92970d59..7b0fcfc9eaa5fc0f724d3313360a304b6bbab3a6 100644 (file)
@@ -33,7 +33,6 @@
 struct crypt_io {
        struct dm_target *target;
        struct bio *base_bio;
-       struct bio *first_clone;
        struct work_struct work;
        atomic_t pending;
        int error;
@@ -107,6 +106,8 @@ struct crypt_config {
 
 static struct kmem_cache *_crypt_io_pool;
 
+static void clone_init(struct crypt_io *, struct bio *);
+
 /*
  * Different IV generation algorithms:
  *
@@ -120,6 +121,9 @@ static struct kmem_cache *_crypt_io_pool;
  * benbi: the 64-bit "big-endian 'narrow block'-count", starting at 1
  *        (needed for LRW-32-AES and possible other narrow block modes)
  *
+ * null: the initial vector is always zero.  Provides compatibility with
+ *       obsolete loop_fish2 devices.  Do not use for new devices.
+ *
  * plumb: unimplemented, see:
  * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
  */
@@ -256,6 +260,13 @@ static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
        return 0;
 }
 
+static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+       memset(iv, 0, cc->iv_size);
+
+       return 0;
+}
+
 static struct crypt_iv_operations crypt_iv_plain_ops = {
        .generator = crypt_iv_plain_gen
 };
@@ -272,6 +283,10 @@ static struct crypt_iv_operations crypt_iv_benbi_ops = {
        .generator = crypt_iv_benbi_gen
 };
 
+static struct crypt_iv_operations crypt_iv_null_ops = {
+       .generator = crypt_iv_null_gen
+};
+
 static int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
@@ -378,36 +393,21 @@ static int crypt_convert(struct crypt_config *cc,
  * This should never violate the device limitations
  * May return a smaller bio when running out of pages
  */
-static struct bio *
-crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
-                   struct bio *base_bio, unsigned int *bio_vec_idx)
+static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int size)
 {
+       struct crypt_config *cc = io->target->private;
        struct bio *clone;
        unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
        unsigned int i;
 
-       if (base_bio) {
-               clone = bio_alloc_bioset(GFP_NOIO, base_bio->bi_max_vecs, cc->bs);
-               __bio_clone(clone, base_bio);
-       } else
-               clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
-
+       clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
        if (!clone)
                return NULL;
 
-       clone->bi_destructor = dm_crypt_bio_destructor;
-
-       /* if the last bio was not complete, continue where that one ended */
-       clone->bi_idx = *bio_vec_idx;
-       clone->bi_vcnt = *bio_vec_idx;
-       clone->bi_size = 0;
-       clone->bi_flags &= ~(1 << BIO_SEG_VALID);
-
-       /* clone->bi_idx pages have already been allocated */
-       size -= clone->bi_idx * PAGE_SIZE;
+       clone_init(io, clone);
 
-       for (i = clone->bi_idx; i < nr_iovecs; i++) {
+       for (i = 0; i < nr_iovecs; i++) {
                struct bio_vec *bv = bio_iovec_idx(clone, i);
 
                bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
@@ -419,7 +419,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
                 * return a partially allocated bio, the caller will then try
                 * to allocate additional bios while submitting this partial bio
                 */
-               if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
+               if (i == (MIN_BIO_PAGES - 1))
                        gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
 
                bv->bv_offset = 0;
@@ -438,12 +438,6 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
                return NULL;
        }
 
-       /*
-        * Remember the last bio_vec allocated to be able
-        * to correctly continue after the splitting.
-        */
-       *bio_vec_idx = clone->bi_vcnt;
-
        return clone;
 }
 
@@ -495,9 +489,6 @@ static void dec_pending(struct crypt_io *io, int error)
        if (!atomic_dec_and_test(&io->pending))
                return;
 
-       if (io->first_clone)
-               bio_put(io->first_clone);
-
        bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
 
        mempool_free(io, cc->io_pool);
@@ -562,6 +553,7 @@ static void clone_init(struct crypt_io *io, struct bio *clone)
        clone->bi_end_io  = crypt_endio;
        clone->bi_bdev    = cc->dev->bdev;
        clone->bi_rw      = io->base_bio->bi_rw;
+       clone->bi_destructor = dm_crypt_bio_destructor;
 }
 
 static void process_read(struct crypt_io *io)
@@ -585,7 +577,6 @@ static void process_read(struct crypt_io *io)
        }
 
        clone_init(io, clone);
-       clone->bi_destructor = dm_crypt_bio_destructor;
        clone->bi_idx = 0;
        clone->bi_vcnt = bio_segments(base_bio);
        clone->bi_size = base_bio->bi_size;
@@ -604,7 +595,6 @@ static void process_write(struct crypt_io *io)
        struct convert_context ctx;
        unsigned remaining = base_bio->bi_size;
        sector_t sector = base_bio->bi_sector - io->target->begin;
-       unsigned bvec_idx = 0;
 
        atomic_inc(&io->pending);
 
@@ -615,14 +605,14 @@ static void process_write(struct crypt_io *io)
         * so repeat the whole process until all the data can be handled.
         */
        while (remaining) {
-               clone = crypt_alloc_buffer(cc, base_bio->bi_size,
-                                          io->first_clone, &bvec_idx);
+               clone = crypt_alloc_buffer(io, remaining);
                if (unlikely(!clone)) {
                        dec_pending(io, -ENOMEM);
                        return;
                }
 
                ctx.bio_out = clone;
+               ctx.idx_out = 0;
 
                if (unlikely(crypt_convert(cc, &ctx) < 0)) {
                        crypt_free_buffer_pages(cc, clone, clone->bi_size);
@@ -631,31 +621,26 @@ static void process_write(struct crypt_io *io)
                        return;
                }
 
-               clone_init(io, clone);
-               clone->bi_sector = cc->start + sector;
-
-               if (!io->first_clone) {
-                       /*
-                        * hold a reference to the first clone, because it
-                        * holds the bio_vec array and that can't be freed
-                        * before all other clones are released
-                        */
-                       bio_get(clone);
-                       io->first_clone = clone;
-               }
+               /* crypt_convert should have filled the clone bio */
+               BUG_ON(ctx.idx_out < clone->bi_vcnt);
 
+               clone->bi_sector = cc->start + sector;
                remaining -= clone->bi_size;
                sector += bio_sectors(clone);
 
-               /* prevent bio_put of first_clone */
+               /* Grab another reference to the io struct
+                * before we kick off the request */
                if (remaining)
                        atomic_inc(&io->pending);
 
                generic_make_request(clone);
 
+               /* Do not reference clone after this - it
+                * may be gone already. */
+
                /* out of memory -> run queues */
                if (remaining)
-                       congestion_wait(bio_data_dir(clone), HZ/100);
+                       congestion_wait(WRITE, HZ/100);
        }
 }
 
@@ -832,6 +817,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                cc->iv_gen_ops = &crypt_iv_essiv_ops;
        else if (strcmp(ivmode, "benbi") == 0)
                cc->iv_gen_ops = &crypt_iv_benbi_ops;
+       else if (strcmp(ivmode, "null") == 0)
+               cc->iv_gen_ops = &crypt_iv_null_ops;
        else {
                ti->error = "Invalid IV mode";
                goto bad2;
@@ -954,10 +941,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
        struct crypt_config *cc = ti->private;
        struct crypt_io *io;
 
+       if (bio_barrier(bio))
+               return -EOPNOTSUPP;
+
        io = mempool_alloc(cc->io_pool, GFP_NOIO);
        io->target = ti;
        io->base_bio = bio;
-       io->first_clone = NULL;
        io->error = io->post_process = 0;
        atomic_set(&io->pending, 0);
        kcryptd_queue_io(io);
@@ -1057,7 +1046,7 @@ error:
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version= {1, 3, 0},
+       .version= {1, 5, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
new file mode 100644 (file)
index 0000000..52c7cf9
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2005-2007 Red Hat GmbH
+ *
+ * A target that delays reads and/or writes and can send
+ * them to different devices.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+
+#include "dm.h"
+#include "dm-bio-list.h"
+
+#define DM_MSG_PREFIX "delay"
+
+struct delay_c {
+       struct timer_list delay_timer;
+       struct semaphore timer_lock;
+       struct work_struct flush_expired_bios;
+       struct list_head delayed_bios;
+       atomic_t may_delay;
+       mempool_t *delayed_pool;
+
+       struct dm_dev *dev_read;
+       sector_t start_read;
+       unsigned read_delay;
+       unsigned reads;
+
+       struct dm_dev *dev_write;
+       sector_t start_write;
+       unsigned write_delay;
+       unsigned writes;
+};
+
+struct delay_info {
+       struct delay_c *context;
+       struct list_head list;
+       struct bio *bio;
+       unsigned long expires;
+};
+
+static DEFINE_MUTEX(delayed_bios_lock);
+
+static struct workqueue_struct *kdelayd_wq;
+static struct kmem_cache *delayed_cache;
+
+static void handle_delayed_timer(unsigned long data)
+{
+       struct delay_c *dc = (struct delay_c *)data;
+
+       queue_work(kdelayd_wq, &dc->flush_expired_bios);
+}
+
+static void queue_timeout(struct delay_c *dc, unsigned long expires)
+{
+       down(&dc->timer_lock);
+
+       if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
+               mod_timer(&dc->delay_timer, expires);
+
+       up(&dc->timer_lock);
+}
+
+static void flush_bios(struct bio *bio)
+{
+       struct bio *n;
+
+       while (bio) {
+               n = bio->bi_next;
+               bio->bi_next = NULL;
+               generic_make_request(bio);
+               bio = n;
+       }
+}
+
+static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
+{
+       struct delay_info *delayed, *next;
+       unsigned long next_expires = 0;
+       int start_timer = 0;
+       BIO_LIST(flush_bios);
+
+       mutex_lock(&delayed_bios_lock);
+       list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
+               if (flush_all || time_after_eq(jiffies, delayed->expires)) {
+                       list_del(&delayed->list);
+                       bio_list_add(&flush_bios, delayed->bio);
+                       if ((bio_data_dir(delayed->bio) == WRITE))
+                               delayed->context->writes--;
+                       else
+                               delayed->context->reads--;
+                       mempool_free(delayed, dc->delayed_pool);
+                       continue;
+               }
+
+               if (!start_timer) {
+                       start_timer = 1;
+                       next_expires = delayed->expires;
+               } else
+                       next_expires = min(next_expires, delayed->expires);
+       }
+
+       mutex_unlock(&delayed_bios_lock);
+
+       if (start_timer)
+               queue_timeout(dc, next_expires);
+
+       return bio_list_get(&flush_bios);
+}
+
+static void flush_expired_bios(struct work_struct *work)
+{
+       struct delay_c *dc;
+
+       dc = container_of(work, struct delay_c, flush_expired_bios);
+       flush_bios(flush_delayed_bios(dc, 0));
+}
+
+/*
+ * Mapping parameters:
+ *    <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+ *
+ * With separate write parameters, the first set is only used for reads.
+ * Delays are specified in milliseconds.
+ */
+static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+       struct delay_c *dc;
+       unsigned long long tmpll;
+
+       if (argc != 3 && argc != 6) {
+               ti->error = "requires exactly 3 or 6 arguments";
+               return -EINVAL;
+       }
+
+       dc = kmalloc(sizeof(*dc), GFP_KERNEL);
+       if (!dc) {
+               ti->error = "Cannot allocate context";
+               return -ENOMEM;
+       }
+
+       dc->reads = dc->writes = 0;
+
+       if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+               ti->error = "Invalid device sector";
+               goto bad;
+       }
+       dc->start_read = tmpll;
+
+       if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+               ti->error = "Invalid delay";
+               goto bad;
+       }
+
+       if (dm_get_device(ti, argv[0], dc->start_read, ti->len,
+                         dm_table_get_mode(ti->table), &dc->dev_read)) {
+               ti->error = "Device lookup failed";
+               goto bad;
+       }
+
+       if (argc == 3) {
+               dc->dev_write = NULL;
+               goto out;
+       }
+
+       if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+               ti->error = "Invalid write device sector";
+               goto bad;
+       }
+       dc->start_write = tmpll;
+
+       if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+               ti->error = "Invalid write delay";
+               goto bad;
+       }
+
+       if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
+                         dm_table_get_mode(ti->table), &dc->dev_write)) {
+               ti->error = "Write device lookup failed";
+               dm_put_device(ti, dc->dev_read);
+               goto bad;
+       }
+
+out:
+       dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
+       if (!dc->delayed_pool) {
+               DMERR("Couldn't create delayed bio pool.");
+               goto bad;
+       }
+
+       init_timer(&dc->delay_timer);
+       dc->delay_timer.function = handle_delayed_timer;
+       dc->delay_timer.data = (unsigned long)dc;
+
+       INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
+       INIT_LIST_HEAD(&dc->delayed_bios);
+       init_MUTEX(&dc->timer_lock);
+       atomic_set(&dc->may_delay, 1);
+
+       ti->private = dc;
+       return 0;
+
+bad:
+       kfree(dc);
+       return -EINVAL;
+}
+
+static void delay_dtr(struct dm_target *ti)
+{
+       struct delay_c *dc = ti->private;
+
+       flush_workqueue(kdelayd_wq);
+
+       dm_put_device(ti, dc->dev_read);
+
+       if (dc->dev_write)
+               dm_put_device(ti, dc->dev_write);
+
+       mempool_destroy(dc->delayed_pool);
+       kfree(dc);
+}
+
+static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
+{
+       struct delay_info *delayed;
+       unsigned long expires = 0;
+
+       if (!delay || !atomic_read(&dc->may_delay))
+               return 1;
+
+       delayed = mempool_alloc(dc->delayed_pool, GFP_NOIO);
+
+       delayed->context = dc;
+       delayed->bio = bio;
+       delayed->expires = expires = jiffies + (delay * HZ / 1000);
+
+       mutex_lock(&delayed_bios_lock);
+
+       if (bio_data_dir(bio) == WRITE)
+               dc->writes++;
+       else
+               dc->reads++;
+
+       list_add_tail(&delayed->list, &dc->delayed_bios);
+
+       mutex_unlock(&delayed_bios_lock);
+
+       queue_timeout(dc, expires);
+
+       return 0;
+}
+
+static void delay_presuspend(struct dm_target *ti)
+{
+       struct delay_c *dc = ti->private;
+
+       atomic_set(&dc->may_delay, 0);
+       del_timer_sync(&dc->delay_timer);
+       flush_bios(flush_delayed_bios(dc, 1));
+}
+
+static void delay_resume(struct dm_target *ti)
+{
+       struct delay_c *dc = ti->private;
+
+       atomic_set(&dc->may_delay, 1);
+}
+
+static int delay_map(struct dm_target *ti, struct bio *bio,
+                    union map_info *map_context)
+{
+       struct delay_c *dc = ti->private;
+
+       if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
+               bio->bi_bdev = dc->dev_write->bdev;
+               bio->bi_sector = dc->start_write +
+                                (bio->bi_sector - ti->begin);
+
+               return delay_bio(dc, dc->write_delay, bio);
+       }
+
+       bio->bi_bdev = dc->dev_read->bdev;
+       bio->bi_sector = dc->start_read +
+                        (bio->bi_sector - ti->begin);
+
+       return delay_bio(dc, dc->read_delay, bio);
+}
+
+static int delay_status(struct dm_target *ti, status_type_t type,
+                       char *result, unsigned maxlen)
+{
+       struct delay_c *dc = ti->private;
+       int sz = 0;
+
+       switch (type) {
+       case STATUSTYPE_INFO:
+               DMEMIT("%u %u", dc->reads, dc->writes);
+               break;
+
+       case STATUSTYPE_TABLE:
+               DMEMIT("%s %llu %u", dc->dev_read->name,
+                      (unsigned long long) dc->start_read,
+                      dc->read_delay);
+               if (dc->dev_write)
+                       DMEMIT("%s %llu %u", dc->dev_write->name,
+                              (unsigned long long) dc->start_write,
+                              dc->write_delay);
+               break;
+       }
+
+       return 0;
+}
+
+static struct target_type delay_target = {
+       .name        = "delay",
+       .version     = {1, 0, 2},
+       .module      = THIS_MODULE,
+       .ctr         = delay_ctr,
+       .dtr         = delay_dtr,
+       .map         = delay_map,
+       .presuspend  = delay_presuspend,
+       .resume      = delay_resume,
+       .status      = delay_status,
+};
+
+static int __init dm_delay_init(void)
+{
+       int r = -ENOMEM;
+
+       kdelayd_wq = create_workqueue("kdelayd");
+       if (!kdelayd_wq) {
+               DMERR("Couldn't start kdelayd");
+               goto bad_queue;
+       }
+
+       delayed_cache = kmem_cache_create("dm-delay",
+                                         sizeof(struct delay_info),
+                                         __alignof__(struct delay_info),
+                                         0, NULL, NULL);
+       if (!delayed_cache) {
+               DMERR("Couldn't create delayed bio cache.");
+               goto bad_memcache;
+       }
+
+       r = dm_register_target(&delay_target);
+       if (r < 0) {
+               DMERR("register failed %d", r);
+               goto bad_register;
+       }
+
+       return 0;
+
+bad_register:
+       kmem_cache_destroy(delayed_cache);
+bad_memcache:
+       destroy_workqueue(kdelayd_wq);
+bad_queue:
+       return r;
+}
+
+static void __exit dm_delay_exit(void)
+{
+       int r = dm_unregister_target(&delay_target);
+
+       if (r < 0)
+               DMERR("unregister failed %d", r);
+
+       kmem_cache_destroy(delayed_cache);
+       destroy_workqueue(kdelayd_wq);
+}
+
+/* Module hooks */
+module_init(dm_delay_init);
+module_exit(dm_delay_exit);
+
+MODULE_DESCRIPTION(DM_NAME " delay target");
+MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
+MODULE_LICENSE("GPL");
index 99cdffa7fbfe0a4522330099dd80ca810f3dc796..07e0a0c84f6ef9f8d93da5b914f22dfc0f9c47fc 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * dm-snapshot.c
+ * dm-exception-store.c
  *
  * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  */
@@ -123,6 +124,7 @@ struct pstore {
        atomic_t pending_count;
        uint32_t callback_count;
        struct commit_callback *callbacks;
+       struct dm_io_client *io_client;
 };
 
 static inline unsigned int sectors_to_pages(unsigned int sectors)
@@ -159,14 +161,20 @@ static void free_area(struct pstore *ps)
  */
 static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
 {
-       struct io_region where;
-       unsigned long bits;
-
-       where.bdev = ps->snap->cow->bdev;
-       where.sector = ps->snap->chunk_size * chunk;
-       where.count = ps->snap->chunk_size;
-
-       return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
+       struct io_region where = {
+               .bdev = ps->snap->cow->bdev,
+               .sector = ps->snap->chunk_size * chunk,
+               .count = ps->snap->chunk_size,
+       };
+       struct dm_io_request io_req = {
+               .bi_rw = rw,
+               .mem.type = DM_IO_VMA,
+               .mem.ptr.vma = ps->area,
+               .client = ps->io_client,
+               .notify.fn = NULL,
+       };
+
+       return dm_io(&io_req, 1, &where, NULL);
 }
 
 /*
@@ -213,17 +221,18 @@ static int read_header(struct pstore *ps, int *new_snapshot)
                chunk_size_supplied = 0;
        }
 
-       r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
-       if (r)
-               return r;
+       ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+                                                            chunk_size));
+       if (IS_ERR(ps->io_client))
+               return PTR_ERR(ps->io_client);
 
        r = alloc_area(ps);
        if (r)
-               goto bad1;
+               return r;
 
        r = chunk_io(ps, 0, READ);
        if (r)
-               goto bad2;
+               goto bad;
 
        dh = (struct disk_header *) ps->area;
 
@@ -235,7 +244,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
        if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
                DMWARN("Invalid or corrupt snapshot");
                r = -ENXIO;
-               goto bad2;
+               goto bad;
        }
 
        *new_snapshot = 0;
@@ -252,27 +261,22 @@ static int read_header(struct pstore *ps, int *new_snapshot)
               (unsigned long long)ps->snap->chunk_size);
 
        /* We had a bogus chunk_size. Fix stuff up. */
-       dm_io_put(sectors_to_pages(ps->snap->chunk_size));
        free_area(ps);
 
        ps->snap->chunk_size = chunk_size;
        ps->snap->chunk_mask = chunk_size - 1;
        ps->snap->chunk_shift = ffs(chunk_size) - 1;
 
-       r = dm_io_get(sectors_to_pages(chunk_size));
+       r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+                               ps->io_client);
        if (r)
                return r;
 
        r = alloc_area(ps);
-       if (r)
-               goto bad1;
-
-       return 0;
+       return r;
 
-bad2:
+bad:
        free_area(ps);
-bad1:
-       dm_io_put(sectors_to_pages(ps->snap->chunk_size));
        return r;
 }
 
@@ -405,7 +409,7 @@ static void persistent_destroy(struct exception_store *store)
 {
        struct pstore *ps = get_info(store);
 
-       dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+       dm_io_client_destroy(ps->io_client);
        vfree(ps->callbacks);
        free_area(ps);
        kfree(ps);
index 32eff28e4adc889f339ae7e75345c2aea42af5cf..e0832e6fcf36c0747c06ae3035c12567e80df797 100644 (file)
@@ -16,6 +16,7 @@
 struct hw_handler_type;
 struct hw_handler {
        struct hw_handler_type *type;
+       struct mapped_device *md;
        void *context;
 };
 
index 8bdc8a87b249c4b9a0b46ab0e22308e30ed7c1d6..352c6fbeac53a19dd82f8ef6994b733da4ad931d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  */
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-static struct bio_set *_bios;
+struct dm_io_client {
+       mempool_t *pool;
+       struct bio_set *bios;
+};
 
 /* FIXME: can we shrink this ? */
 struct io {
        unsigned long error;
        atomic_t count;
        struct task_struct *sleeper;
+       struct dm_io_client *client;
        io_notify_fn callback;
        void *context;
 };
@@ -26,63 +31,58 @@ struct io {
 /*
  * io contexts are only dynamically allocated for asynchronous
  * io.  Since async io is likely to be the majority of io we'll
- * have the same number of io contexts as buffer heads ! (FIXME:
- * must reduce this).
+ * have the same number of io contexts as bios! (FIXME: must reduce this).
  */
-static unsigned _num_ios;
-static mempool_t *_io_pool;
 
 static unsigned int pages_to_ios(unsigned int pages)
 {
        return 4 * pages;       /* too many ? */
 }
 
-static int resize_pool(unsigned int new_ios)
+/*
+ * Create a client with mempool and bioset.
+ */
+struct dm_io_client *dm_io_client_create(unsigned num_pages)
 {
-       int r = 0;
-
-       if (_io_pool) {
-               if (new_ios == 0) {
-                       /* free off the pool */
-                       mempool_destroy(_io_pool);
-                       _io_pool = NULL;
-                       bioset_free(_bios);
-
-               } else {
-                       /* resize the pool */
-                       r = mempool_resize(_io_pool, new_ios, GFP_KERNEL);
-               }
+       unsigned ios = pages_to_ios(num_pages);
+       struct dm_io_client *client;
 
-       } else {
-               /* create new pool */
-               _io_pool = mempool_create_kmalloc_pool(new_ios,
-                                                      sizeof(struct io));
-               if (!_io_pool)
-                       return -ENOMEM;
-
-               _bios = bioset_create(16, 16);
-               if (!_bios) {
-                       mempool_destroy(_io_pool);
-                       _io_pool = NULL;
-                       return -ENOMEM;
-               }
-       }
+       client = kmalloc(sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return ERR_PTR(-ENOMEM);
+
+       client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io));
+       if (!client->pool)
+               goto bad;
 
-       if (!r)
-               _num_ios = new_ios;
+       client->bios = bioset_create(16, 16);
+       if (!client->bios)
+               goto bad;
 
-       return r;
+       return client;
+
+   bad:
+       if (client->pool)
+               mempool_destroy(client->pool);
+       kfree(client);
+       return ERR_PTR(-ENOMEM);
 }
+EXPORT_SYMBOL(dm_io_client_create);
 
-int dm_io_get(unsigned int num_pages)
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client)
 {
-       return resize_pool(_num_ios + pages_to_ios(num_pages));
+       return mempool_resize(client->pool, pages_to_ios(num_pages),
+                             GFP_KERNEL);
 }
+EXPORT_SYMBOL(dm_io_client_resize);
 
-void dm_io_put(unsigned int num_pages)
+void dm_io_client_destroy(struct dm_io_client *client)
 {
-       resize_pool(_num_ios - pages_to_ios(num_pages));
+       mempool_destroy(client->pool);
+       bioset_free(client->bios);
+       kfree(client);
 }
+EXPORT_SYMBOL(dm_io_client_destroy);
 
 /*-----------------------------------------------------------------
  * We need to keep track of which region a bio is doing io for.
@@ -118,7 +118,7 @@ static void dec_count(struct io *io, unsigned int region, int error)
                        io_notify_fn fn = io->callback;
                        void *context = io->context;
 
-                       mempool_free(io, _io_pool);
+                       mempool_free(io, io->client->pool);
                        fn(r, context);
                }
        }
@@ -126,7 +126,8 @@ static void dec_count(struct io *io, unsigned int region, int error)
 
 static int endio(struct bio *bio, unsigned int done, int error)
 {
-       struct io *io = (struct io *) bio->bi_private;
+       struct io *io;
+       unsigned region;
 
        /* keep going until we've finished */
        if (bio->bi_size)
@@ -135,10 +136,17 @@ static int endio(struct bio *bio, unsigned int done, int error)
        if (error && bio_data_dir(bio) == READ)
                zero_fill_bio(bio);
 
-       dec_count(io, bio_get_region(bio), error);
+       /*
+        * The bio destructor in bio_put() may use the io object.
+        */
+       io = bio->bi_private;
+       region = bio_get_region(bio);
+
        bio->bi_max_vecs++;
        bio_put(bio);
 
+       dec_count(io, region, error);
+
        return 0;
 }
 
@@ -209,6 +217,9 @@ static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec)
        dp->context_ptr = bvec;
 }
 
+/*
+ * Functions for getting the pages from a VMA.
+ */
 static void vm_get_page(struct dpages *dp,
                 struct page **p, unsigned long *len, unsigned *offset)
 {
@@ -233,7 +244,34 @@ static void vm_dp_init(struct dpages *dp, void *data)
 
 static void dm_bio_destructor(struct bio *bio)
 {
-       bio_free(bio, _bios);
+       struct io *io = bio->bi_private;
+
+       bio_free(bio, io->client->bios);
+}
+
+/*
+ * Functions for getting the pages from kernel memory.
+ */
+static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len,
+                       unsigned *offset)
+{
+       *p = virt_to_page(dp->context_ptr);
+       *offset = dp->context_u;
+       *len = PAGE_SIZE - dp->context_u;
+}
+
+static void km_next_page(struct dpages *dp)
+{
+       dp->context_ptr += PAGE_SIZE - dp->context_u;
+       dp->context_u = 0;
+}
+
+static void km_dp_init(struct dpages *dp, void *data)
+{
+       dp->get_page = km_get_page;
+       dp->next_page = km_next_page;
+       dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+       dp->context_ptr = data;
 }
 
 /*-----------------------------------------------------------------
@@ -256,7 +294,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
                 * to hide it from bio_add_page().
                 */
                num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
-               bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
+               bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
                bio->bi_sector = where->sector + (where->count - remaining);
                bio->bi_bdev = where->bdev;
                bio->bi_end_io = endio;
@@ -311,8 +349,9 @@ static void dispatch_io(int rw, unsigned int num_regions,
        dec_count(io, 0, 0);
 }
 
-static int sync_io(unsigned int num_regions, struct io_region *where,
-           int rw, struct dpages *dp, unsigned long *error_bits)
+static int sync_io(struct dm_io_client *client, unsigned int num_regions,
+                  struct io_region *where, int rw, struct dpages *dp,
+                  unsigned long *error_bits)
 {
        struct io io;
 
@@ -324,6 +363,7 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
        io.error = 0;
        atomic_set(&io.count, 1); /* see dispatch_io() */
        io.sleeper = current;
+       io.client = client;
 
        dispatch_io(rw, num_regions, where, dp, &io, 1);
 
@@ -340,12 +380,15 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
        if (atomic_read(&io.count))
                return -EINTR;
 
-       *error_bits = io.error;
+       if (error_bits)
+               *error_bits = io.error;
+
        return io.error ? -EIO : 0;
 }
 
-static int async_io(unsigned int num_regions, struct io_region *where, int rw,
-            struct dpages *dp, io_notify_fn fn, void *context)
+static int async_io(struct dm_io_client *client, unsigned int num_regions,
+                   struct io_region *where, int rw, struct dpages *dp,
+                   io_notify_fn fn, void *context)
 {
        struct io *io;
 
@@ -355,10 +398,11 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
                return -EIO;
        }
 
-       io = mempool_alloc(_io_pool, GFP_NOIO);
+       io = mempool_alloc(client->pool, GFP_NOIO);
        io->error = 0;
        atomic_set(&io->count, 1); /* see dispatch_io() */
        io->sleeper = NULL;
+       io->client = client;
        io->callback = fn;
        io->context = context;
 
@@ -366,61 +410,51 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
        return 0;
 }
 
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
-              struct page_list *pl, unsigned int offset,
-              unsigned long *error_bits)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
 {
-       struct dpages dp;
-       list_dp_init(&dp, pl, offset);
-       return sync_io(num_regions, where, rw, &dp, error_bits);
-}
+       /* Set up dpages based on memory type */
+       switch (io_req->mem.type) {
+       case DM_IO_PAGE_LIST:
+               list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
+               break;
+
+       case DM_IO_BVEC:
+               bvec_dp_init(dp, io_req->mem.ptr.bvec);
+               break;
+
+       case DM_IO_VMA:
+               vm_dp_init(dp, io_req->mem.ptr.vma);
+               break;
+
+       case DM_IO_KMEM:
+               km_dp_init(dp, io_req->mem.ptr.addr);
+               break;
+
+       default:
+               return -EINVAL;
+       }
 
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
-                   struct bio_vec *bvec, unsigned long *error_bits)
-{
-       struct dpages dp;
-       bvec_dp_init(&dp, bvec);
-       return sync_io(num_regions, where, rw, &dp, error_bits);
+       return 0;
 }
 
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
-                 void *data, unsigned long *error_bits)
+/*
+ * New collapsed (a)synchronous interface
+ */
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+         struct io_region *where, unsigned long *sync_error_bits)
 {
+       int r;
        struct dpages dp;
-       vm_dp_init(&dp, data);
-       return sync_io(num_regions, where, rw, &dp, error_bits);
-}
 
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
-               struct page_list *pl, unsigned int offset,
-               io_notify_fn fn, void *context)
-{
-       struct dpages dp;
-       list_dp_init(&dp, pl, offset);
-       return async_io(num_regions, where, rw, &dp, fn, context);
-}
+       r = dp_init(io_req, &dp);
+       if (r)
+               return r;
 
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
-                    struct bio_vec *bvec, io_notify_fn fn, void *context)
-{
-       struct dpages dp;
-       bvec_dp_init(&dp, bvec);
-       return async_io(num_regions, where, rw, &dp, fn, context);
-}
+       if (!io_req->notify.fn)
+               return sync_io(io_req->client, num_regions, where,
+                              io_req->bi_rw, &dp, sync_error_bits);
 
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
-                  void *data, io_notify_fn fn, void *context)
-{
-       struct dpages dp;
-       vm_dp_init(&dp, data);
-       return async_io(num_regions, where, rw, &dp, fn, context);
+       return async_io(io_req->client, num_regions, where, io_req->bi_rw,
+                       &dp, io_req->notify.fn, io_req->notify.context);
 }
-
-EXPORT_SYMBOL(dm_io_get);
-EXPORT_SYMBOL(dm_io_put);
-EXPORT_SYMBOL(dm_io_sync);
-EXPORT_SYMBOL(dm_io_async);
-EXPORT_SYMBOL(dm_io_sync_bvec);
-EXPORT_SYMBOL(dm_io_async_bvec);
-EXPORT_SYMBOL(dm_io_sync_vm);
-EXPORT_SYMBOL(dm_io_async_vm);
+EXPORT_SYMBOL(dm_io);
index f9035bfd1a9f73aa8f8854a6c24c76a9790e7eef..f647e2cceaa673f8098fce058832a3cc55ce23c4 100644 (file)
@@ -12,7 +12,7 @@
 struct io_region {
        struct block_device *bdev;
        sector_t sector;
-       sector_t count;
+       sector_t count;         /* If this is zero the region is ignored. */
 };
 
 struct page_list {
@@ -20,55 +20,60 @@ struct page_list {
        struct page *page;
 };
 
-
-/*
- * 'error' is a bitset, with each bit indicating whether an error
- * occurred doing io to the corresponding region.
- */
 typedef void (*io_notify_fn)(unsigned long error, void *context);
 
+enum dm_io_mem_type {
+       DM_IO_PAGE_LIST,/* Page list */
+       DM_IO_BVEC,     /* Bio vector */
+       DM_IO_VMA,      /* Virtual memory area */
+       DM_IO_KMEM,     /* Kernel memory */
+};
+
+struct dm_io_memory {
+       enum dm_io_mem_type type;
+
+       union {
+               struct page_list *pl;
+               struct bio_vec *bvec;
+               void *vma;
+               void *addr;
+       } ptr;
+
+       unsigned offset;
+};
+
+struct dm_io_notify {
+       io_notify_fn fn;        /* Callback for asynchronous requests */
+       void *context;          /* Passed to callback */
+};
 
 /*
- * Before anyone uses the IO interface they should call
- * dm_io_get(), specifying roughly how many pages they are
- * expecting to perform io on concurrently.
- *
- * This function may block.
+ * IO request structure
  */
-int dm_io_get(unsigned int num_pages);
-void dm_io_put(unsigned int num_pages);
+struct dm_io_client;
+struct dm_io_request {
+       int bi_rw;                      /* READ|WRITE - not READA */
+       struct dm_io_memory mem;        /* Memory to use for io */
+       struct dm_io_notify notify;     /* Synchronous if notify.fn is NULL */
+       struct dm_io_client *client;    /* Client memory handler */
+};
 
 /*
- * Synchronous IO.
+ * For async io calls, users can alternatively use the dm_io() function below
+ * and dm_io_client_create() to create private mempools for the client.
  *
- * Please ensure that the rw flag in the next two functions is
- * either READ or WRITE, ie. we don't take READA.  Any
- * regions with a zero count field will be ignored.
+ * Create/destroy may block.
  */
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
-              struct page_list *pl, unsigned int offset,
-              unsigned long *error_bits);
-
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
-                   struct bio_vec *bvec, unsigned long *error_bits);
-
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
-                 void *data, unsigned long *error_bits);
+struct dm_io_client *dm_io_client_create(unsigned num_pages);
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client);
+void dm_io_client_destroy(struct dm_io_client *client);
 
 /*
- * Aynchronous IO.
- *
- * The 'where' array may be safely allocated on the stack since
- * the function takes a copy.
+ * IO interface using private per-client pools.
+ * Each bit in the optional 'sync_error_bits' bitset indicates whether an
+ * error occurred doing io to the corresponding region.
  */
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
-               struct page_list *pl, unsigned int offset,
-               io_notify_fn fn, void *context);
-
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
-                    struct bio_vec *bvec, io_notify_fn fn, void *context);
-
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
-                  void *data, io_notify_fn fn, void *context);
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+         struct io_region *region, unsigned long *sync_error_bits);
 
 #endif
index 6a9261351848ba7e3272de48a51d100345a45a7f..a66428d860fef830d3fddc6d8f48140d7a646a4b 100644 (file)
@@ -149,9 +149,12 @@ struct log_c {
                FORCESYNC,      /* Force a sync to happen */
        } sync;
 
+       struct dm_io_request io_req;
+
        /*
         * Disk log fields
         */
+       int log_dev_failed;
        struct dm_dev *log_dev;
        struct log_header header;
 
@@ -199,13 +202,20 @@ static void header_from_disk(struct log_header *core, struct log_header *disk)
        core->nr_regions = le64_to_cpu(disk->nr_regions);
 }
 
+static int rw_header(struct log_c *lc, int rw)
+{
+       lc->io_req.bi_rw = rw;
+       lc->io_req.mem.ptr.vma = lc->disk_header;
+       lc->io_req.notify.fn = NULL;
+
+       return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
+}
+
 static int read_header(struct log_c *log)
 {
        int r;
-       unsigned long ebits;
 
-       r = dm_io_sync_vm(1, &log->header_location, READ,
-                         log->disk_header, &ebits);
+       r = rw_header(log, READ);
        if (r)
                return r;
 
@@ -233,11 +243,8 @@ static int read_header(struct log_c *log)
 
 static inline int write_header(struct log_c *log)
 {
-       unsigned long ebits;
-
        header_to_disk(&log->header, log->disk_header);
-       return dm_io_sync_vm(1, &log->header_location, WRITE,
-                            log->disk_header, &ebits);
+       return rw_header(log, WRITE);
 }
 
 /*----------------------------------------------------------------
@@ -256,6 +263,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
        uint32_t region_size;
        unsigned int region_count;
        size_t bitset_size, buf_size;
+       int r;
 
        if (argc < 1 || argc > 2) {
                DMWARN("wrong number of arguments to mirror log");
@@ -315,6 +323,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
                lc->disk_header = NULL;
        } else {
                lc->log_dev = dev;
+               lc->log_dev_failed = 0;
                lc->header_location.bdev = lc->log_dev->bdev;
                lc->header_location.sector = 0;
 
@@ -324,6 +333,15 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
                buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
                                       bitset_size, ti->limits.hardsect_size);
                lc->header_location.count = buf_size >> SECTOR_SHIFT;
+               lc->io_req.mem.type = DM_IO_VMA;
+               lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
+                                                                  PAGE_SIZE));
+               if (IS_ERR(lc->io_req.client)) {
+                       r = PTR_ERR(lc->io_req.client);
+                       DMWARN("couldn't allocate disk io client");
+                       kfree(lc);
+                       return -ENOMEM;
+               }
 
                lc->disk_header = vmalloc(buf_size);
                if (!lc->disk_header) {
@@ -424,6 +442,7 @@ static void disk_dtr(struct dirty_log *log)
 
        dm_put_device(lc->ti, lc->log_dev);
        vfree(lc->disk_header);
+       dm_io_client_destroy(lc->io_req.client);
        destroy_log_context(lc);
 }
 
@@ -437,6 +456,15 @@ static int count_bits32(uint32_t *addr, unsigned size)
        return count;
 }
 
+static void fail_log_device(struct log_c *lc)
+{
+       if (lc->log_dev_failed)
+               return;
+
+       lc->log_dev_failed = 1;
+       dm_table_event(lc->ti->table);
+}
+
 static int disk_resume(struct dirty_log *log)
 {
        int r;
@@ -446,8 +474,19 @@ static int disk_resume(struct dirty_log *log)
 
        /* read the disk header */
        r = read_header(lc);
-       if (r)
-               return r;
+       if (r) {
+               DMWARN("%s: Failed to read header on mirror log device",
+                      lc->log_dev->name);
+               fail_log_device(lc);
+               /*
+                * If the log device cannot be read, we must assume
+                * all regions are out-of-sync.  If we simply return
+                * here, the state will be uninitialized and could
+                * lead us to return 'in-sync' status for regions
+                * that are actually 'out-of-sync'.
+                */
+               lc->header.nr_regions = 0;
+       }
 
        /* set or clear any new bits -- device has grown */
        if (lc->sync == NOSYNC)
@@ -472,7 +511,14 @@ static int disk_resume(struct dirty_log *log)
        lc->header.nr_regions = lc->region_count;
 
        /* write the new header */
-       return write_header(lc);
+       r = write_header(lc);
+       if (r) {
+               DMWARN("%s: Failed to write header on mirror log device",
+                      lc->log_dev->name);
+               fail_log_device(lc);
+       }
+
+       return r;
 }
 
 static uint32_t core_get_region_size(struct dirty_log *log)
@@ -516,7 +562,9 @@ static int disk_flush(struct dirty_log *log)
                return 0;
 
        r = write_header(lc);
-       if (!r)
+       if (r)
+               fail_log_device(lc);
+       else
                lc->touched = 0;
 
        return r;
@@ -591,6 +639,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
 
        switch(status) {
        case STATUSTYPE_INFO:
+               DMEMIT("1 %s", log->type->name);
                break;
 
        case STATUSTYPE_TABLE:
@@ -606,17 +655,17 @@ static int disk_status(struct dirty_log *log, status_type_t status,
                       char *result, unsigned int maxlen)
 {
        int sz = 0;
-       char buffer[16];
        struct log_c *lc = log->context;
 
        switch(status) {
        case STATUSTYPE_INFO:
+               DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
+                      lc->log_dev_failed ? 'D' : 'A');
                break;
 
        case STATUSTYPE_TABLE:
-               format_dev_t(buffer, lc->log_dev->bdev->bd_dev);
                DMEMIT("%s %u %s %u ", log->type->name,
-                      lc->sync == DEFAULTSYNC ? 2 : 3, buffer,
+                      lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
                       lc->region_size);
                DMEMIT_SYNC;
        }
index 3aa0135069672d8fe7f3ed4c6e743d969478c95f..de54b39e6ffe9fb78cbad18c2a5d5b559d54d870 100644 (file)
@@ -668,6 +668,9 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
                return -EINVAL;
        }
 
+       m->hw_handler.md = dm_table_get_md(ti->table);
+       dm_put(m->hw_handler.md);
+
        r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
        if (r) {
                dm_put_hw_handler(hwht);
index 23a642619bedfbbe76137f2d1e8d174782622f4e..ef124b71ccc8f1dfd9aa0fdfad0fad81010b0613 100644 (file)
 #include <linux/workqueue.h>
 
 #define DM_MSG_PREFIX "raid1"
+#define DM_IO_PAGES 64
 
-static struct workqueue_struct *_kmirrord_wq;
-static struct work_struct _kmirrord_work;
-static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
+#define DM_RAID1_HANDLE_ERRORS 0x01
 
-static inline void wake(void)
-{
-       queue_work(_kmirrord_wq, &_kmirrord_work);
-}
+static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
 
 /*-----------------------------------------------------------------
  * Region hash
@@ -125,17 +121,23 @@ struct mirror_set {
        struct list_head list;
        struct region_hash rh;
        struct kcopyd_client *kcopyd_client;
+       uint64_t features;
 
        spinlock_t lock;        /* protects the next two lists */
        struct bio_list reads;
        struct bio_list writes;
 
+       struct dm_io_client *io_client;
+
        /* recovery */
        region_t nr_regions;
        int in_sync;
 
        struct mirror *default_mirror;  /* Default mirror */
 
+       struct workqueue_struct *kmirrord_wq;
+       struct work_struct kmirrord_work;
+
        unsigned int nr_mirrors;
        struct mirror mirror[0];
 };
@@ -153,6 +155,11 @@ static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
        return region << rh->region_shift;
 }
 
+static void wake(struct mirror_set *ms)
+{
+       queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
+}
+
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
@@ -398,8 +405,7 @@ static void rh_update_states(struct region_hash *rh)
                mempool_free(reg, rh->region_pool);
        }
 
-       if (!list_empty(&recovered))
-               rh->log->type->flush(rh->log);
+       rh->log->type->flush(rh->log);
 
        list_for_each_entry_safe (reg, next, &clean, list)
                mempool_free(reg, rh->region_pool);
@@ -471,7 +477,7 @@ static void rh_dec(struct region_hash *rh, region_t region)
        spin_unlock_irqrestore(&rh->region_lock, flags);
 
        if (should_wake)
-               wake();
+               wake(rh->ms);
 }
 
 /*
@@ -558,7 +564,7 @@ static void rh_recovery_end(struct region *reg, int success)
        list_add(&reg->list, &reg->rh->recovered_regions);
        spin_unlock_irq(&rh->region_lock);
 
-       wake();
+       wake(rh->ms);
 }
 
 static void rh_flush(struct region_hash *rh)
@@ -592,7 +598,7 @@ static void rh_start_recovery(struct region_hash *rh)
        for (i = 0; i < MAX_RECOVERY; i++)
                up(&rh->recovery_count);
 
-       wake();
+       wake(rh->ms);
 }
 
 /*
@@ -735,7 +741,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
                /*
                 * We can only read balance if the region is in sync.
                 */
-               if (rh_in_sync(&ms->rh, region, 0))
+               if (rh_in_sync(&ms->rh, region, 1))
                        m = choose_mirror(ms, bio->bi_sector);
                else
                        m = ms->default_mirror;
@@ -792,6 +798,14 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        unsigned int i;
        struct io_region io[KCOPYD_MAX_REGIONS+1];
        struct mirror *m;
+       struct dm_io_request io_req = {
+               .bi_rw = WRITE,
+               .mem.type = DM_IO_BVEC,
+               .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+               .notify.fn = write_callback,
+               .notify.context = bio,
+               .client = ms->io_client,
+       };
 
        for (i = 0; i < ms->nr_mirrors; i++) {
                m = ms->mirror + i;
@@ -802,9 +816,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        }
 
        bio_set_ms(bio, ms);
-       dm_io_async_bvec(ms->nr_mirrors, io, WRITE,
-                        bio->bi_io_vec + bio->bi_idx,
-                        write_callback, bio);
+
+       (void) dm_io(&io_req, ms->nr_mirrors, io, NULL);
 }
 
 static void do_writes(struct mirror_set *ms, struct bio_list *writes)
@@ -870,11 +883,10 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
 /*-----------------------------------------------------------------
  * kmirrord
  *---------------------------------------------------------------*/
-static LIST_HEAD(_mirror_sets);
-static DECLARE_RWSEM(_mirror_sets_lock);
-
-static void do_mirror(struct mirror_set *ms)
+static void do_mirror(struct work_struct *work)
 {
+       struct mirror_set *ms =container_of(work, struct mirror_set,
+                                           kmirrord_work);
        struct bio_list reads, writes;
 
        spin_lock(&ms->lock);
@@ -890,16 +902,6 @@ static void do_mirror(struct mirror_set *ms)
        do_writes(ms, &writes);
 }
 
-static void do_work(struct work_struct *ignored)
-{
-       struct mirror_set *ms;
-
-       down_read(&_mirror_sets_lock);
-       list_for_each_entry (ms, &_mirror_sets, list)
-               do_mirror(ms);
-       up_read(&_mirror_sets_lock);
-}
-
 /*-----------------------------------------------------------------
  * Target functions
  *---------------------------------------------------------------*/
@@ -931,6 +933,13 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
        ms->in_sync = 0;
        ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
 
+       ms->io_client = dm_io_client_create(DM_IO_PAGES);
+       if (IS_ERR(ms->io_client)) {
+               ti->error = "Error creating dm_io client";
+               kfree(ms);
+               return NULL;
+       }
+
        if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
                ti->error = "Error creating dirty region hash";
                kfree(ms);
@@ -946,6 +955,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
        while (m--)
                dm_put_device(ti, ms->mirror[m].dev);
 
+       dm_io_client_destroy(ms->io_client);
        rh_exit(&ms->rh);
        kfree(ms);
 }
@@ -978,23 +988,6 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
        return 0;
 }
 
-static int add_mirror_set(struct mirror_set *ms)
-{
-       down_write(&_mirror_sets_lock);
-       list_add_tail(&ms->list, &_mirror_sets);
-       up_write(&_mirror_sets_lock);
-       wake();
-
-       return 0;
-}
-
-static void del_mirror_set(struct mirror_set *ms)
-{
-       down_write(&_mirror_sets_lock);
-       list_del(&ms->list);
-       up_write(&_mirror_sets_lock);
-}
-
 /*
  * Create dirty log: log_type #log_params <log_params>
  */
@@ -1037,16 +1030,55 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
        return dl;
 }
 
+static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
+                         unsigned *args_used)
+{
+       unsigned num_features;
+       struct dm_target *ti = ms->ti;
+
+       *args_used = 0;
+
+       if (!argc)
+               return 0;
+
+       if (sscanf(argv[0], "%u", &num_features) != 1) {
+               ti->error = "Invalid number of features";
+               return -EINVAL;
+       }
+
+       argc--;
+       argv++;
+       (*args_used)++;
+
+       if (num_features > argc) {
+               ti->error = "Not enough arguments to support feature count";
+               return -EINVAL;
+       }
+
+       if (!strcmp("handle_errors", argv[0]))
+               ms->features |= DM_RAID1_HANDLE_ERRORS;
+       else {
+               ti->error = "Unrecognised feature requested";
+               return -EINVAL;
+       }
+
+       (*args_used)++;
+
+       return 0;
+}
+
 /*
  * Construct a mirror mapping:
  *
  * log_type #log_params <log_params>
  * #mirrors [mirror_path offset]{2,}
+ * [#features <features>]
  *
  * log_type is "core" or "disk"
  * #log_params is between 1 and 3
+ *
+ * If present, features must be "handle_errors".
  */
-#define DM_IO_PAGES 64
 static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 {
        int r;
@@ -1070,8 +1102,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        argv++, argc--;
 
-       if (argc != nr_mirrors * 2) {
-               ti->error = "Wrong number of mirror arguments";
+       if (argc < nr_mirrors * 2) {
+               ti->error = "Too few mirror arguments";
                dm_destroy_dirty_log(dl);
                return -EINVAL;
        }
@@ -1096,13 +1128,37 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        ti->private = ms;
        ti->split_io = ms->rh.region_size;
 
+       ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
+       if (!ms->kmirrord_wq) {
+               DMERR("couldn't start kmirrord");
+               free_context(ms, ti, m);
+               return -ENOMEM;
+       }
+       INIT_WORK(&ms->kmirrord_work, do_mirror);
+
+       r = parse_features(ms, argc, argv, &args_used);
+       if (r) {
+               free_context(ms, ti, ms->nr_mirrors);
+               return r;
+       }
+
+       argv += args_used;
+       argc -= args_used;
+
+       if (argc) {
+               ti->error = "Too many mirror arguments";
+               free_context(ms, ti, ms->nr_mirrors);
+               return -EINVAL;
+       }
+
        r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
        if (r) {
+               destroy_workqueue(ms->kmirrord_wq);
                free_context(ms, ti, ms->nr_mirrors);
                return r;
        }
 
-       add_mirror_set(ms);
+       wake(ms);
        return 0;
 }
 
@@ -1110,8 +1166,9 @@ static void mirror_dtr(struct dm_target *ti)
 {
        struct mirror_set *ms = (struct mirror_set *) ti->private;
 
-       del_mirror_set(ms);
+       flush_workqueue(ms->kmirrord_wq);
        kcopyd_client_destroy(ms->kcopyd_client);
+       destroy_workqueue(ms->kmirrord_wq);
        free_context(ms, ti, ms->nr_mirrors);
 }
 
@@ -1127,7 +1184,7 @@ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
        spin_unlock(&ms->lock);
 
        if (should_wake)
-               wake();
+               wake(ms);
 }
 
 /*
@@ -1222,11 +1279,9 @@ static void mirror_resume(struct dm_target *ti)
 static int mirror_status(struct dm_target *ti, status_type_t type,
                         char *result, unsigned int maxlen)
 {
-       unsigned int m, sz;
+       unsigned int m, sz = 0;
        struct mirror_set *ms = (struct mirror_set *) ti->private;
 
-       sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
-
        switch (type) {
        case STATUSTYPE_INFO:
                DMEMIT("%d ", ms->nr_mirrors);
@@ -1237,13 +1292,21 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
                        (unsigned long long)ms->rh.log->type->
                                get_sync_count(ms->rh.log),
                        (unsigned long long)ms->nr_regions);
+
+               sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
                break;
 
        case STATUSTYPE_TABLE:
+               sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
                DMEMIT("%d", ms->nr_mirrors);
                for (m = 0; m < ms->nr_mirrors; m++)
                        DMEMIT(" %s %llu", ms->mirror[m].dev->name,
                                (unsigned long long)ms->mirror[m].offset);
+
+               if (ms->features & DM_RAID1_HANDLE_ERRORS)
+                       DMEMIT(" 1 handle_errors");
        }
 
        return 0;
@@ -1251,7 +1314,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
 
 static struct target_type mirror_target = {
        .name    = "mirror",
-       .version = {1, 0, 2},
+       .version = {1, 0, 3},
        .module  = THIS_MODULE,
        .ctr     = mirror_ctr,
        .dtr     = mirror_dtr,
@@ -1270,20 +1333,11 @@ static int __init dm_mirror_init(void)
        if (r)
                return r;
 
-       _kmirrord_wq = create_singlethread_workqueue("kmirrord");
-       if (!_kmirrord_wq) {
-               DMERR("couldn't start kmirrord");
-               dm_dirty_log_exit();
-               return r;
-       }
-       INIT_WORK(&_kmirrord_work, do_work);
-
        r = dm_register_target(&mirror_target);
        if (r < 0) {
                DMERR("%s: Failed to register mirror target",
                      mirror_target.name);
                dm_dirty_log_exit();
-               destroy_workqueue(_kmirrord_wq);
        }
 
        return r;
@@ -1297,7 +1351,6 @@ static void __exit dm_mirror_exit(void)
        if (r < 0)
                DMERR("%s: unregister failed %d", mirror_target.name, r);
 
-       destroy_workqueue(_kmirrord_wq);
        dm_dirty_log_exit();
 }
 
index 05befa91807a332b87676bef2cc47de92417e1eb..2fc199b0016bd5c819b42572b97dbc69dc03844c 100644 (file)
@@ -425,13 +425,15 @@ static void close_dev(struct dm_dev *d, struct mapped_device *md)
 }
 
 /*
- * If possible (ie. blk_size[major] is set), this checks an area
- * of a destination device is valid.
+ * If possible, this checks an area of a destination device is valid.
  */
 static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
 {
-       sector_t dev_size;
-       dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+       sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+
+       if (!dev_size)
+               return 1;
+
        return ((start < dev_size) && (len <= (dev_size - start)));
 }
 
index 11a98df298ece4db805682edc80d9860635f5cc4..2717a355dc5bf6847243de88f78fd540da5e941b 100644 (file)
@@ -1236,6 +1236,7 @@ void dm_put(struct mapped_device *md)
                free_dev(md);
        }
 }
+EXPORT_SYMBOL_GPL(dm_put);
 
 /*
  * Process the deferred bios
index b46f6c575f7ebd5ee79dbe543525ed5459e173d6..dbc234e3c69f917fb58e7a2f7d26b89dea324b9f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
  *
  * This file is released under the GPL.
  *
@@ -45,6 +46,8 @@ struct kcopyd_client {
        unsigned int nr_pages;
        unsigned int nr_free_pages;
 
+       struct dm_io_client *io_client;
+
        wait_queue_head_t destroyq;
        atomic_t nr_jobs;
 };
@@ -342,16 +345,20 @@ static void complete_io(unsigned long error, void *context)
 static int run_io_job(struct kcopyd_job *job)
 {
        int r;
+       struct dm_io_request io_req = {
+               .bi_rw = job->rw,
+               .mem.type = DM_IO_PAGE_LIST,
+               .mem.ptr.pl = job->pages,
+               .mem.offset = job->offset,
+               .notify.fn = complete_io,
+               .notify.context = job,
+               .client = job->kc->io_client,
+       };
 
        if (job->rw == READ)
-               r = dm_io_async(1, &job->source, job->rw,
-                               job->pages,
-                               job->offset, complete_io, job);
-
+               r = dm_io(&io_req, 1, &job->source, NULL);
        else
-               r = dm_io_async(job->num_dests, job->dests, job->rw,
-                               job->pages,
-                               job->offset, complete_io, job);
+               r = dm_io(&io_req, job->num_dests, job->dests, NULL);
 
        return r;
 }
@@ -670,8 +677,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
                return r;
        }
 
-       r = dm_io_get(nr_pages);
-       if (r) {
+       kc->io_client = dm_io_client_create(nr_pages);
+       if (IS_ERR(kc->io_client)) {
+               r = PTR_ERR(kc->io_client);
                client_free_pages(kc);
                kfree(kc);
                kcopyd_exit();
@@ -691,7 +699,7 @@ void kcopyd_client_destroy(struct kcopyd_client *kc)
        /* Wait for completion of all jobs submitted by this client. */
        wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
 
-       dm_io_put(kc->nr_pages);
+       dm_io_client_destroy(kc->io_client);
        client_free_pages(kc);
        client_del(kc);
        kfree(kc);
index 2b4315d7e5d6531573e7ecfedd425df19178a3f3..c10ce91b64e9b432cbe797df44b7d605aa7a4609 100644 (file)
@@ -33,6 +33,7 @@
 */
 
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/linkage.h>
 #include <linux/raid/md.h>
@@ -273,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit)
        atomic_set(&new->active, 1);
        spin_lock_init(&new->write_lock);
        init_waitqueue_head(&new->sb_wait);
+       new->reshape_position = MaxSector;
 
        new->queue = blk_alloc_queue(GFP_KERNEL);
        if (!new->queue) {
@@ -589,14 +591,41 @@ abort:
        return ret;
 }
 
+
+static u32 md_csum_fold(u32 csum)
+{
+       csum = (csum & 0xffff) + (csum >> 16);
+       return (csum & 0xffff) + (csum >> 16);
+}
+
 static unsigned int calc_sb_csum(mdp_super_t * sb)
 {
+       u64 newcsum = 0;
+       u32 *sb32 = (u32*)sb;
+       int i;
        unsigned int disk_csum, csum;
 
        disk_csum = sb->sb_csum;
        sb->sb_csum = 0;
-       csum = csum_partial((void *)sb, MD_SB_BYTES, 0);
+
+       for (i = 0; i < MD_SB_BYTES/4 ; i++)
+               newcsum += sb32[i];
+       csum = (newcsum & 0xffffffff) + (newcsum>>32);
+
+
+#ifdef CONFIG_ALPHA
+       /* This used to use csum_partial, which was wrong for several
+        * reasons including that different results are returned on
+        * different architectures.  It isn't critical that we get exactly
+        * the same return value as before (we always csum_fold before
+        * testing, and that removes any differences).  However as we
+        * know that csum_partial always returned a 16bit value on
+        * alphas, do a fold to maximise conformity to previous behaviour.
+        */
+       sb->sb_csum = md_csum_fold(disk_csum);
+#else
        sb->sb_csum = disk_csum;
+#endif
        return csum;
 }
 
@@ -684,7 +713,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
        if (sb->raid_disks <= 0)
                goto abort;
 
-       if (csum_fold(calc_sb_csum(sb)) != csum_fold(sb->sb_csum)) {
+       if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
                printk(KERN_WARNING "md: invalid superblock checksum on %s\n",
                        b);
                goto abort;
@@ -694,6 +723,17 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
        rdev->data_offset = 0;
        rdev->sb_size = MD_SB_BYTES;
 
+       if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+               if (sb->level != 1 && sb->level != 4
+                   && sb->level != 5 && sb->level != 6
+                   && sb->level != 10) {
+                       /* FIXME use a better test */
+                       printk(KERN_WARNING
+                              "md: bitmaps not supported for this level.\n");
+                       goto abort;
+               }
+       }
+
        if (sb->level == LEVEL_MULTIPATH)
                rdev->desc_nr = -1;
        else
@@ -792,16 +832,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->max_disks = MD_SB_DISKS;
 
                if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
-                   mddev->bitmap_file == NULL) {
-                       if (mddev->level != 1 && mddev->level != 4
-                           && mddev->level != 5 && mddev->level != 6
-                           && mddev->level != 10) {
-                               /* FIXME use a better test */
-                               printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
-                               return -EINVAL;
-                       }
+                   mddev->bitmap_file == NULL)
                        mddev->bitmap_offset = mddev->default_bitmap_offset;
-               }
 
        } else if (mddev->pers == NULL) {
                /* Insist on good event counter while assembling */
@@ -1058,6 +1090,18 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                       bdevname(rdev->bdev,b));
                return -EINVAL;
        }
+       if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) {
+               if (sb->level != cpu_to_le32(1) &&
+                   sb->level != cpu_to_le32(4) &&
+                   sb->level != cpu_to_le32(5) &&
+                   sb->level != cpu_to_le32(6) &&
+                   sb->level != cpu_to_le32(10)) {
+                       printk(KERN_WARNING
+                              "md: bitmaps not supported for this level.\n");
+                       return -EINVAL;
+               }
+       }
+
        rdev->preferred_minor = 0xffff;
        rdev->data_offset = le64_to_cpu(sb->data_offset);
        atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
@@ -1141,14 +1185,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
                mddev->max_disks =  (4096-256)/2;
 
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
-                   mddev->bitmap_file == NULL ) {
-                       if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
-                           && mddev->level != 10) {
-                               printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
-                               return -EINVAL;
-                       }
+                   mddev->bitmap_file == NULL )
                        mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
-               }
+
                if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
                        mddev->reshape_position = le64_to_cpu(sb->reshape_position);
                        mddev->delta_disks = le32_to_cpu(sb->delta_disks);
@@ -2204,6 +2243,10 @@ static ssize_t
 layout_show(mddev_t *mddev, char *page)
 {
        /* just a number, not meaningful for all levels */
+       if (mddev->reshape_position != MaxSector &&
+           mddev->layout != mddev->new_layout)
+               return sprintf(page, "%d (%d)\n",
+                              mddev->new_layout, mddev->layout);
        return sprintf(page, "%d\n", mddev->layout);
 }
 
@@ -2212,13 +2255,16 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
 {
        char *e;
        unsigned long n = simple_strtoul(buf, &e, 10);
-       if (mddev->pers)
-               return -EBUSY;
 
        if (!*buf || (*e && *e != '\n'))
                return -EINVAL;
 
-       mddev->layout = n;
+       if (mddev->pers)
+               return -EBUSY;
+       if (mddev->reshape_position != MaxSector)
+               mddev->new_layout = n;
+       else
+               mddev->layout = n;
        return len;
 }
 static struct md_sysfs_entry md_layout =
@@ -2230,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page)
 {
        if (mddev->raid_disks == 0)
                return 0;
+       if (mddev->reshape_position != MaxSector &&
+           mddev->delta_disks != 0)
+               return sprintf(page, "%d (%d)\n", mddev->raid_disks,
+                              mddev->raid_disks - mddev->delta_disks);
        return sprintf(page, "%d\n", mddev->raid_disks);
 }
 
@@ -2247,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
 
        if (mddev->pers)
                rv = update_raid_disks(mddev, n);
-       else
+       else if (mddev->reshape_position != MaxSector) {
+               int olddisks = mddev->raid_disks - mddev->delta_disks;
+               mddev->delta_disks = n - olddisks;
+               mddev->raid_disks = n;
+       } else
                mddev->raid_disks = n;
        return rv ? rv : len;
 }
@@ -2257,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
 static ssize_t
 chunk_size_show(mddev_t *mddev, char *page)
 {
+       if (mddev->reshape_position != MaxSector &&
+           mddev->chunk_size != mddev->new_chunk)
+               return sprintf(page, "%d (%d)\n", mddev->new_chunk,
+                              mddev->chunk_size);
        return sprintf(page, "%d\n", mddev->chunk_size);
 }
 
@@ -2267,12 +2325,15 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
        char *e;
        unsigned long n = simple_strtoul(buf, &e, 10);
 
-       if (mddev->pers)
-               return -EBUSY;
        if (!*buf || (*e && *e != '\n'))
                return -EINVAL;
 
-       mddev->chunk_size = n;
+       if (mddev->pers)
+               return -EBUSY;
+       else if (mddev->reshape_position != MaxSector)
+               mddev->new_chunk = n;
+       else
+               mddev->chunk_size = n;
        return len;
 }
 static struct md_sysfs_entry md_chunk_size =
@@ -2637,8 +2698,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
        minor = simple_strtoul(buf, &e, 10);
        if (e==buf || (*e && *e != '\n') )
                return -EINVAL;
-       if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
-           super_types[major].name == NULL)
+       if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
                return -ENOENT;
        mddev->major_version = major;
        mddev->minor_version = minor;
@@ -2859,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
 static struct md_sysfs_entry md_suspend_hi =
 __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
 
+static ssize_t
+reshape_position_show(mddev_t *mddev, char *page)
+{
+       if (mddev->reshape_position != MaxSector)
+               return sprintf(page, "%llu\n",
+                              (unsigned long long)mddev->reshape_position);
+       strcpy(page, "none\n");
+       return 5;
+}
+
+static ssize_t
+reshape_position_store(mddev_t *mddev, const char *buf, size_t len)
+{
+       char *e;
+       unsigned long long new = simple_strtoull(buf, &e, 10);
+       if (mddev->pers)
+               return -EBUSY;
+       if (buf == e || (*e && *e != '\n'))
+               return -EINVAL;
+       mddev->reshape_position = new;
+       mddev->delta_disks = 0;
+       mddev->new_level = mddev->level;
+       mddev->new_layout = mddev->layout;
+       mddev->new_chunk = mddev->chunk_size;
+       return len;
+}
+
+static struct md_sysfs_entry md_reshape_position =
+__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
+       reshape_position_store);
+
 
 static struct attribute *md_default_attrs[] = {
        &md_level.attr,
@@ -2871,6 +2962,7 @@ static struct attribute *md_default_attrs[] = {
        &md_new_device.attr,
        &md_safe_delay.attr,
        &md_array_state.attr,
+       &md_reshape_position.attr,
        NULL,
 };
 
@@ -3409,6 +3501,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
                mddev->size = 0;
                mddev->raid_disks = 0;
                mddev->recovery_cp = 0;
+               mddev->reshape_position = MaxSector;
 
        } else if (mddev->pers)
                printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4019,7 +4112,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
        if (info->raid_disks == 0) {
                /* just setting version number for superblock loading */
                if (info->major_version < 0 ||
-                   info->major_version >= sizeof(super_types)/sizeof(super_types[0]) ||
+                   info->major_version >= ARRAY_SIZE(super_types) ||
                    super_types[info->major_version].name == NULL) {
                        /* maybe try to auto-load a module? */
                        printk(KERN_INFO 
@@ -4941,15 +5034,6 @@ static int md_seq_open(struct inode *inode, struct file *file)
        return error;
 }
 
-static int md_seq_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *m = file->private_data;
-       struct mdstat_info *mi = m->private;
-       m->private = NULL;
-       kfree(mi);
-       return seq_release(inode, file);
-}
-
 static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
 {
        struct seq_file *m = filp->private_data;
@@ -4971,7 +5055,7 @@ static const struct file_operations md_seq_fops = {
        .open           = md_seq_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = md_seq_release,
+       .release        = seq_release_private,
        .poll           = mdstat_poll,
 };
 
@@ -5019,7 +5103,7 @@ static int is_mddev_idle(mddev_t *mddev)
                 *
                 * Note: the following is an unsigned comparison.
                 */
-               if ((curr_events - rdev->last_events + 4096) > 8192) {
+               if ((long)curr_events - (long)rdev->last_events > 4096) {
                        rdev->last_events = curr_events;
                        idle = 0;
                }
index 97ee870b265d866ffa818bdf83dc7f551cd40d7b..3a95cc5e029c932eaddf0b85df6d6b0f744c36b8 100644 (file)
@@ -271,21 +271,25 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
         */
        update_head_pos(mirror, r1_bio);
 
-       if (uptodate || (conf->raid_disks - conf->mddev->degraded) <= 1) {
-               /*
-                * Set R1BIO_Uptodate in our master bio, so that
-                * we will return a good error code for to the higher
-                * levels even if IO on some other mirrored buffer fails.
-                *
-                * The 'master' represents the composite IO operation to
-                * user-side. So if something waits for IO, then it will
-                * wait for the 'master' bio.
+       if (uptodate)
+               set_bit(R1BIO_Uptodate, &r1_bio->state);
+       else {
+               /* If all other devices have failed, we want to return
+                * the error upwards rather than fail the last device.
+                * Here we redefine "uptodate" to mean "Don't want to retry"
                 */
-               if (uptodate)
-                       set_bit(R1BIO_Uptodate, &r1_bio->state);
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
+               if (r1_bio->mddev->degraded == conf->raid_disks ||
+                   (r1_bio->mddev->degraded == conf->raid_disks-1 &&
+                    !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags)))
+                       uptodate = 1;
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+       }
 
+       if (uptodate)
                raid_end_bio_io(r1_bio);
-       else {
+       else {
                /*
                 * oops, read error:
                 */
@@ -992,13 +996,14 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                unsigned long flags;
                spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded++;
+               set_bit(Faulty, &rdev->flags);
                spin_unlock_irqrestore(&conf->device_lock, flags);
                /*
                 * if recovery is running, make sure it aborts.
                 */
                set_bit(MD_RECOVERY_ERR, &mddev->recovery);
-       }
-       set_bit(Faulty, &rdev->flags);
+       } else
+               set_bit(Faulty, &rdev->flags);
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
        printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
                "       Operation continuing on %d devices\n",
index 8d59914f2057a6d0a06527dd8b3c872ed3c1b842..061375ee6592517cf1796c2ff730b5cefcbc7269 100644 (file)
@@ -353,8 +353,8 @@ static int grow_stripes(raid5_conf_t *conf, int num)
        struct kmem_cache *sc;
        int devs = conf->raid_disks;
 
-       sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev));
-       sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev));
+       sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev));
+       sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev));
        conf->active_name = 0;
        sc = kmem_cache_create(conf->cache_name[conf->active_name],
                               sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
index 91d25798ae4a625ceab60094f2a43340bc443f2f..3a80e0cc73699e9e24bcc6fb4382fab9cb5a9dec 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Multimedia devices"
+       depends on HAS_IOMEM
 
 config VIDEO_DEV
        tristate "Video For Linux"
index 68ed3a788083dd1a69124fa430e440c49d55bd49..9200a30dd1b906ffad037d3351d441f56a668c2c 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
  * see dvb-usb-init.c for copyright information.
  *
- * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
  */
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
index f5d40aa3d27f707b021a32b4578929c7e231e362..f64546c6aeb5b63af45dffb0b6dd6efc462f602c 100644 (file)
@@ -266,7 +266,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
 {
 
 /* internal */
-//     dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+//     dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
        dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
        dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
 
index 0349a4b5da3f863c5f891e98bf4753568f508efd..aece458cfe12eb50441dca12258bd23eb3be64f8 100644 (file)
@@ -223,7 +223,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
 static int dib7000p_sad_calib(struct dib7000p_state *state)
 {
 /* internal */
-//     dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+//     dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
        dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
        dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
 
index 110536843e8e891354ab08135c677ed0f53e7b8d..e725f612a6b72c2b8d34965297aac2b73dc8e62e 100644 (file)
@@ -1,6 +1,6 @@
 /*
     TDA10021  - Single Chip Cable Channel Receiver driver module
-              used on the the Siemens DVB-C cards
+              used on the Siemens DVB-C cards
 
     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
     Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
index 54d7b07571b8e3ac23482a5ad2acd9eb9704dd45..23fd0303c91b486a38776ab80fc8c915a0e9d364 100644 (file)
@@ -306,7 +306,7 @@ static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
         * The ves1893 sometimes returns sync values that make no sense,
         * because, e.g., the SIGNAL bit is 0, while some of the higher
         * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
-        * Tests showed that the the VITERBI and SYNC bits are returned
+        * Tests showed that the VITERBI and SYNC bits are returned
         * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
         * If such a case occurs, we read the value again, until we get a
         * valid value.
index 563a8319e608eedca87736e1849b4462617b8e76..54ccc6e1f92e05e00beb9327285ba1d2b4c3cd24 100644 (file)
@@ -70,7 +70,7 @@ static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
 
        ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
        if (ret != 2 + len) {
-               em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+               em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
                return -EIO;
        }
        for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
index bec67609500fd1b1d34dbc6ac2d675af651f4169..2c7b158ce7e1bdbf9af1826701a9780ba6a3aa58 100644 (file)
@@ -1729,7 +1729,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
        endpoint = &interface->cur_altsetting->endpoint[1].desc;
 
-       /* check if the the device has the iso in endpoint at the correct place */
+       /* check if the device has the iso in endpoint at the correct place */
        if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
            USB_ENDPOINT_XFER_ISOC) {
                em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
index f5e8484103116045fec5912c584f46cf175ef181..f9f3584281d864a4e837c4a7489c2359c531859c 100644 (file)
@@ -54,9 +54,9 @@ fps
    Specifies the desired framerate. Is an integer in the range of 4-30.
 
 fbufs
-   This paramter specifies the number of internal buffers to use for storing
+   This parameter specifies the number of internal buffers to use for storing
    frames from the cam. This will help if the process that reads images from
-   the cam is a bit slow or momentarely busy. However, on slow machines it
+   the cam is a bit slow or momentarily busy. However, on slow machines it
    only introduces lag, so choose carefully. The default is 3, which is
    reasonable. You can set it between 2 and 5.
 
@@ -209,7 +209,7 @@ trace
 
      128   0x80   PWCX debugging                                      Off
 
-   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+   For example, to trace the open() & read() functions, sum 8 + 4 = 12,
    so you would supply trace=12 during insmod or modprobe. If
    you want to turn the initialization and probing tracing off, set trace=0.
    The default value for trace is 35 (0x23).
index 876fd276824215d35b29e3a539642c80a1df0e15..982b115193f855e5e6cdee2191b9b1ae1e11c78c 100644 (file)
@@ -28,7 +28,7 @@
  *
  * Portions of this code were also copied from usbvideo.c
  *
- * Special thanks to the the whole team at Sourceforge for help making
+ * Special thanks to the whole team at Sourceforge for help making
  * this driver become a reality.  Notably:
  * Andy Armstrong who reverse engineered the color encoding and
  * Pavel Machek and Chris Cheney who worked on reverse engineering the
index 71037f91c222611e8d9933d441fb29a4337f4096..c88cc75ab49b7e807f30da88de8e4bf0bf776aba 100644 (file)
@@ -1,5 +1,6 @@
 
 menu "Fusion MPT device support"
+       depends on PCI
 
 config FUSION
        bool
index d6b4c607453bdde0cd1179e40cab7786e52ee231..ddc7ae029dd3bb9dc8f61b4e4dd9de5b825bb09d 100644 (file)
@@ -571,7 +571,7 @@ mpi_fc.h
  *  11-02-00  01.01.01  Original release for post 1.0 work
  *  12-04-00  01.01.02  Added messages for Common Transport Send and
  *                      Primitive Send.
- *  01-09-01  01.01.03  Modifed some of the new flags to have an MPI prefix
+ *  01-09-01  01.01.03  Modified some of the new flags to have an MPI prefix
  *                      and modified the FcPrimitiveSend flags.
  *  01-25-01  01.01.04  Move InitiatorIndex in LinkServiceRsp reply to a larger
  *                      field.
index 97471af4309c7a7b44b011a438df6d65957ece7a..5021d1a2a1d4856e058915ea9a0d2fb8309b3f60 100644 (file)
@@ -3585,7 +3585,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
         * index = chain_idx
         *
         * Calculate the number of chain buffers needed(plus 1) per I/O
-        * then multiply the the maximum number of simultaneous cmds
+        * then multiply the maximum number of simultaneous cmds
         *
         * num_sge = num sge in request frame + last chain buffer
         * scale = num sge per chain buffer if no chain element
index 6443392bffff17402d59b2ff39f3700a7229e7fe..f4ac21e5771e8da2d9bcb42455407f7c22ddaaf4 100644 (file)
@@ -1,5 +1,6 @@
 
 menu "I2O device support"
+       depends on PCI
 
 config I2O
        tristate "I2O support"
index ab6e985275b28b3ae9e4addba68732deaeea7b7a..a20a51efe11896416e2ca4f7bdee82f4e047a592 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Multifunction device drivers"
+       depends on HAS_IOMEM
 
 config MFD_SM501
        tristate "Support for Silicon Motion SM501"
index 877e7909a0e55c34341f89ef0069be67922080fb..2f2fbffafbe052799e2315737b0e9e08225fd8ff 100644 (file)
@@ -130,7 +130,7 @@ config SONY_LAPTOP
 
          Read <file:Documentation/sony-laptop.txt> for more information.
 
-config SONY_LAPTOP_OLD
+config SONYPI_COMPAT
        bool "Sonypi compatibility"
        depends on SONY_LAPTOP
          ---help---
index 65c32a95e121360d3288e95fc5b96792538084ad..4f9060a2a2f2fce960486d07132fa889179510aa 100644 (file)
@@ -30,7 +30,7 @@
  *  Eric Burghard  - LED display support for W1N
  *  Josh Green     - Light Sens support
  *  Thomas Tuttle  - His first patch for led support was very helpfull
- *
+ *  Sam Lin        - GPS support
  */
 
 #include <linux/autoconf.h>
@@ -48,7 +48,7 @@
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 
-#define ASUS_LAPTOP_VERSION "0.41"
+#define ASUS_LAPTOP_VERSION "0.42"
 
 #define ASUS_HOTK_NAME          "Asus Laptop Support"
 #define ASUS_HOTK_CLASS         "hotkey"
@@ -83,6 +83,7 @@
 #define PLED_ON     0x20       //Phone LED
 #define GLED_ON     0x40       //Gaming LED
 #define LCD_ON      0x80       //LCD backlight
+#define GPS_ON      0x100      //GPS
 
 #define ASUS_LOG    ASUS_HOTK_FILE ": "
 #define ASUS_ERR    KERN_ERR    ASUS_LOG
@@ -148,7 +149,7 @@ ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
 ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD",   /*  A6B, A6K A6R A7D F3JM L4R M6R A3G
                                                           M6A M6V VX-1 V6J V6V W3Z */
            "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
-                                          S5A M5A z33A W1Jc W2V */
+                                          S5A M5A z33A W1Jc W2V G1 */
            "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
            "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
            "\\_SB.PCI0.PCI1.VGAC.NMAP",        /* L3C */
@@ -162,6 +163,12 @@ ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD",       /*  A6B, A6K A6R A7D F3JM L
 ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC");       /* Z71A Z71V */
 ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL");        /* Z71A Z71V */
 
+/* GPS */
+/* R2H use different handle for GPS on/off */
+ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON");  /* R2H */
+ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
+ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
+
 /*
  * This is the main structure, we can use it to store anything interesting
  * about the hotk device
@@ -278,12 +285,28 @@ static int read_wireless_status(int mask)
        return (hotk->status & mask) ? 1 : 0;
 }
 
+static int read_gps_status(void)
+{
+       ulong status;
+       acpi_status rv = AE_OK;
+
+       rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
+       if (ACPI_FAILURE(rv))
+               printk(ASUS_WARNING "Error reading GPS status\n");
+       else
+               return status ? 1 : 0;
+
+       return (hotk->status & GPS_ON) ? 1 : 0;
+}
+
 /* Generic LED functions */
 static int read_status(int mask)
 {
        /* There is a special method for both wireless devices */
        if (mask == BT_ON || mask == WL_ON)
                return read_wireless_status(mask);
+       else if (mask == GPS_ON)
+               return read_gps_status();
 
        return (hotk->status & mask) ? 1 : 0;
 }
@@ -299,6 +322,10 @@ static void write_status(acpi_handle handle, int out, int mask)
        case GLED_ON:
                out = (out & 0x1) + 1;
                break;
+       case GPS_ON:
+               handle = (out) ? gps_on_handle : gps_off_handle;
+               out = 0x02;
+               break;
        default:
                out &= 0x1;
                break;
@@ -667,6 +694,21 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
        return rv;
 }
 
+/*
+ * GPS
+ */
+static ssize_t show_gps(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", read_status(GPS_ON));
+}
+
+static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count)
+{
+       return store_status(buf, count, NULL, GPS_ON);
+}
+
 static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
 {
        /* TODO Find a better way to handle events count. */
@@ -715,6 +757,7 @@ static ASUS_CREATE_DEVICE_ATTR(display);
 static ASUS_CREATE_DEVICE_ATTR(ledd);
 static ASUS_CREATE_DEVICE_ATTR(ls_switch);
 static ASUS_CREATE_DEVICE_ATTR(ls_level);
+static ASUS_CREATE_DEVICE_ATTR(gps);
 
 static struct attribute *asuspf_attributes[] = {
        &dev_attr_infos.attr,
@@ -724,6 +767,7 @@ static struct attribute *asuspf_attributes[] = {
        &dev_attr_ledd.attr,
        &dev_attr_ls_switch.attr,
        &dev_attr_ls_level.attr,
+       &dev_attr_gps.attr,
        NULL
 };
 
@@ -763,6 +807,9 @@ static void asus_hotk_add_fs(void)
                ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
                ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
        }
+
+       if (gps_status_handle && gps_on_handle && gps_off_handle)
+               ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
 }
 
 static int asus_handle_init(char *name, acpi_handle * handle,
@@ -890,9 +937,13 @@ static int asus_hotk_get_info(void)
 
        /* There is a lot of models with "ALSL", but a few get
           a real light sens, so we need to check it. */
-       if (ASUS_HANDLE_INIT(ls_switch))
+       if (!ASUS_HANDLE_INIT(ls_switch))
                ASUS_HANDLE_INIT(ls_level);
 
+       ASUS_HANDLE_INIT(gps_on);
+       ASUS_HANDLE_INIT(gps_off);
+       ASUS_HANDLE_INIT(gps_status);
+
        kfree(model);
 
        return AE_OK;
@@ -950,7 +1001,7 @@ static int asus_hotk_add(struct acpi_device *device)
         * We install the handler, it will receive the hotk in parameter, so, we
         * could add other data to the hotk struct
         */
-       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+       status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
                                             asus_hotk_notify, hotk);
        if (ACPI_FAILURE(status))
                printk(ASUS_ERR "Error installing notify handler\n");
@@ -981,6 +1032,9 @@ static int asus_hotk_add(struct acpi_device *device)
        if (ls_level_handle)
                set_light_sens_level(hotk->light_level);
 
+       /* GPS is on by default */
+       write_status(NULL, 1, GPS_ON);
+
       end:
        if (result) {
                kfree(hotk->name);
@@ -997,7 +1051,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
 
-       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+       status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
                                            asus_hotk_notify);
        if (ACPI_FAILURE(status))
                printk(ASUS_ERR "Error removing notify handler\n");
index 68c4b58525ba615b8450ff57d979099d67892a9a..41e901f53e7c819699b909f2a3afcf7a3587e6b4 100644 (file)
@@ -85,7 +85,7 @@ static int set_lcd_level(int level)
        buf[0] = 0x80;
        buf[1] = (u8) (level*31);
 
-       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1);
 }
 
 static int get_lcd_level(void)
@@ -93,7 +93,7 @@ static int get_lcd_level(void)
        u8 wdata = 0, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
        if (result < 0)
                return result;
 
@@ -105,7 +105,7 @@ static int get_auto_brightness(void)
        u8 wdata = 4, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
        if (result < 0)
                return result;
 
@@ -119,14 +119,14 @@ static int set_auto_brightness(int enable)
 
        wdata[0] = 4;
 
-       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
+       result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1);
        if (result < 0)
                return result;
 
        wdata[0] = 0x84;
        wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
 
-       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
+       return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
 }
 
 static int get_wireless_state(int *wlan, int *bluetooth)
@@ -134,7 +134,7 @@ static int get_wireless_state(int *wlan, int *bluetooth)
        u8 wdata = 0, rdata;
        int result;
 
-       result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
+       result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1);
        if (result < 0)
                return -1;
 
index c15c1f61bd1bfad853b8c6ea343d6cdd47e98135..8ee0321ef1c8f6226a62ad5a20680a8866b69773 100644 (file)
@@ -63,7 +63,7 @@
 #include <asm/uaccess.h>
 #include <linux/sonypi.h>
 #include <linux/sony-laptop.h>
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
 #endif
@@ -114,7 +114,7 @@ MODULE_PARM_DESC(camera,
                 "set this to 1 to enable Motion Eye camera controls "
                 "(only use it if you have a C1VE or C1VN model)");
 
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
 static int minor = -1;
 module_param(minor, int, 0);
 MODULE_PARM_DESC(minor,
@@ -1504,7 +1504,7 @@ static struct attribute_group spic_attribute_group = {
 };
 
 /******** SONYPI compatibility **********/
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
 
 /* battery / brightness / temperature  addresses */
 #define SONYPI_BAT_FLAGS       0x81
@@ -1798,7 +1798,7 @@ static void sonypi_compat_exit(void)
 static int sonypi_compat_init(void) { return 0; }
 static void sonypi_compat_exit(void) { }
 static void sonypi_compat_report_event(u8 event) { }
-#endif /* CONFIG_SONY_LAPTOP_OLD */
+#endif /* CONFIG_SONYPI_COMPAT */
 
 /*
  * ACPI callbacks
index 1ba6c085419a243fb3afcbf59acf092a90559d05..c08ad8f823d233657b9f076f8aee62b4135e0e3b 100644 (file)
@@ -105,7 +105,8 @@ static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
            == TIFM_TYPE_XD)
                msleep(40);
 
-       writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+       writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00,
+              sock_addr + SOCK_CONTROL);
        /* wait for power to stabilize */
        msleep(20);
        for (cnt = 16; cnt <= 256; cnt <<= 1) {
@@ -122,6 +123,12 @@ static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
        return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
 }
 
+inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr)
+{
+       writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL),
+              sock_addr + SOCK_CONTROL);
+}
+
 inline static char __iomem *
 tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
 {
@@ -133,6 +140,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
        struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
                                               media_switcher);
        struct tifm_dev *sock;
+       char __iomem *sock_addr;
        unsigned long flags;
        unsigned char media_id;
        unsigned int socket_change_set, cnt;
@@ -158,11 +166,12 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
                               "%s : demand removing card from socket %u:%u\n",
                               fm->cdev.class_id, fm->id, cnt);
                        fm->sockets[cnt] = NULL;
+                       sock_addr = sock->addr;
                        spin_unlock_irqrestore(&fm->lock, flags);
                        device_unregister(&sock->dev);
                        spin_lock_irqsave(&fm->lock, flags);
-                       writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
-                              + SOCK_CONTROL);
+                       tifm_7xx1_sock_power_off(sock_addr);
+                       writel(0x0e00, sock_addr + SOCK_CONTROL);
                }
 
                spin_unlock_irqrestore(&fm->lock, flags);
@@ -205,8 +214,16 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
 
 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
 {
+       struct tifm_adapter *fm = pci_get_drvdata(dev);
+       int cnt;
+
        dev_dbg(&dev->dev, "suspending host\n");
 
+       for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+               if (fm->sockets[cnt])
+                       tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr);
+       }
+
        pci_save_state(dev);
        pci_enable_wake(dev, pci_choose_state(dev, state), 0);
        pci_disable_device(dev);
@@ -357,6 +374,7 @@ err_out:
 static void tifm_7xx1_remove(struct pci_dev *dev)
 {
        struct tifm_adapter *fm = pci_get_drvdata(dev);
+       int cnt;
 
        fm->eject = tifm_7xx1_dummy_eject;
        writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
@@ -365,6 +383,9 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
 
        tifm_remove_adapter(fm);
 
+       for (cnt = 0; cnt < fm->num_sockets; cnt++)
+               tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt));
+
        pci_set_drvdata(dev, NULL);
 
        iounmap(fm->addr);
index 6c97491543dbd80949eb89914c5c23f90f31fe16..c0b41e8bcd9d9311cef9976ca38e968746d72167 100644 (file)
@@ -2,10 +2,9 @@
 # MMC subsystem configuration
 #
 
-menu "MMC/SD Card support"
-
-config MMC
-       tristate "MMC support"
+menuconfig MMC
+       tristate "MMC/SD card support"
+       depends on HAS_IOMEM
        help
          MMC is the "multi-media card" bus protocol.
 
@@ -19,10 +18,12 @@ config MMC_DEBUG
          This is an option for use by developers; most people should
          say N here.  This enables MMC core and driver debugging.
 
+if MMC
+
 source "drivers/mmc/core/Kconfig"
 
 source "drivers/mmc/card/Kconfig"
 
 source "drivers/mmc/host/Kconfig"
 
-endmenu
+endif # MMC
index 01a9fd376a1f15ac9e5e6715722356a7789961f8..9320a8c73239ceff909e30a045bb06aec60bd5ee 100644 (file)
@@ -3,11 +3,10 @@
 #
 
 comment "MMC/SD Card Drivers"
-       depends MMC
 
 config MMC_BLOCK
        tristate "MMC block device driver"
-       depends on MMC && BLOCK
+       depends on BLOCK
        default y
        help
          Say Y here to enable the MMC block device driver support.
index 94222b9a15ea4668e32cad6ca67a72661e49a947..ab37a6d9d32a046d7318b3a89a6358c8456b5ef9 100644 (file)
@@ -4,7 +4,6 @@
 
 config MMC_UNSAFE_RESUME
        bool "Allow unsafe resume (DANGEROUS)"
-       depends on MMC != n
        help
          If you say Y here, the MMC layer will assume that all cards
          stayed in their respective slots during the suspend. The
index 72c7cf4a9f9dbdc6683999b28f9c7e86eda2e0fb..7385acfa1dd939a29e77fc414f89be7b47bed576 100644 (file)
@@ -500,9 +500,10 @@ void __mmc_release_bus(struct mmc_host *host)
 void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
 #ifdef CONFIG_MMC_DEBUG
-       mmc_claim_host(host);
+       unsigned long flags;
+       spin_lock_irqsave(&host->lock, flags);
        BUG_ON(host->removed);
-       mmc_release_host(host);
+       spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
        mmc_schedule_delayed_work(&host->detect, delay);
@@ -625,9 +626,10 @@ EXPORT_SYMBOL(mmc_add_host);
 void mmc_remove_host(struct mmc_host *host)
 {
 #ifdef CONFIG_MMC_DEBUG
-       mmc_claim_host(host);
+       unsigned long flags;
+       spin_lock_irqsave(&host->lock, flags);
        host->removed = 1;
-       mmc_release_host(host);
+       spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
        mmc_flush_scheduled_work();
index ed4deab2203d26382500a3da8528e60e97245d8d..e23082fe88d0ddebac4921b54631fb75bed935e0 100644 (file)
@@ -3,11 +3,10 @@
 #
 
 comment "MMC/SD Host Controller Drivers"
-       depends on MMC
 
 config MMC_ARMMMCI
        tristate "ARM AMBA Multimedia Card Interface support"
-       depends on ARM_AMBA && MMC
+       depends on ARM_AMBA
        help
          This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
          Interface (PL180 and PL181) support.  If you have an ARM(R)
@@ -17,7 +16,7 @@ config MMC_ARMMMCI
 
 config MMC_PXA
        tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
-       depends on ARCH_PXA && MMC
+       depends on ARCH_PXA
        help
          This selects the Intel(R) PXA(R) Multimedia card Interface.
          If you have a PXA(R) platform with a Multimedia Card slot,
@@ -27,7 +26,7 @@ config MMC_PXA
 
 config MMC_SDHCI
        tristate "Secure Digital Host Controller Interface support  (EXPERIMENTAL)"
-       depends on PCI && MMC && EXPERIMENTAL
+       depends on PCI && EXPERIMENTAL
        help
          This select the generic Secure Digital Host Controller Interface.
          It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
@@ -38,7 +37,7 @@ config MMC_SDHCI
 
 config MMC_OMAP
        tristate "TI OMAP Multimedia Card Interface support"
-       depends on ARCH_OMAP && MMC
+       depends on ARCH_OMAP
        select TPS65010 if MACH_OMAP_H2
        help
          This selects the TI OMAP Multimedia card Interface.
@@ -49,7 +48,7 @@ config MMC_OMAP
 
 config MMC_WBSD
        tristate "Winbond W83L51xD SD/MMC Card Interface support"
-       depends on MMC && ISA_DMA_API
+       depends on ISA_DMA_API
        help
          This selects the Winbond(R) W83L51xD Secure digital and
           Multimedia card Interface.
@@ -60,7 +59,7 @@ config MMC_WBSD
 
 config MMC_AU1X
        tristate "Alchemy AU1XX0 MMC Card Interface support"
-       depends on MMC && SOC_AU1200
+       depends on SOC_AU1200
        help
          This selects the AMD Alchemy(R) Multimedia card interface.
          If you have a Alchemy platform with a MMC slot, say Y or M here.
@@ -69,7 +68,7 @@ config MMC_AU1X
 
 config MMC_AT91
        tristate "AT91 SD/MMC Card Interface support"
-       depends on ARCH_AT91 && MMC
+       depends on ARCH_AT91
        help
          This selects the AT91 MCI controller.
 
@@ -77,7 +76,7 @@ config MMC_AT91
 
 config MMC_IMX
        tristate "Motorola i.MX Multimedia Card Interface support"
-       depends on ARCH_IMX && MMC
+       depends on ARCH_IMX
        help
          This selects the Motorola i.MX Multimedia card Interface.
          If you have a i.MX platform with a Multimedia Card slot,
@@ -87,7 +86,7 @@ config MMC_IMX
 
 config MMC_TIFM_SD
        tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
-       depends on MMC && EXPERIMENTAL && PCI
+       depends on EXPERIMENTAL && PCI
        select TIFM_CORE
        help
          Say Y here if you want to be able to access MMC/SD cards with
index 7511f961c67b78351754f9a07b24ba04fb81d9ec..8b736e9684477236604e54932f1cf788a90db858 100644 (file)
@@ -1021,10 +1021,6 @@ static void tifm_sd_remove(struct tifm_dev *sock)
        mmc_remove_host(mmc);
        dev_dbg(&sock->dev, "after remove\n");
 
-       /* The meaning of the bit majority in this constant is unknown. */
-       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-
        mmc_free_host(mmc);
 }
 
@@ -1032,14 +1028,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
 
 static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       int rc;
-
-       rc = mmc_suspend_host(mmc, state);
-       /* The meaning of the bit majority in this constant is unknown. */
-       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-              sock->addr + SOCK_CONTROL);
-       return rc;
+       return mmc_suspend_host(tifm_get_drvdata(sock), state);
 }
 
 static int tifm_sd_resume(struct tifm_dev *sock)
index c1b47db29bd23ad72f8443e4e1ad2885f7cb8f4d..fbec8cd55e38e78e020826d9df8cb6ed7879d6d9 100644 (file)
@@ -2,6 +2,7 @@
 
 menuconfig MTD
        tristate "Memory Technology Device (MTD) support"
+       depends on HAS_IOMEM
        help
          Memory Technology Devices are flash, RAM and similar chips, often
          used for solid state file systems on embedded devices. This option
index d28e0fc85e12c2e0bad8810551b1a3a8a4cffd42..479d32b57a1eb54b20b731855274bd9d343a62ae 100644 (file)
@@ -1,5 +1,4 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -231,45 +230,6 @@ config MTD_ABSENT
          the system regardless of media presence.  Device nodes created
          with this driver will return -ENODEV upon access.
 
-config MTD_OBSOLETE_CHIPS
-       bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
-       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_JEDECPROBE 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_JEDECPROBE method and reported its failure
-         to the MTD mailing list at <linux-mtd@lists.infradead.org>
-
-config MTD_AMDSTD
-       tristate "AMD compatible flash chip support (non-CFI)"
-       depends on MTD_OBSOLETE_CHIPS && BROKEN
-       help
-         This option enables support for flash chips using AMD-compatible
-         commands, including some which are not CFI-compatible and hence
-         cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
-         It also works on AMD compatible chips that do conform to CFI.
-
-config MTD_SHARP
-       tristate "pre-CFI Sharp chip support"
-       depends on MTD_OBSOLETE_CHIPS
-       help
-         This option enables support for flash chips using Sharp-compatible
-         commands, including some which are not CFI-compatible and hence
-         cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
-
-config MTD_JEDEC
-       tristate "JEDEC device support"
-       depends on MTD_OBSOLETE_CHIPS && BROKEN
-       help
-         Enable older JEDEC flash interface devices for self
-         programming flash.  It is commonly used in older AMD chips.  It is
-         only called JEDEC because the JEDEC association
-         <http://www.jedec.org/> distributes the identification codes for the
-         chips.
-
 config MTD_XIP
        bool "XIP aware MTD support"
        depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP
index 75bc1c2a0f431b9954447921f03b7246ed2fb395..36582412ccdaeb2c2aea2c0752f8b62e51554154 100644 (file)
@@ -1,19 +1,15 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
 
 obj-$(CONFIG_MTD)              += chipreg.o
-obj-$(CONFIG_MTD_AMDSTD)       += amd_flash.o
 obj-$(CONFIG_MTD_CFI)          += cfi_probe.o
 obj-$(CONFIG_MTD_CFI_UTIL)     += cfi_util.o
 obj-$(CONFIG_MTD_CFI_STAA)     += cfi_cmdset_0020.o
 obj-$(CONFIG_MTD_CFI_AMDSTD)   += cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
 obj-$(CONFIG_MTD_GEN_PROBE)    += gen_probe.o
-obj-$(CONFIG_MTD_JEDEC)                += jedec.o
 obj-$(CONFIG_MTD_JEDECPROBE)   += jedec_probe.o
 obj-$(CONFIG_MTD_RAM)          += map_ram.o
 obj-$(CONFIG_MTD_ROM)          += map_rom.o
-obj-$(CONFIG_MTD_SHARP)                += sharp.o
 obj-$(CONFIG_MTD_ABSENT)       += map_absent.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
deleted file mode 100644 (file)
index e7999f1..0000000
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- * MTD map driver for AMD compatible flash chips (non-CFI)
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
- * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
- *
- * Copyright (c) 2001 Axis Communications AB
- *
- * This file is under GPL.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/flashchip.h>
-
-/* There's no limit. It exists only to avoid realloc. */
-#define MAX_AMD_CHIPS 8
-
-#define DEVICE_TYPE_X8 (8 / 8)
-#define DEVICE_TYPE_X16        (16 / 8)
-#define DEVICE_TYPE_X32        (32 / 8)
-
-/* Addresses */
-#define ADDR_MANUFACTURER              0x0000
-#define ADDR_DEVICE_ID                 0x0001
-#define ADDR_SECTOR_LOCK               0x0002
-#define ADDR_HANDSHAKE                 0x0003
-#define ADDR_UNLOCK_1                  0x0555
-#define ADDR_UNLOCK_2                  0x02AA
-
-/* Commands */
-#define CMD_UNLOCK_DATA_1              0x00AA
-#define CMD_UNLOCK_DATA_2              0x0055
-#define CMD_MANUFACTURER_UNLOCK_DATA   0x0090
-#define CMD_UNLOCK_BYPASS_MODE         0x0020
-#define CMD_PROGRAM_UNLOCK_DATA                0x00A0
-#define CMD_RESET_DATA                 0x00F0
-#define CMD_SECTOR_ERASE_UNLOCK_DATA   0x0080
-#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x0030
-
-#define CMD_UNLOCK_SECTOR              0x0060
-
-/* Manufacturers */
-#define MANUFACTURER_AMD       0x0001
-#define MANUFACTURER_ATMEL     0x001F
-#define MANUFACTURER_FUJITSU   0x0004
-#define MANUFACTURER_ST                0x0020
-#define MANUFACTURER_SST       0x00BF
-#define MANUFACTURER_TOSHIBA   0x0098
-
-/* AMD */
-#define AM29F800BB     0x2258
-#define AM29F800BT     0x22D6
-#define AM29LV800BB    0x225B
-#define AM29LV800BT    0x22DA
-#define AM29LV160DT    0x22C4
-#define AM29LV160DB    0x2249
-#define AM29BDS323D     0x22D1
-
-/* Atmel */
-#define AT49xV16x      0x00C0
-#define AT49xV16xT     0x00C2
-
-/* Fujitsu */
-#define MBM29LV160TE   0x22C4
-#define MBM29LV160BE   0x2249
-#define MBM29LV800BB   0x225B
-
-/* ST - www.st.com */
-#define M29W800T       0x00D7
-#define M29W160DT      0x22C4
-#define M29W160DB      0x2249
-
-/* SST */
-#define SST39LF800     0x2781
-#define SST39LF160     0x2782
-
-/* Toshiba */
-#define TC58FVT160     0x00C2
-#define TC58FVB160     0x0043
-
-#define D6_MASK        0x40
-
-struct amd_flash_private {
-       int device_type;
-       int interleave;
-       int numchips;
-       unsigned long chipshift;
-       struct flchip chips[0];
-};
-
-struct amd_flash_info {
-       const __u16 mfr_id;
-       const __u16 dev_id;
-       const char *name;
-       const u_long size;
-       const int numeraseregions;
-       const struct mtd_erase_region_info regions[4];
-};
-
-
-
-static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
-                         u_char *);
-static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
-                          const u_char *);
-static int amd_flash_erase(struct mtd_info *, struct erase_info *);
-static void amd_flash_sync(struct mtd_info *);
-static int amd_flash_suspend(struct mtd_info *);
-static void amd_flash_resume(struct mtd_info *);
-static void amd_flash_destroy(struct mtd_info *);
-static struct mtd_info *amd_flash_probe(struct map_info *map);
-
-
-static struct mtd_chip_driver amd_flash_chipdrv = {
-       .probe = amd_flash_probe,
-       .destroy = amd_flash_destroy,
-       .name = "amd_flash",
-       .module = THIS_MODULE
-};
-
-static inline __u32 wide_read(struct map_info *map, __u32 addr)
-{
-       if (map->buswidth == 1) {
-               return map_read8(map, addr);
-       } else if (map->buswidth == 2) {
-               return map_read16(map, addr);
-       } else if (map->buswidth == 4) {
-               return map_read32(map, addr);
-        }
-
-       return 0;
-}
-
-static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
-{
-       if (map->buswidth == 1) {
-               map_write8(map, val, addr);
-       } else if (map->buswidth == 2) {
-               map_write16(map, val, addr);
-       } else if (map->buswidth == 4) {
-               map_write32(map, val, addr);
-       }
-}
-
-static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
-{
-       const struct amd_flash_private *private = map->fldrv_priv;
-       if ((private->interleave == 2) &&
-           (private->device_type == DEVICE_TYPE_X16)) {
-               cmd |= (cmd << 16);
-       }
-
-       return cmd;
-}
-
-static inline void send_unlock(struct map_info *map, unsigned long base)
-{
-       wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
-                  base + (map->buswidth * ADDR_UNLOCK_1));
-       wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
-                  base + (map->buswidth * ADDR_UNLOCK_2));
-}
-
-static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
-{
-       send_unlock(map, base);
-       wide_write(map, make_cmd(map, cmd),
-                  base + (map->buswidth * ADDR_UNLOCK_1));
-}
-
-static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
-                                   __u32 cmd, unsigned long addr)
-{
-       send_unlock(map, base);
-       wide_write(map, make_cmd(map, cmd), addr);
-}
-
-static inline int flash_is_busy(struct map_info *map, unsigned long addr,
-                               int interleave)
-{
-
-       if ((interleave == 2) && (map->buswidth == 4)) {
-               __u32 read1, read2;
-
-               read1 = wide_read(map, addr);
-               read2 = wide_read(map, addr);
-
-               return (((read1 >> 16) & D6_MASK) !=
-                       ((read2 >> 16) & D6_MASK)) ||
-                      (((read1 & 0xffff) & D6_MASK) !=
-                       ((read2 & 0xffff) & D6_MASK));
-       }
-
-       return ((wide_read(map, addr) & D6_MASK) !=
-               (wide_read(map, addr) & D6_MASK));
-}
-
-static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
-                                int unlock)
-{
-       /* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
-       int SLA = unlock ?
-               (sect_addr |  (0x40 * map->buswidth)) :
-               (sect_addr & ~(0x40 * map->buswidth)) ;
-
-       __u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
-
-       wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
-       wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
-       wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
-       wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
-}
-
-static inline int is_sector_locked(struct map_info *map,
-                                  unsigned long sect_addr)
-{
-       int status;
-
-       wide_write(map, CMD_RESET_DATA, 0);
-       send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
-
-       /* status is 0x0000 for unlocked and 0x0001 for locked */
-       status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
-       wide_write(map, CMD_RESET_DATA, 0);
-       return status;
-}
-
-static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
-                              int is_unlock)
-{
-       struct map_info *map;
-       struct mtd_erase_region_info *merip;
-       int eraseoffset, erasesize, eraseblocks;
-       int i;
-       int retval = 0;
-       int lock_status;
-
-       map = mtd->priv;
-
-       /* Pass the whole chip through sector by sector and check for each
-          sector if the sector and the given interval overlap */
-       for(i = 0; i < mtd->numeraseregions; i++) {
-               merip = &mtd->eraseregions[i];
-
-               eraseoffset = merip->offset;
-               erasesize = merip->erasesize;
-               eraseblocks = merip->numblocks;
-
-               if (ofs > eraseoffset + erasesize)
-                       continue;
-
-               while (eraseblocks > 0) {
-                       if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
-                               unlock_sector(map, eraseoffset, is_unlock);
-
-                               lock_status = is_sector_locked(map, eraseoffset);
-
-                               if (is_unlock && lock_status) {
-                                       printk("Cannot unlock sector at address %x length %xx\n",
-                                              eraseoffset, merip->erasesize);
-                                       retval = -1;
-                               } else if (!is_unlock && !lock_status) {
-                                       printk("Cannot lock sector at address %x length %x\n",
-                                              eraseoffset, merip->erasesize);
-                                       retval = -1;
-                               }
-                       }
-                       eraseoffset += erasesize;
-                       eraseblocks --;
-               }
-       }
-       return retval;
-}
-
-static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return amd_flash_do_unlock(mtd, ofs, len, 1);
-}
-
-static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return amd_flash_do_unlock(mtd, ofs, len, 0);
-}
-
-
-/*
- * Reads JEDEC manufacturer ID and device ID and returns the index of the first
- * matching table entry (-1 if not found or alias for already found chip).
- */
-static int probe_new_chip(struct mtd_info *mtd, __u32 base,
-                         struct flchip *chips,
-                         struct amd_flash_private *private,
-                         const struct amd_flash_info *table, int table_size)
-{
-       __u32 mfr_id;
-       __u32 dev_id;
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private temp;
-       int i;
-
-       temp.device_type = DEVICE_TYPE_X16;     // Assume X16 (FIXME)
-       temp.interleave = 2;
-       map->fldrv_priv = &temp;
-
-       /* Enter autoselect mode. */
-       send_cmd(map, base, CMD_RESET_DATA);
-       send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
-
-       mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
-       dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
-
-       if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
-           ((dev_id >> 16) == (dev_id & 0xffff))) {
-               mfr_id &= 0xffff;
-               dev_id &= 0xffff;
-       } else {
-               temp.interleave = 1;
-       }
-
-       for (i = 0; i < table_size; i++) {
-               if ((mfr_id == table[i].mfr_id) &&
-                   (dev_id == table[i].dev_id)) {
-                       if (chips) {
-                               int j;
-
-                               /* Is this an alias for an already found chip?
-                                * In that case that chip should be in
-                                * autoselect mode now.
-                                */
-                               for (j = 0; j < private->numchips; j++) {
-                                       __u32 mfr_id_other;
-                                       __u32 dev_id_other;
-
-                                       mfr_id_other =
-                                               wide_read(map, chips[j].start +
-                                                              (map->buswidth *
-                                                               ADDR_MANUFACTURER
-                                                              ));
-                                       dev_id_other =
-                                               wide_read(map, chips[j].start +
-                                                              (map->buswidth *
-                                                               ADDR_DEVICE_ID));
-                                       if (temp.interleave == 2) {
-                                               mfr_id_other &= 0xffff;
-                                               dev_id_other &= 0xffff;
-                                       }
-                                       if ((mfr_id_other == mfr_id) &&
-                                           (dev_id_other == dev_id)) {
-
-                                               /* Exit autoselect mode. */
-                                               send_cmd(map, base,
-                                                        CMD_RESET_DATA);
-
-                                               return -1;
-                                       }
-                               }
-
-                               if (private->numchips == MAX_AMD_CHIPS) {
-                                       printk(KERN_WARNING
-                                              "%s: Too many flash chips "
-                                              "detected. Increase "
-                                              "MAX_AMD_CHIPS from %d.\n",
-                                              map->name, MAX_AMD_CHIPS);
-
-                                       return -1;
-                               }
-
-                               chips[private->numchips].start = base;
-                               chips[private->numchips].state = FL_READY;
-                               chips[private->numchips].mutex =
-                                       &chips[private->numchips]._spinlock;
-                               private->numchips++;
-                       }
-
-                       printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
-                              temp.interleave, (table[i].size)/(1024*1024),
-                              table[i].name, base);
-
-                       mtd->size += table[i].size * temp.interleave;
-                       mtd->numeraseregions += table[i].numeraseregions;
-
-                       break;
-               }
-       }
-
-       /* Exit autoselect mode. */
-       send_cmd(map, base, CMD_RESET_DATA);
-
-       if (i == table_size) {
-               printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
-                      "mfr id 0x%x, dev id 0x%x\n", map->name,
-                      base, mfr_id, dev_id);
-               map->fldrv_priv = NULL;
-
-               return -1;
-       }
-
-       private->device_type = temp.device_type;
-       private->interleave = temp.interleave;
-
-       return i;
-}
-
-
-
-static struct mtd_info *amd_flash_probe(struct map_info *map)
-{
-       static const struct amd_flash_info table[] = {
-       {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV160DT,
-               .name = "AMD AM29LV160DT",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV160DB,
-               .name = "AMD AM29LV160DB",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_TOSHIBA,
-               .dev_id = TC58FVT160,
-               .name = "Toshiba TC58FVT160",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV160TE,
-               .name = "Fujitsu MBM29LV160TE",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_TOSHIBA,
-               .dev_id = TC58FVB160,
-               .name = "Toshiba TC58FVB160",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV160BE,
-               .name = "Fujitsu MBM29LV160BE",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BB,
-               .name = "AMD AM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29F800BB,
-               .name = "AMD AM29F800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BT,
-               .name = "AMD AM29LV800BT",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29F800BT,
-               .name = "AMD AM29F800BT",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BB,
-               .name = "AMD AM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV800BB,
-               .name = "Fujitsu MBM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W800T,
-               .name = "ST M29W800T",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W160DT,
-               .name = "ST M29W160DT",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W160DB,
-               .name = "ST M29W160DB",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29BDS323D,
-               .name = "AMD AM29BDS323D",
-               .size = 0x00400000,
-               .numeraseregions = 3,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
-                       { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ATMEL,
-               .dev_id = AT49xV16x,
-               .name = "Atmel AT49xV16x",
-               .size = 0x00200000,
-               .numeraseregions = 2,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x02000, .numblocks =  8 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ATMEL,
-               .dev_id = AT49xV16xT,
-               .name = "Atmel AT49xV16xT",
-               .size = 0x00200000,
-               .numeraseregions = 2,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
-               }
-       }
-       };
-
-       struct mtd_info *mtd;
-       struct flchip chips[MAX_AMD_CHIPS];
-       int table_pos[MAX_AMD_CHIPS];
-       struct amd_flash_private temp;
-       struct amd_flash_private *private;
-       u_long size;
-       unsigned long base;
-       int i;
-       int reg_idx;
-       int offset;
-
-       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_WARNING
-                      "%s: kmalloc failed for info structure\n", map->name);
-               return NULL;
-       }
-       mtd->priv = map;
-
-       memset(&temp, 0, sizeof(temp));
-
-       printk("%s: Probing for AMD compatible flash...\n", map->name);
-
-       if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
-                                          ARRAY_SIZE(table)))
-           == -1) {
-               printk(KERN_WARNING
-                      "%s: Found no AMD compatible device at location zero\n",
-                      map->name);
-               kfree(mtd);
-
-               return NULL;
-       }
-
-       chips[0].start = 0;
-       chips[0].state = FL_READY;
-       chips[0].mutex = &chips[0]._spinlock;
-       temp.numchips = 1;
-       for (size = mtd->size; size > 1; size >>= 1) {
-               temp.chipshift++;
-       }
-       switch (temp.interleave) {
-               case 2:
-                       temp.chipshift += 1;
-                       break;
-               case 4:
-                       temp.chipshift += 2;
-                       break;
-       }
-
-       /* Find out if there are any more chips in the map. */
-       for (base = (1 << temp.chipshift);
-            base < map->size;
-            base += (1 << temp.chipshift)) {
-               int numchips = temp.numchips;
-               table_pos[numchips] = probe_new_chip(mtd, base, chips,
-                       &temp, table, ARRAY_SIZE(table));
-       }
-
-       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
-                                   mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) {
-               printk(KERN_WARNING "%s: Failed to allocate "
-                      "memory for MTD erase region info\n", map->name);
-               kfree(mtd);
-               map->fldrv_priv = NULL;
-               return NULL;
-       }
-
-       reg_idx = 0;
-       offset = 0;
-       for (i = 0; i < temp.numchips; i++) {
-               int dev_size;
-               int j;
-
-               dev_size = 0;
-               for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
-                       mtd->eraseregions[reg_idx].offset = offset +
-                               (table[table_pos[i]].regions[j].offset *
-                                temp.interleave);
-                       mtd->eraseregions[reg_idx].erasesize =
-                               table[table_pos[i]].regions[j].erasesize *
-                               temp.interleave;
-                       mtd->eraseregions[reg_idx].numblocks =
-                               table[table_pos[i]].regions[j].numblocks;
-                       if (mtd->erasesize <
-                           mtd->eraseregions[reg_idx].erasesize) {
-                               mtd->erasesize =
-                                       mtd->eraseregions[reg_idx].erasesize;
-                       }
-                       dev_size += mtd->eraseregions[reg_idx].erasesize *
-                                   mtd->eraseregions[reg_idx].numblocks;
-                       reg_idx++;
-               }
-               offset += dev_size;
-       }
-       mtd->type = MTD_NORFLASH;
-       mtd->writesize = 1;
-       mtd->flags = MTD_CAP_NORFLASH;
-       mtd->name = map->name;
-       mtd->erase = amd_flash_erase;
-       mtd->read = amd_flash_read;
-       mtd->write = amd_flash_write;
-       mtd->sync = amd_flash_sync;
-       mtd->suspend = amd_flash_suspend;
-       mtd->resume = amd_flash_resume;
-       mtd->lock = amd_flash_lock;
-       mtd->unlock = amd_flash_unlock;
-
-       private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
-                                             temp.numchips), GFP_KERNEL);
-       if (!private) {
-               printk(KERN_WARNING
-                      "%s: kmalloc failed for private structure\n", map->name);
-               kfree(mtd);
-               map->fldrv_priv = NULL;
-               return NULL;
-       }
-       memcpy(private, &temp, sizeof(temp));
-       memcpy(private->chips, chips,
-              sizeof(struct flchip) * private->numchips);
-       for (i = 0; i < private->numchips; i++) {
-               init_waitqueue_head(&private->chips[i].wq);
-               spin_lock_init(&private->chips[i]._spinlock);
-       }
-
-       map->fldrv_priv = private;
-
-       map->fldrv = &amd_flash_chipdrv;
-
-       __module_get(THIS_MODULE);
-       return mtd;
-}
-
-
-
-static inline int read_one_chip(struct map_info *map, struct flchip *chip,
-                              loff_t adr, size_t len, u_char *buf)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long timeo = jiffies + HZ;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
-                      map->name, chip->state);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if(signal_pending(current)) {
-                       return -EINTR;
-               }
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       adr += chip->start;
-
-       chip->state = FL_READY;
-
-       map_copy_from(map, buf, adr, len);
-
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-
-
-static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
-                         size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       unsigned long ofs;
-       int chipnum;
-       int ret = 0;
-
-       if ((from + len) > mtd->size) {
-               printk(KERN_WARNING "%s: read request past end of device "
-                      "(0x%lx)\n", map->name, (unsigned long)from + len);
-
-               return -EINVAL;
-       }
-
-       /* Offset within the first chip that the first read should start. */
-       chipnum = (from >> private->chipshift);
-       ofs = from - (chipnum <<  private->chipshift);
-
-       *retlen = 0;
-
-       while (len) {
-               unsigned long this_len;
-
-               if (chipnum >= private->numchips) {
-                       break;
-               }
-
-               if ((len + ofs - 1) >> private->chipshift) {
-                       this_len = (1 << private->chipshift) - ofs;
-               } else {
-                       this_len = len;
-               }
-
-               ret = read_one_chip(map, &private->chips[chipnum], ofs,
-                                   this_len, buf);
-               if (ret) {
-                       break;
-               }
-
-               *retlen += this_len;
-               len -= this_len;
-               buf += this_len;
-
-               ofs = 0;
-               chipnum++;
-       }
-
-       return ret;
-}
-
-
-
-static int write_one_word(struct map_info *map, struct flchip *chip,
-                         unsigned long adr, __u32 datum)
-{
-       unsigned long timeo = jiffies + HZ;
-       struct amd_flash_private *private = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
-       int times_left;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               printk("%s: waiting for chip to write, state = %d\n",
-                      map->name, chip->state);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-               printk(KERN_INFO "%s: woke up to write\n", map->name);
-               if(signal_pending(current))
-                       return -EINTR;
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       chip->state = FL_WRITING;
-
-       adr += chip->start;
-       ENABLE_VPP(map);
-       send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
-       wide_write(map, datum, adr);
-
-       times_left = 500000;
-       while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
-               if (need_resched()) {
-                       spin_unlock_bh(chip->mutex);
-                       schedule();
-                       spin_lock_bh(chip->mutex);
-               }
-       }
-
-       if (!times_left) {
-               printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
-                      map->name, adr);
-               ret = -EIO;
-       } else {
-               __u32 verify;
-               if ((verify = wide_read(map, adr)) != datum) {
-                       printk(KERN_WARNING "%s: write to 0x%lx failed. "
-                              "datum = %x, verify = %x\n",
-                              map->name, adr, datum, verify);
-                       ret = -EIO;
-               }
-       }
-
-       DISABLE_VPP(map);
-       chip->state = FL_READY;
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return ret;
-}
-
-
-
-static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
-                          size_t *retlen, const u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       int ret = 0;
-       int chipnum;
-       unsigned long ofs;
-       unsigned long chipstart;
-
-       *retlen = 0;
-       if (!len) {
-               return 0;
-       }
-
-       chipnum = to >> private->chipshift;
-       ofs = to  - (chipnum << private->chipshift);
-       chipstart = private->chips[chipnum].start;
-
-       /* If it's not bus-aligned, do the first byte write. */
-       if (ofs & (map->buswidth - 1)) {
-               unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
-               int i = ofs - bus_ofs;
-               int n = 0;
-               u_char tmp_buf[4];
-               __u32 datum;
-
-               map_copy_from(map, tmp_buf,
-                              bus_ofs + private->chips[chipnum].start,
-                              map->buswidth);
-               while (len && i < map->buswidth)
-                       tmp_buf[i++] = buf[n++], len--;
-
-               if (map->buswidth == 2) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
-                                    datum);
-               if (ret) {
-                       return ret;
-               }
-
-               ofs += n;
-               buf += n;
-               (*retlen) += n;
-
-               if (ofs >> private->chipshift) {
-                       chipnum++;
-                       ofs = 0;
-                       if (chipnum == private->numchips) {
-                               return 0;
-                       }
-               }
-       }
-
-       /* We are now aligned, write as much as possible. */
-       while(len >= map->buswidth) {
-               __u32 datum;
-
-               if (map->buswidth == 1) {
-                       datum = *(__u8*)buf;
-               } else if (map->buswidth == 2) {
-                       datum = *(__u16*)buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)buf;
-               } else {
-                       return -EINVAL;
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-               if (ret) {
-                       return ret;
-               }
-
-               ofs += map->buswidth;
-               buf += map->buswidth;
-               (*retlen) += map->buswidth;
-               len -= map->buswidth;
-
-               if (ofs >> private->chipshift) {
-                       chipnum++;
-                       ofs = 0;
-                       if (chipnum == private->numchips) {
-                               return 0;
-                       }
-                       chipstart = private->chips[chipnum].start;
-               }
-       }
-
-       if (len & (map->buswidth - 1)) {
-               int i = 0, n = 0;
-               u_char tmp_buf[2];
-               __u32 datum;
-
-               map_copy_from(map, tmp_buf,
-                              ofs + private->chips[chipnum].start,
-                              map->buswidth);
-               while (len--) {
-                       tmp_buf[i++] = buf[n++];
-               }
-
-               if (map->buswidth == 2) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-               if (ret) {
-                       return ret;
-               }
-
-               (*retlen) += n;
-       }
-
-       return 0;
-}
-
-
-
-static inline int erase_one_block(struct map_info *map, struct flchip *chip,
-                                 unsigned long adr, u_long size)
-{
-       unsigned long timeo = jiffies + HZ;
-       struct amd_flash_private *private = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if (signal_pending(current)) {
-                       return -EINTR;
-               }
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       chip->state = FL_ERASING;
-
-       adr += chip->start;
-       ENABLE_VPP(map);
-       send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
-       send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
-
-       timeo = jiffies + (HZ * 20);
-
-       spin_unlock_bh(chip->mutex);
-       msleep(1000);
-       spin_lock_bh(chip->mutex);
-
-       while (flash_is_busy(map, adr, private->interleave)) {
-
-               if (chip->state != FL_ERASING) {
-                       /* Someone's suspended the erase. Sleep */
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       add_wait_queue(&chip->wq, &wait);
-
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_INFO "%s: erase suspended. Sleeping\n",
-                              map->name);
-                       schedule();
-                       remove_wait_queue(&chip->wq, &wait);
-
-                       if (signal_pending(current)) {
-                               return -EINTR;
-                       }
-
-                       timeo = jiffies + (HZ*2); /* FIXME */
-                       spin_lock_bh(chip->mutex);
-                       continue;
-               }
-
-               /* OK Still waiting */
-               if (time_after(jiffies, timeo)) {
-                       chip->state = FL_READY;
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_WARNING "%s: waiting for erase to complete "
-                              "timed out.\n", map->name);
-                       DISABLE_VPP(map);
-
-                       return -EIO;
-               }
-
-               /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock_bh(chip->mutex);
-
-               if (need_resched())
-                       schedule();
-               else
-                       udelay(1);
-
-               spin_lock_bh(chip->mutex);
-       }
-
-       /* Verify every single word */
-       {
-               int address;
-               int error = 0;
-               __u8 verify;
-
-               for (address = adr; address < (adr + size); address++) {
-                       if ((verify = map_read8(map, address)) != 0xFF) {
-                               error = 1;
-                               break;
-                       }
-               }
-               if (error) {
-                       chip->state = FL_READY;
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_WARNING
-                              "%s: verify error at 0x%x, size %ld.\n",
-                              map->name, address, size);
-                       DISABLE_VPP(map);
-
-                       return -EIO;
-               }
-       }
-
-       DISABLE_VPP(map);
-       chip->state = FL_READY;
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-
-
-static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       unsigned long adr, len;
-       int chipnum;
-       int ret = 0;
-       int i;
-       int first;
-       struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-       if (instr->addr > mtd->size) {
-               return -EINVAL;
-       }
-
-       if ((instr->len + instr->addr) > mtd->size) {
-               return -EINVAL;
-       }
-
-       /* Check that both start and end of the requested erase are
-        * aligned with the erasesize at the appropriate addresses.
-        */
-
-       i = 0;
-
-        /* Skip all erase regions which are ended before the start of
-           the requested erase. Actually, to save on the calculations,
-           we skip to the first erase region which starts after the
-           start of the requested erase, and then go back one.
-        */
-
-        while ((i < mtd->numeraseregions) &&
-              (instr->addr >= regions[i].offset)) {
-               i++;
-       }
-        i--;
-
-       /* OK, now i is pointing at the erase region in which this
-        * erase request starts. Check the start of the requested
-        * erase range is aligned with the erase size which is in
-        * effect here.
-        */
-
-       if (instr->addr & (regions[i].erasesize-1)) {
-               return -EINVAL;
-       }
-
-       /* Remember the erase region we start on. */
-
-       first = i;
-
-       /* Next, check that the end of the requested erase is aligned
-        * with the erase region at that address.
-        */
-
-       while ((i < mtd->numeraseregions) &&
-              ((instr->addr + instr->len) >= regions[i].offset)) {
-                i++;
-       }
-
-       /* As before, drop back one to point at the region in which
-        * the address actually falls.
-        */
-
-       i--;
-
-       if ((instr->addr + instr->len) & (regions[i].erasesize-1)) {
-                return -EINVAL;
-       }
-
-       chipnum = instr->addr >> private->chipshift;
-       adr = instr->addr - (chipnum << private->chipshift);
-       len = instr->len;
-
-       i = first;
-
-       while (len) {
-               ret = erase_one_block(map, &private->chips[chipnum], adr,
-                                     regions[i].erasesize);
-
-               if (ret) {
-                       return ret;
-               }
-
-               adr += regions[i].erasesize;
-               len -= regions[i].erasesize;
-
-               if ((adr % (1 << private->chipshift)) ==
-                   ((regions[i].offset + (regions[i].erasesize *
-                                          regions[i].numblocks))
-                    % (1 << private->chipshift))) {
-                       i++;
-               }
-
-               if (adr >> private->chipshift) {
-                       adr = 0;
-                       chipnum++;
-                       if (chipnum >= private->numchips) {
-                               break;
-                       }
-               }
-       }
-
-       instr->state = MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
-
-       return 0;
-}
-
-
-
-static void amd_flash_sync(struct mtd_info *mtd)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       int i;
-       struct flchip *chip;
-       int ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       for (i = 0; !ret && (i < private->numchips); i++) {
-               chip = &private->chips[i];
-
-       retry:
-               spin_lock_bh(chip->mutex);
-
-               switch(chip->state) {
-               case FL_READY:
-               case FL_STATUS:
-               case FL_CFI_QUERY:
-               case FL_JEDEC_QUERY:
-                       chip->oldstate = chip->state;
-                       chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change -
-                        * as the whole point is that nobody can do anything
-                        * with the chip now anyway.
-                        */
-               case FL_SYNCING:
-                       spin_unlock_bh(chip->mutex);
-                       break;
-
-               default:
-                       /* Not an idle state */
-                       add_wait_queue(&chip->wq, &wait);
-
-                       spin_unlock_bh(chip->mutex);
-
-                       schedule();
-
-                       remove_wait_queue(&chip->wq, &wait);
-
-                       goto retry;
-               }
-       }
-
-       /* Unlock the chips again */
-       for (i--; i >= 0; i--) {
-               chip = &private->chips[i];
-
-               spin_lock_bh(chip->mutex);
-
-               if (chip->state == FL_SYNCING) {
-                       chip->state = chip->oldstate;
-                       wake_up(&chip->wq);
-               }
-               spin_unlock_bh(chip->mutex);
-       }
-}
-
-
-
-static int amd_flash_suspend(struct mtd_info *mtd)
-{
-printk("amd_flash_suspend(): not implemented!\n");
-       return -EINVAL;
-}
-
-
-
-static void amd_flash_resume(struct mtd_info *mtd)
-{
-printk("amd_flash_resume(): not implemented!\n");
-}
-
-
-
-static void amd_flash_destroy(struct mtd_info *mtd)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       kfree(private);
-}
-
-int __init amd_flash_init(void)
-{
-       register_mtd_chip_driver(&amd_flash_chipdrv);
-       return 0;
-}
-
-void __exit amd_flash_exit(void)
-{
-       unregister_mtd_chip_driver(&amd_flash_chipdrv);
-}
-
-module_init(amd_flash_init);
-module_exit(amd_flash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
-MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
deleted file mode 100644 (file)
index 14e57b2..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * This code does not support anything wider than 8 bit flash chips, I am
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
- * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mtd/jedec.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-
-static struct mtd_info *jedec_probe(struct map_info *);
-static int jedec_probe8(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static int jedec_probe16(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static int jedec_probe32(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-                           unsigned long len);
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-                      size_t *retlen, const u_char *buf);
-
-static unsigned long my_bank_size;
-
-/* Listing of parts and sizes. We need this table to learn the sector
-   size of the chip and the total length */
-static const struct JEDECTable JEDEC_table[] = {
-       {
-               .jedec          = 0x013D,
-               .name           = "AMD Am29F017D",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01AD,
-               .name           = "AMD Am29F016",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01D5,
-               .name           = "AMD Am29F080",
-               .size           = 1*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01A4,
-               .name           = "AMD Am29F040",
-               .size           = 512*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x20E3,
-               .name           = "AMD Am29W040B",
-               .size           = 512*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0xC2AD,
-               .name           = "Macronix MX29F016",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       { .jedec = 0x0 }
-};
-
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
-static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-                     size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-                            size_t *retlen, u_char *buf);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-
-
-static struct mtd_chip_driver jedec_chipdrv = {
-       .probe  = jedec_probe,
-       .name   = "jedec",
-       .module = THIS_MODULE
-};
-
-/* Probe entry point */
-
-static struct mtd_info *jedec_probe(struct map_info *map)
-{
-   struct mtd_info *MTD;
-   struct jedec_private *priv;
-   unsigned long Base;
-   unsigned long SectorSize;
-   unsigned count;
-   unsigned I,Uniq;
-   char Part[200];
-   memset(&priv,0,sizeof(priv));
-
-   MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
-   if (!MTD)
-          return NULL;
-
-   priv = (struct jedec_private *)&MTD[1];
-
-   my_bank_size = map->size;
-
-   if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
-      kfree(MTD);
-      return NULL;
-   }
-
-   for (Base = 0; Base < map->size; Base += my_bank_size)
-   {
-      // Perhaps zero could designate all tests?
-      if (map->buswidth == 0)
-        map->buswidth = 1;
-
-      if (map->buswidth == 1){
-        if (jedec_probe8(map,Base,priv) == 0) {
-                printk("did recognize jedec chip\n");
-                kfree(MTD);
-                return NULL;
-        }
-      }
-      if (map->buswidth == 2)
-        jedec_probe16(map,Base,priv);
-      if (map->buswidth == 4)
-        jedec_probe32(map,Base,priv);
-   }
-
-   // Get the biggest sector size
-   SectorSize = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-          //      printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
-          //      printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
-      if (priv->chips[I].sectorsize > SectorSize)
-        SectorSize = priv->chips[I].sectorsize;
-   }
-
-   // Quickly ensure that the other sector sizes are factors of the largest
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
-      {
-        printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
-        kfree(MTD);
-        return NULL;
-      }
-   }
-
-   /* Generate a part name that includes the number of different chips and
-      other configuration information */
-   count = 1;
-   strlcpy(Part,map->name,sizeof(Part)-10);
-   strcat(Part," ");
-   Uniq = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      const struct JEDECTable *JEDEC;
-
-      if (priv->chips[I+1].jedec == priv->chips[I].jedec)
-      {
-        count++;
-        continue;
-      }
-
-      // Locate the chip in the jedec table
-      JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
-      if (JEDEC == 0)
-      {
-        printk("mtd: Internal Error, JEDEC not set\n");
-        kfree(MTD);
-        return NULL;
-      }
-
-      if (Uniq != 0)
-        strcat(Part,",");
-      Uniq++;
-
-      if (count != 1)
-        sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
-      else
-        sprintf(Part+strlen(Part),"%s",JEDEC->name);
-      if (strlen(Part) > sizeof(Part)*2/3)
-        break;
-      count = 1;
-   }
-
-   /* Determine if the chips are organized in a linear fashion, or if there
-      are empty banks. Note, the last bank does not count here, only the
-      first banks are important. Holes on non-bank boundaries can not exist
-      due to the way the detection algorithm works. */
-   if (priv->size < my_bank_size)
-      my_bank_size = priv->size;
-   priv->is_banked = 0;
-   //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
-   //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
-   if (!priv->size) {
-          printk("priv->size is zero\n");
-          kfree(MTD);
-          return NULL;
-   }
-   if (priv->size/my_bank_size) {
-          if (priv->size/my_bank_size == 1) {
-                  priv->size = my_bank_size;
-          }
-          else {
-                  for (I = 0; I != priv->size/my_bank_size - 1; I++)
-                  {
-                     if (priv->bank_fill[I] != my_bank_size)
-                        priv->is_banked = 1;
-
-                     /* This even could be eliminated, but new de-optimized read/write
-                        functions have to be written */
-                     printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
-                     if (priv->bank_fill[I] != priv->bank_fill[0])
-                     {
-                        printk("mtd: Failed. Cannot handle unsymmetric banking\n");
-                        kfree(MTD);
-                        return NULL;
-                     }
-                  }
-          }
-   }
-   if (priv->is_banked == 1)
-      strcat(Part,", banked");
-
-   //   printk("Part: '%s'\n",Part);
-
-   memset(MTD,0,sizeof(*MTD));
-  // strlcpy(MTD->name,Part,sizeof(MTD->name));
-   MTD->name = map->name;
-   MTD->type = MTD_NORFLASH;
-   MTD->flags = MTD_CAP_NORFLASH;
-   MTD->writesize = 1;
-   MTD->erasesize = SectorSize*(map->buswidth);
-   //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
-   MTD->size = priv->size;
-   //   printk("MTD->size is %x\n",(unsigned int)MTD->size);
-   //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
-   MTD->erase = flash_erase;
-   if (priv->is_banked == 1)
-      MTD->read = jedec_read_banked;
-   else
-      MTD->read = jedec_read;
-   MTD->write = flash_write;
-   MTD->sync = jedec_sync;
-   MTD->priv = map;
-   map->fldrv_priv = priv;
-   map->fldrv = &jedec_chipdrv;
-   __module_get(THIS_MODULE);
-   return MTD;
-}
-
-/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
-static int checkparity(u_char C)
-{
-   u_char parity = 0;
-   while (C != 0)
-   {
-      parity ^= C & 1;
-      C >>= 1;
-   }
-
-   return parity == 1;
-}
-
-
-/* Take an array of JEDEC numbers that represent interleved flash chips
-   and process them. Check to make sure they are good JEDEC numbers, look
-   them up and then add them to the chip list */
-static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
-                 unsigned long base,struct jedec_private *priv)
-{
-   unsigned I,J;
-   unsigned long Size;
-   unsigned long SectorSize;
-   const struct JEDECTable *JEDEC;
-
-   // Test #2 JEDEC numbers exhibit odd parity
-   for (I = 0; I != Count; I++)
-   {
-      if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
-        return 0;
-   }
-
-   // Finally, just make sure all the chip sizes are the same
-   JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-
-   if (JEDEC == 0)
-   {
-      printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-      return 0;
-   }
-
-   Size = JEDEC->size;
-   SectorSize = JEDEC->sectorsize;
-   for (I = 0; I != Count; I++)
-   {
-      JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-      if (JEDEC == 0)
-      {
-        printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-        return 0;
-      }
-
-      if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
-      {
-        printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
-        return 0;
-      }
-   }
-
-   // Load the Chips
-   for (I = 0; I != MAX_JEDEC_CHIPS; I++)
-   {
-      if (priv->chips[I].jedec == 0)
-        break;
-   }
-
-   if (I + Count > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
-      return 0;
-   }
-
-   // Add them to the table
-   for (J = 0; J != Count; J++)
-   {
-      unsigned long Bank;
-
-      JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
-      priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
-      priv->chips[I].size = JEDEC->size;
-      priv->chips[I].sectorsize = JEDEC->sectorsize;
-      priv->chips[I].base = base + J;
-      priv->chips[I].datashift = J*8;
-      priv->chips[I].capabilities = JEDEC->capabilities;
-      priv->chips[I].offset = priv->size + J;
-
-      // log2 n :|
-      priv->chips[I].addrshift = 0;
-      for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-
-      // Determine how filled this bank is.
-      Bank = base & (~(my_bank_size-1));
-      if (priv->bank_fill[Bank/my_bank_size] < base +
-         (JEDEC->size << priv->chips[I].addrshift) - Bank)
-        priv->bank_fill[Bank/my_bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
-      I++;
-   }
-
-   priv->size += priv->chips[I-1].size*Count;
-
-   return priv->chips[I-1].size;
-}
-
-/* Lookup the chip information from the JEDEC ID table. */
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
-{
-   __u16 Id = (mfr << 8) | id;
-   unsigned long I = 0;
-   for (I = 0; JEDEC_table[I].jedec != 0; I++)
-      if (JEDEC_table[I].jedec == Id)
-        return JEDEC_table + I;
-   return NULL;
-}
-
-// Look for flash using an 8 bit bus interface
-static int jedec_probe8(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   #define flread(x) map_read8(map,base+x)
-   #define flwrite(v,x) map_write8(map,v,base+x)
-
-   const unsigned long AutoSel1 = 0xAA;
-   const unsigned long AutoSel2 = 0x55;
-   const unsigned long AutoSel3 = 0x90;
-   const unsigned long Reset = 0xF0;
-   __u32 OldVal;
-   __u8 Mfg[1];
-   __u8 Id[1];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   //  Get the JEDEC numbers
-   Mfg[0] = flread(0);
-   Id[0] = flread(1);
-   //   printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
-
-   Size = handle_jedecs(map,Mfg,Id,1,base,priv);
-   //   printk("handle_jedecs Size is %x\n",(unsigned int)Size);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-
-   // Reset.
-   flwrite(Reset,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
-static int jedec_probe16(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   return 0;
-}
-
-// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
-static int jedec_probe32(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   #define flread(x) map_read32(map,base+((x)<<2))
-   #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
-   const unsigned long AutoSel1 = 0xAAAAAAAA;
-   const unsigned long AutoSel2 = 0x55555555;
-   const unsigned long AutoSel3 = 0x90909090;
-   const unsigned long Reset = 0xF0F0F0F0;
-   __u32 OldVal;
-   __u8 Mfg[4];
-   __u8 Id[4];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   // Test #1, JEDEC numbers are readable from 0x??00/0x??01
-   if (flread(0) != flread(0x100) ||
-       flread(1) != flread(0x101))
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   // Split up the JEDEC numbers
-   OldVal = flread(0);
-   for (I = 0; I != 4; I++)
-      Mfg[I] = (OldVal >> (I*8));
-   OldVal = flread(1);
-   for (I = 0; I != 4; I++)
-      Id[I] = (OldVal >> (I*8));
-
-   Size = handle_jedecs(map,Mfg,Id,4,base,priv);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   /* Check if there is address wrap around within a single bank, if this
-      returns JEDEC numbers then we assume that it is wrap around. Notice
-      we call this routine with the JEDEC return still enabled, if two or
-      more flashes have a truncated address space the probe test will still
-      work */
-   if (base + (Size<<2)+0x555 < map->size &&
-       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
-   {
-      if (flread(base+Size) != flread(base+Size + 0x100) ||
-         flread(base+Size + 1) != flread(base+Size + 0x101))
-      {
-        jedec_probe32(map,base+Size,priv);
-      }
-   }
-
-   // Reset.
-   flwrite(0xF0F0F0F0,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* Linear read. */
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-                     size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-
-   map_copy_from(map, buf, from, len);
-   *retlen = len;
-   return 0;
-}
-
-/* Banked read. Take special care to jump past the holes in the bank
-   mapping. This version assumes symetry in the holes.. */
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-                            size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   *retlen = 0;
-   while (len > 0)
-   {
-      // Determine what bank and offset into that bank the first byte is
-      unsigned long bank = from & (~(priv->bank_fill[0]-1));
-      unsigned long offset = from & (priv->bank_fill[0]-1);
-      unsigned long get = len;
-      if (priv->bank_fill[0] - offset < len)
-        get = priv->bank_fill[0] - offset;
-
-      bank /= priv->bank_fill[0];
-      map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
-      len -= get;
-      *retlen += get;
-      from += get;
-   }
-   return 0;
-}
-
-/* Pass the flags value that the flash return before it re-entered read
-   mode. */
-static void jedec_flash_failed(unsigned char code)
-{
-   /* Bit 5 being high indicates that there was an internal device
-      failure, erasure time limits exceeded or something */
-   if ((code & (1 << 5)) != 0)
-   {
-      printk("mtd: Internal Flash failure\n");
-      return;
-   }
-   printk("mtd: Programming didn't take\n");
-}
-
-/* This uses the erasure function described in the AMD Flash Handbook,
-   it will work for flashes with a fixed sector size only. Flashes with
-   a selection of sector sizes (ie the AMD Am29F800B) will need a different
-   routine. This routine tries to parallize erasing multiple chips/sectors
-   where possible */
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-   // Does IO to the currently selected chip
-   #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
-   unsigned long Time = 0;
-   unsigned long NoTime = 0;
-   unsigned long start = instr->addr, len = instr->len;
-   unsigned int I;
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   // Verify the arguments..
-   if (start + len > mtd->size ||
-       (start % mtd->erasesize) != 0 ||
-       (len % mtd->erasesize) != 0 ||
-       (len/mtd->erasesize) == 0)
-      return -EINVAL;
-
-   jedec_flash_chip_scan(priv,start,len);
-
-   // Start the erase sequence on each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      unsigned long off;
-      struct jedec_flash_chip *chip = priv->chips + I;
-
-      if (chip->length == 0)
-        continue;
-
-      if (chip->start + chip->length > chip->size)
-      {
-        printk("DIE\n");
-        return -EIO;
-      }
-
-      flwrite(0xF0,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-      flwrite(0x80,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-
-      /* Once we start selecting the erase sectors the delay between each
-         command must not exceed 50us or it will immediately start erasing
-         and ignore the other sectors */
-      for (off = 0; off < len; off += chip->sectorsize)
-      {
-        // Check to make sure we didn't timeout
-        flwrite(0x30,chip->start + off);
-        if (off == 0)
-           continue;
-        if ((flread(chip->start + off) & (1 << 3)) != 0)
-        {
-           printk("mtd: Ack! We timed out the erase timer!\n");
-           return -EIO;
-        }
-      }
-   }
-
-   /* We could split this into a timer routine and return early, performing
-      background erasure.. Maybe later if the need warrents */
-
-   /* Poll the flash for erasure completion, specs say this can take as long
-      as 480 seconds to do all the sectors (for a 2 meg flash).
-      Erasure time is dependent on chip age, temp and wear.. */
-
-   /* This being a generic routine assumes a 32 bit bus. It does read32s
-      and bundles interleved chips into the same grouping. This will work
-      for all bus widths */
-   Time = 0;
-   NoTime = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long off = 0;
-      unsigned todo[4] = {0,0,0,0};
-      unsigned todo_left = 0;
-      unsigned J;
-
-      if (chip->length == 0)
-        continue;
-
-      /* Find all chips in this data line, realistically this is all
-         or nothing up to the interleve count */
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-            (chip->base & (~((1<<chip->addrshift)-1))))
-        {
-           todo_left++;
-           todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
-        }
-      }
-
-      /*      printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
-             (short)todo[2],(short)todo[3]);
-      */
-      while (1)
-      {
-        __u32 Last[4];
-        unsigned long Count = 0;
-
-        /* During erase bit 7 is held low and bit 6 toggles, we watch this,
-           should it stop toggling or go high then the erase is completed,
-           or this is not really flash ;> */
-        switch (map->buswidth) {
-        case 1:
-           Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        case 2:
-           Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        case 3:
-           Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        }
-        Count = 3;
-        while (todo_left != 0)
-        {
-           for (J = 0; J != 4; J++)
-           {
-              __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
-              __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
-              __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
-              if (todo[J] == 0)
-                 continue;
-
-              if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
-              {
-//               printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
-                 continue;
-              }
-
-              if (Byte1 == Byte2)
-              {
-                 jedec_flash_failed(Byte3);
-                 return -EIO;
-              }
-
-              todo[J] = 0;
-              todo_left--;
-           }
-
-/*         if (NoTime == 0)
-              Time += HZ/10 - schedule_timeout(HZ/10);*/
-           NoTime = 0;
-
-           switch (map->buswidth) {
-           case 1:
-              Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           case 2:
-              Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           case 4:
-              Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           }
-           Count++;
-
-/*         // Count time, max of 15s per sector (according to AMD)
-           if (Time > 15*len/mtd->erasesize*HZ)
-           {
-              printk("mtd: Flash Erase Timed out\n");
-              return -EIO;
-           }       */
-        }
-
-        // Skip to the next chip if we used chip erase
-        if (chip->length == chip->size)
-           off = chip->size;
-        else
-           off += chip->sectorsize;
-
-        if (off >= chip->length)
-           break;
-        NoTime = 1;
-      }
-
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-            (chip->base & (~((1<<chip->addrshift)-1))))
-           priv->chips[J].length = 0;
-      }
-   }
-
-   //printk("done\n");
-   instr->state = MTD_ERASE_DONE;
-   mtd_erase_callback(instr);
-   return 0;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* This is the simple flash writing function. It writes to every byte, in
-   sequence. It takes care of how to properly address the flash if
-   the flash is interleved. It can only be used if all the chips in the
-   array are identical!*/
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-                      size_t *retlen, const u_char *buf)
-{
-   /* Does IO to the currently selected chip. It takes the bank addressing
-      base (which is divisible by the chip size) adds the necessary lower bits
-      of addrshift (interleave index) and then adds the control register index. */
-   #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-   unsigned long base;
-   unsigned long off;
-   size_t save_len = len;
-
-   if (start + len > mtd->size)
-      return -EIO;
-
-   //printk("Here");
-
-   //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
-   while (len != 0)
-   {
-      struct jedec_flash_chip *chip = priv->chips;
-      unsigned long bank;
-      unsigned long boffset;
-
-      // Compute the base of the flash.
-      off = ((unsigned long)start) % (chip->size << chip->addrshift);
-      base = start - off;
-
-      // Perform banked addressing translation.
-      bank = base & (~(priv->bank_fill[0]-1));
-      boffset = base & (priv->bank_fill[0]-1);
-      bank = (bank/priv->bank_fill[0])*my_bank_size;
-      base = bank + boffset;
-
-    //  printk("Flasing %X %X %X\n",base,chip->size,len);
-     // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
-
-      // Loop over this page
-      for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
-      {
-        unsigned char oldbyte = map_read8(map,base+off);
-        unsigned char Last[4];
-        unsigned long Count = 0;
-
-        if (oldbyte == *buf) {
-       //       printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
-           continue;
-        }
-        if (((~oldbyte) & *buf) != 0)
-           printk("mtd: warn: Trying to set a 0 to a 1\n");
-
-        // Write
-        flwrite(0xAA,0x555);
-        flwrite(0x55,0x2AA);
-        flwrite(0xA0,0x555);
-        map_write8(map,*buf,base + off);
-        Last[0] = map_read8(map,base + off);
-        Last[1] = map_read8(map,base + off);
-        Last[2] = map_read8(map,base + off);
-
-        /* Wait for the flash to finish the operation. We store the last 4
-           status bytes that have been retrieved so we can determine why
-           it failed. The toggle bits keep toggling when there is a
-           failure */
-        for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
-             Count < 10000; Count++)
-           Last[Count % 4] = map_read8(map,base + off);
-        if (Last[(Count - 1) % 4] != *buf)
-        {
-           jedec_flash_failed(Last[(Count - 3) % 4]);
-           return -EIO;
-        }
-      }
-   }
-   *retlen = save_len;
-   return 0;
-}
-
-/* This is used to enhance the speed of the erase routine,
-   when things are being done to multiple chips it is possible to
-   parallize the operations, particularly full memory erases of multi
-   chip memories benifit */
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-                    unsigned long len)
-{
-   unsigned int I;
-
-   // Zero the records
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-      priv->chips[I].start = priv->chips[I].length = 0;
-
-   // Intersect the region with each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long ByteStart;
-      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-
-      // End is before this chip or the start is after it
-      if (start+len < chip->offset ||
-         ChipEndByte - (1 << chip->addrshift) < start)
-        continue;
-
-      if (start < chip->offset)
-      {
-        ByteStart = chip->offset;
-        chip->start = 0;
-      }
-      else
-      {
-        chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
-        ByteStart = start;
-      }
-
-      if (start + len >= ChipEndByte)
-        chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
-      else
-        chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
-   }
-}
-
-int __init jedec_init(void)
-{
-       register_mtd_chip_driver(&jedec_chipdrv);
-       return 0;
-}
-
-static void __exit jedec_exit(void)
-{
-       unregister_mtd_chip_driver(&jedec_chipdrv);
-}
-
-module_init(jedec_init);
-module_exit(jedec_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
-MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
deleted file mode 100644 (file)
index c9cd3d2..0000000
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * MTD chip driver for pre-CFI Sharp flash chips
- *
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- *           2000,2001 Lineo, Inc.
- *
- * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
- *
- * Devices supported:
- *   LH28F016SCT Symmetrical block flash memory, 2Mx8
- *   LH28F008SCT Symmetrical block flash memory, 1Mx8
- *
- * Documentation:
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
- *   016sctl9.pdf
- *
- * Limitations:
- *   This driver only supports 4x1 arrangement of chips.
- *   Not tested on anything but PowerPC.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/cfi.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#define CMD_RESET              0xffffffff
-#define CMD_READ_ID            0x90909090
-#define CMD_READ_STATUS                0x70707070
-#define CMD_CLEAR_STATUS       0x50505050
-#define CMD_BLOCK_ERASE_1      0x20202020
-#define CMD_BLOCK_ERASE_2      0xd0d0d0d0
-#define CMD_BYTE_WRITE         0x40404040
-#define CMD_SUSPEND            0xb0b0b0b0
-#define CMD_RESUME             0xd0d0d0d0
-#define CMD_SET_BLOCK_LOCK_1   0x60606060
-#define CMD_SET_BLOCK_LOCK_2   0x01010101
-#define CMD_SET_MASTER_LOCK_1  0x60606060
-#define CMD_SET_MASTER_LOCK_2  0xf1f1f1f1
-#define CMD_CLEAR_BLOCK_LOCKS_1        0x60606060
-#define CMD_CLEAR_BLOCK_LOCKS_2        0xd0d0d0d0
-
-#define SR_READY               0x80808080 // 1 = ready
-#define SR_ERASE_SUSPEND       0x40404040 // 1 = block erase suspended
-#define SR_ERROR_ERASE         0x20202020 // 1 = error in block erase or clear lock bits
-#define SR_ERROR_WRITE         0x10101010 // 1 = error in byte write or set lock bit
-#define        SR_VPP                  0x08080808 // 1 = Vpp is low
-#define SR_WRITE_SUSPEND       0x04040404 // 1 = byte write suspended
-#define SR_PROTECT             0x02020202 // 1 = lock bit set
-#define SR_RESERVED            0x01010101
-
-#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
-
-/* Configuration options */
-
-#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
-
-static struct mtd_info *sharp_probe(struct map_info *);
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf);
-static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, const u_char *buf);
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
-static void sharp_sync(struct mtd_info *mtd);
-static int sharp_suspend(struct mtd_info *mtd);
-static void sharp_resume(struct mtd_info *mtd);
-static void sharp_destroy(struct mtd_info *mtd);
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-       unsigned long adr, __u32 datum);
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr);
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr);
-#endif
-
-
-struct sharp_info{
-       struct flchip *chip;
-       int bogus;
-       int chipshift;
-       int numchips;
-       struct flchip chips[1];
-};
-
-static void sharp_destroy(struct mtd_info *mtd);
-
-static struct mtd_chip_driver sharp_chipdrv = {
-       .probe          = sharp_probe,
-       .destroy        = sharp_destroy,
-       .name           = "sharp",
-       .module         = THIS_MODULE
-};
-
-
-static struct mtd_info *sharp_probe(struct map_info *map)
-{
-       struct mtd_info *mtd = NULL;
-       struct sharp_info *sharp = NULL;
-       int width;
-
-       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if(!mtd)
-               return NULL;
-
-       sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
-       if(!sharp) {
-               kfree(mtd);
-               return NULL;
-       }
-
-       width = sharp_probe_map(map,mtd);
-       if(!width){
-               kfree(mtd);
-               kfree(sharp);
-               return NULL;
-       }
-
-       mtd->priv = map;
-       mtd->type = MTD_NORFLASH;
-       mtd->erase = sharp_erase;
-       mtd->read = sharp_read;
-       mtd->write = sharp_write;
-       mtd->sync = sharp_sync;
-       mtd->suspend = sharp_suspend;
-       mtd->resume = sharp_resume;
-       mtd->flags = MTD_CAP_NORFLASH;
-       mtd->writesize = 1;
-       mtd->name = map->name;
-
-       sharp->chipshift = 23;
-       sharp->numchips = 1;
-       sharp->chips[0].start = 0;
-       sharp->chips[0].state = FL_READY;
-       sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
-       sharp->chips[0].word_write_time = 0;
-       init_waitqueue_head(&sharp->chips[0].wq);
-       spin_lock_init(&sharp->chips[0]._spinlock);
-
-       map->fldrv = &sharp_chipdrv;
-       map->fldrv_priv = sharp;
-
-       __module_get(THIS_MODULE);
-       return mtd;
-}
-
-static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
-{
-       map_word map_cmd;
-       map_cmd.x[0] = cmd;
-       map_write(map, map_cmd, adr);
-}
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
-{
-       map_word tmp, read0, read4;
-       unsigned long base = 0;
-       int width = 4;
-
-       tmp = map_read(map, base+0);
-
-       sharp_send_cmd(map, CMD_READ_ID, base+0);
-
-       read0 = map_read(map, base+0);
-       read4 = map_read(map, base+4);
-       if(read0.x[0] == 0x89898989){
-               printk("Looks like sharp flash\n");
-               switch(read4.x[0]){
-               case 0xaaaaaaaa:
-               case 0xa0a0a0a0:
-                       /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
-                       /* a0 - LH28F016SCT-Z4  2Mx8, 32 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x200000 * width;
-                       return width;
-               case 0xa6a6a6a6:
-                       /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
-                       /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x100000 * width;
-                       return width;
-#if 0
-               case 0x00000000: /* unknown */
-                       /* XX - LH28F004SCT 512kx8, 8 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x80000 * width;
-                       return width;
-#endif
-               default:
-                       printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
-                               read0.x[0], read4.x[0]);
-               }
-       }else if((map_read(map, base+0).x[0] == CMD_READ_ID)){
-               /* RAM, probably */
-               printk("Looks like RAM\n");
-               map_write(map, tmp, base+0);
-       }else{
-               printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
-                       read0.x[0], read4.x[0]);
-       }
-
-       return 0;
-}
-
-/* This function returns with the chip->mutex lock held. */
-static int sharp_wait(struct map_info *map, struct flchip *chip)
-{
-       int i;
-       map_word status;
-       unsigned long timeo = jiffies + HZ;
-       DECLARE_WAITQUEUE(wait, current);
-       int adr = 0;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       switch(chip->state){
-       case FL_READY:
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               chip->state = FL_STATUS;
-       case FL_STATUS:
-               for(i=0;i<100;i++){
-                       status = map_read(map, adr);
-                       if((status.x[0] & SR_READY)==SR_READY)
-                               break;
-                       udelay(1);
-               }
-               break;
-       default:
-               printk("Waiting for chip\n");
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if(signal_pending(current))
-                       return -EINTR;
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       sharp_send_cmd(map, CMD_RESET, adr);
-
-       chip->state = FL_READY;
-
-       return 0;
-}
-
-static void sharp_release(struct flchip *chip)
-{
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-}
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       int chipnum;
-       int ret = 0;
-       int ofs = 0;
-
-       chipnum = (from >> sharp->chipshift);
-       ofs = from & ((1 << sharp->chipshift)-1);
-
-       *retlen = 0;
-
-       while(len){
-               unsigned long thislen;
-
-               if(chipnum>=sharp->numchips)
-                       break;
-
-               thislen = len;
-               if(ofs+thislen >= (1<<sharp->chipshift))
-                       thislen = (1<<sharp->chipshift) - ofs;
-
-               ret = sharp_wait(map,&sharp->chips[chipnum]);
-               if(ret<0)
-                       break;
-
-               map_copy_from(map,buf,ofs,thislen);
-
-               sharp_release(&sharp->chips[chipnum]);
-
-               *retlen += thislen;
-               len -= thislen;
-               buf += thislen;
-
-               ofs = 0;
-               chipnum++;
-       }
-       return ret;
-}
-
-static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       int ret = 0;
-       int i,j;
-       int chipnum;
-       unsigned long ofs;
-       union { u32 l; unsigned char uc[4]; } tbuf;
-
-       *retlen = 0;
-
-       while(len){
-               tbuf.l = 0xffffffff;
-               chipnum = to >> sharp->chipshift;
-               ofs = to & ((1<<sharp->chipshift)-1);
-
-               j=0;
-               for(i=ofs&3;i<4 && len;i++){
-                       tbuf.uc[i] = *buf;
-                       buf++;
-                       to++;
-                       len--;
-                       j++;
-               }
-               sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
-               if(ret<0)
-                       return ret;
-               (*retlen)+=j;
-       }
-
-       return 0;
-}
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-       unsigned long adr, __u32 datum)
-{
-       int ret;
-       int timeo;
-       int try;
-       int i;
-       map_word data, status;
-
-       status.x[0] = 0;
-       ret = sharp_wait(map,chip);
-
-       for(try=0;try<10;try++){
-               sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
-               /* cpu_to_le32 -> hack to fix the writel be->le conversion */
-               data.x[0] = cpu_to_le32(datum);
-               map_write(map, data, adr);
-
-               chip->state = FL_WRITING;
-
-               timeo = jiffies + (HZ/2);
-
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               for(i=0;i<100;i++){
-                       status = map_read(map, adr);
-                       if((status.x[0] & SR_READY) == SR_READY)
-                               break;
-               }
-               if(i==100){
-                       printk("sharp: timed out writing\n");
-               }
-
-               if(!(status.x[0] & SR_ERRORS))
-                       break;
-
-               printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
-
-               sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-       }
-       sharp_send_cmd(map, CMD_RESET, adr);
-       chip->state = FL_READY;
-
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       unsigned long adr,len;
-       int chipnum, ret=0;
-
-//printk("sharp_erase()\n");
-       if(instr->addr & (mtd->erasesize - 1))
-               return -EINVAL;
-       if(instr->len & (mtd->erasesize - 1))
-               return -EINVAL;
-       if(instr->len + instr->addr > mtd->size)
-               return -EINVAL;
-
-       chipnum = instr->addr >> sharp->chipshift;
-       adr = instr->addr & ((1<<sharp->chipshift)-1);
-       len = instr->len;
-
-       while(len){
-               ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
-               if(ret)return ret;
-
-               adr += mtd->erasesize;
-               len -= mtd->erasesize;
-               if(adr >> sharp->chipshift){
-                       adr = 0;
-                       chipnum++;
-                       if(chipnum>=sharp->numchips)
-                               break;
-               }
-       }
-
-       instr->state = MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
-
-       return 0;
-}
-
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int ret;
-       unsigned long timeo;
-       map_word status;
-       DECLARE_WAITQUEUE(wait, current);
-
-       sharp_send_cmd(map, CMD_READ_STATUS, adr);
-       status = map_read(map, adr);
-
-       timeo = jiffies + HZ;
-
-       while(time_before(jiffies, timeo)){
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               status = map_read(map, adr);
-               if((status.x[0] & SR_READY)==SR_READY){
-                       ret = 0;
-                       goto out;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               //spin_unlock_bh(chip->mutex);
-
-               schedule_timeout(1);
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               //spin_lock_bh(chip->mutex);
-
-               if (signal_pending(current)){
-                       ret = -EINTR;
-                       goto out;
-               }
-
-       }
-       ret = -ETIME;
-out:
-       return ret;
-}
-
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int ret;
-       //int timeo;
-       map_word status;
-       //int i;
-
-//printk("sharp_erase_oneblock()\n");
-
-#ifdef AUTOUNLOCK
-       /* This seems like a good place to do an unlock */
-       sharp_unlock_oneblock(map,chip,adr);
-#endif
-
-       sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
-       sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
-
-       chip->state = FL_ERASING;
-
-       ret = sharp_do_wait_for_ready(map,chip,adr);
-       if(ret<0)return ret;
-
-       sharp_send_cmd(map, CMD_READ_STATUS, adr);
-       status = map_read(map, adr);
-
-       if(!(status.x[0] & SR_ERRORS)){
-               sharp_send_cmd(map, CMD_RESET, adr);
-               chip->state = FL_READY;
-               //spin_unlock_bh(chip->mutex);
-               return 0;
-       }
-
-       printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-       sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-
-       //spin_unlock_bh(chip->mutex);
-
-       return -EIO;
-}
-
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int i;
-       map_word status;
-
-       sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr);
-       sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr);
-
-       udelay(100);
-
-       status = map_read(map, adr);
-       printk("status=%08lx\n", status.x[0]);
-
-       for(i=0;i<1000;i++){
-               //sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               status = map_read(map, adr);
-               if((status.x[0] & SR_READY) == SR_READY)
-                       break;
-               udelay(100);
-       }
-       if(i==1000){
-               printk("sharp: timed out unlocking block\n");
-       }
-
-       if(!(status.x[0] & SR_ERRORS)){
-               sharp_send_cmd(map, CMD_RESET, adr);
-               chip->state = FL_READY;
-               return;
-       }
-
-       printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-       sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-}
-#endif
-
-static void sharp_sync(struct mtd_info *mtd)
-{
-       //printk("sharp_sync()\n");
-}
-
-static int sharp_suspend(struct mtd_info *mtd)
-{
-       printk("sharp_suspend()\n");
-       return -EINVAL;
-}
-
-static void sharp_resume(struct mtd_info *mtd)
-{
-       printk("sharp_resume()\n");
-
-}
-
-static void sharp_destroy(struct mtd_info *mtd)
-{
-       printk("sharp_destroy()\n");
-
-}
-
-static int __init sharp_probe_init(void)
-{
-       printk("MTD Sharp chip driver <ds@lineo.com>\n");
-
-       register_mtd_chip_driver(&sharp_chipdrv);
-
-       return 0;
-}
-
-static void __exit sharp_probe_exit(void)
-{
-       unregister_mtd_chip_driver(&sharp_chipdrv);
-}
-
-module_init(sharp_probe_init);
-module_exit(sharp_probe_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Schleef <ds@schleef.org>");
-MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
index fc4cc8ba9e29b98a5df19e0d5119dfefd5455882..be4b9948c762e33b577cbd192dd836ff50c75e46 100644 (file)
@@ -373,7 +373,7 @@ static inline void kill_final_newline(char *str)
 
 #ifndef MODULE
 static int block2mtd_init_called = 0;
-static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
+static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 
 
index d990d8141ef5dab4337dd7be35d3dc836f8926f5..b665e4ac2208458bc70d1f8dfe9cd00a3a6a58fd 100644 (file)
@@ -60,7 +60,7 @@ config MTD_PHYSMAP_BANKWIDTH
          (i.e., run-time calling physmap_configure()).
 
 config MTD_PHYSMAP_OF
-       tristate "Flash device in physical memory map based on OF descirption"
+       tristate "Flash device in physical memory map based on OF description"
        depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
        help
          This provides a 'mapping' driver which allows the NOR Flash and
@@ -358,22 +358,6 @@ config MTD_CFI_FLAGADM
          Mapping for the Flaga digital module. If you don't have one, ignore
          this setting.
 
-config MTD_BEECH
-       tristate "CFI Flash device mapped on IBM 405LP Beech"
-       depends on MTD_CFI && BEECH
-       help
-         This enables access routines for the flash chips on the IBM
-         405LP Beech board. If you have one of these boards and would like
-         to use the flash chips on it, say 'Y'.
-
-config MTD_ARCTIC
-       tristate "CFI Flash device mapped on IBM 405LP Arctic"
-       depends on MTD_CFI && ARCTIC2
-       help
-         This enables access routines for the flash chips on the IBM 405LP
-         Arctic board. If you have one of these boards and would like to
-         use the flash chips on it, say 'Y'.
-
 config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
        depends on MTD_JEDECPROBE && WALNUT
index de036c5e61394375721a4fe789a824da6cbcf23e..3acbb5d01ca4edc159238390e1f827ebee431524 100644 (file)
@@ -58,8 +58,6 @@ obj-$(CONFIG_MTD_NETtel)      += nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)   += scb2_flash.o
 obj-$(CONFIG_MTD_EBONY)                += ebony.o
 obj-$(CONFIG_MTD_OCOTEA)       += ocotea.o
-obj-$(CONFIG_MTD_BEECH)                += beech-mtd.o
-obj-$(CONFIG_MTD_ARCTIC)       += arctic-mtd.o
 obj-$(CONFIG_MTD_WALNUT)        += walnut.o
 obj-$(CONFIG_MTD_H720X)                += h720x-flash.o
 obj-$(CONFIG_MTD_SBC8240)      += sbc8240.o
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
deleted file mode 100644 (file)
index 2cc9024..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Arctic boards.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- * modified for Arctic by,
- * David Gibson
- * IBM OzLabs, Canberra, Australia
- * <arctic@gibson.dropbear.id.au>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-/*
- * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
- * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
- * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
- * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
- */
-
-#define FFS1_SIZE      0x01000000 /* 16MiB */
-#define KERNEL_SIZE    0x00500000 /* 5.12MiB */
-#define FFS2_SIZE      0x00a60000 /* 10.624MiB */
-#define FIRMWARE_SIZE  0x000a0000 /* 640KiB */
-
-
-#define NAME           "Arctic Linux Flash"
-#define PADDR          SUBZERO_BOOTFLASH_PADDR
-#define BUSWIDTH       2
-#define SIZE           SUBZERO_BOOTFLASH_SIZE
-#define PARTITIONS     4
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-{
-  /* do nothing for now */
-}
-
-static struct map_info arctic_mtd_map = {
-       .name           = NAME,
-       .size           = SIZE,
-       .bankwidth      = BUSWIDTH,
-       .phys           = PADDR,
-};
-
-static struct mtd_info *arctic_mtd;
-
-static struct mtd_partition arctic_partitions[PARTITIONS] = {
-       { .name         = "Filesystem",
-         .size         = FFS1_SIZE,
-         .offset       = 0,},
-        { .name                = "Kernel",
-         .size         = KERNEL_SIZE,
-         .offset       = FFS1_SIZE,},
-       { .name         = "Filesystem",
-         .size         = FFS2_SIZE,
-         .offset       = FFS1_SIZE + KERNEL_SIZE,},
-       { .name         = "Firmware",
-         .size         = FIRMWARE_SIZE,
-         .offset       = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-};
-
-static int __init
-init_arctic_mtd(void)
-{
-       int err;
-
-       printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-       arctic_mtd_map.virt = ioremap(PADDR, SIZE);
-
-       if (!arctic_mtd_map.virt) {
-               printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-               return -EIO;
-       }
-       simple_map_init(&arctic_mtd_map);
-
-       printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-       arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-
-       if (!arctic_mtd) {
-               iounmap(arctic_mtd_map.virt);
-               return -ENXIO;
-       }
-
-       arctic_mtd->owner = THIS_MODULE;
-
-       err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
-       if (err) {
-               printk("%s: add_mtd_partitions failed\n", NAME);
-               iounmap(arctic_mtd_map.virt);
-       }
-
-       return err;
-}
-
-static void __exit
-cleanup_arctic_mtd(void)
-{
-       if (arctic_mtd) {
-               del_mtd_partitions(arctic_mtd);
-               map_destroy(arctic_mtd);
-               iounmap((void *) arctic_mtd_map.virt);
-       }
-}
-
-module_init(init_arctic_mtd);
-module_exit(cleanup_arctic_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
deleted file mode 100644 (file)
index d76d598..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Beech boards.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-#define NAME     "Beech Linux Flash"
-#define PADDR    BEECH_BIGFLASH_PADDR
-#define SIZE     BEECH_BIGFLASH_SIZE
-#define BUSWIDTH 1
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-
-static struct map_info beech_mtd_map = {
-       .name =         NAME,
-       .size =         SIZE,
-       .bankwidth =    BUSWIDTH,
-       .phys =         PADDR
-};
-
-static struct mtd_info *beech_mtd;
-
-static struct mtd_partition beech_partitions[2] = {
-       {
-             .name = "Linux Kernel",
-             .size = BEECH_KERNEL_SIZE,
-             .offset = BEECH_KERNEL_OFFSET
-       }, {
-             .name = "Free Area",
-             .size = BEECH_FREE_AREA_SIZE,
-             .offset = BEECH_FREE_AREA_OFFSET
-       }
-};
-
-static int __init
-init_beech_mtd(void)
-{
-       int err;
-
-       printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-       beech_mtd_map.virt = ioremap(PADDR, SIZE);
-
-       if (!beech_mtd_map.virt) {
-               printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-               return -EIO;
-       }
-
-       simple_map_init(&beech_mtd_map);
-
-       printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-       beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-
-       if (!beech_mtd) {
-               iounmap(beech_mtd_map.virt);
-               return -ENXIO;
-       }
-
-       beech_mtd->owner = THIS_MODULE;
-
-       err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
-       if (err) {
-               printk("%s: add_mtd_partitions failed\n", NAME);
-               iounmap(beech_mtd_map.virt);
-       }
-
-       return err;
-}
-
-static void __exit
-cleanup_beech_mtd(void)
-{
-       if (beech_mtd) {
-               del_mtd_partitions(beech_mtd);
-               map_destroy(beech_mtd);
-               iounmap((void *) beech_mtd_map.virt);
-       }
-}
-
-module_init(init_beech_mtd);
-module_exit(cleanup_beech_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
index 9f53c655af3a9e18f1d7c1e9d6a07fb4ade7a824..7b96cd02f82b37c08a4ed0faad6c07b189aa11a3 100644 (file)
@@ -358,7 +358,7 @@ int __init nettel_init(void)
        /* Turn other PAR off so the first probe doesn't find it */
        *intel1par = 0;
 
-       /* Probe for the the size of the first Intel flash */
+       /* Probe for the size of the first Intel flash */
        nettel_intel_map.size = maxsize;
        nettel_intel_map.phys = intel0addr;
        nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
index 72107dc06d6745df15a528febb2cabbe9255a58b..bbb42c35b69b9df05a108f21b0d837f80ca3d7e6 100644 (file)
@@ -186,7 +186,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
        else {
                if (strcmp(of_probe, "ROM"))
                        dev_dbg(&dev->dev, "map_probe: don't know probe type "
-                       "'%s', mapping as rom\n");
+                       "'%s', mapping as rom\n", of_probe);
                info->mtd = do_map_probe("mtd_rom", &info->map);
        }
        if (info->mtd == NULL) {
index 1af989023c6644ca89c8e4107c21fcde8137904d..9c6236852942ec7e98441c5a333c1786a0e83a0c 100644 (file)
@@ -347,7 +347,6 @@ int add_mtd_partitions(struct mtd_info *master,
                slave->mtd.subpage_sft = master->subpage_sft;
 
                slave->mtd.name = parts[i].name;
-               slave->mtd.bank_size = master->bank_size;
                slave->mtd.owner = master->owner;
 
                slave->mtd.read = part_read;
index d05873b8c155a8f8c478fc86cd522ca792441451..f1d60b6f048e6f08aa855e19fed1337a292cfe79 100644 (file)
@@ -232,11 +232,13 @@ config MTD_NAND_BASLER_EXCITE
           will be named "excite_nandflash.ko".
 
 config MTD_NAND_CAFE
-       tristate "NAND support for OLPC CAFÉ chip"
-       depends on PCI
-       help
-        Use NAND flash attached to the CAFÉ chip designed for the $100
-        laptop.
+       tristate "NAND support for OLPC CAFÉ chip"
+       depends on PCI
+       select REED_SOLOMON
+       select REED_SOLOMON_DEC16
+       help
+         Use NAND flash attached to the CAFÉ chip designed for the $100
+         laptop.
 
 config MTD_NAND_CS553X
        tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
@@ -270,4 +272,13 @@ config MTD_NAND_NANDSIM
          The simulator may simulate various NAND flash chips for the
          MTD nand layer.
 
+config MTD_NAND_PLATFORM
+       tristate "Support for generic platform NAND driver"
+       depends on MTD_NAND
+       help
+         This implements a generic NAND driver for on-SOC platform
+         devices. You will need to provide platform-specific functions
+         via platform_data.
+
+
 endif # MTD_NAND
index 6872031a3fb25ff45d4e263691133d4698d94c8f..edba1db14bfad6581260b822b60a260063fc542c 100644 (file)
@@ -26,6 +26,6 @@ obj-$(CONFIG_MTD_NAND_NDFC)           += ndfc.o
 obj-$(CONFIG_MTD_NAND_AT91)            += at91_nand.o
 obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
+obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
-cafe_nand-objs := cafe.o cafe_ecc.o
index 14b80cc90a7b789d7af4efe96b549bb105f87e22..512e999177f70cb39c745ac6d454d22e6a4c3bae 100644 (file)
@@ -82,6 +82,10 @@ static void at91_nand_disable(struct at91_nand_host *host)
                at91_set_gpio_value(host->board->enable_pin, 1);
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -151,6 +155,12 @@ static int __init at91_nand_probe(struct platform_device *pdev)
 #ifdef CONFIG_MTD_PARTITIONS
        if (host->board->partition_info)
                partitions = host->board->partition_info(mtd->size, &num_partitions);
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       else {
+               mtd->name = "at91_nand";
+               num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+       }
+#endif
 
        if ((!partitions) || (num_partitions == 0)) {
                printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
deleted file mode 100644 (file)
index ea5c849..0000000
+++ /dev/null
@@ -1,1381 +0,0 @@
-/* Error correction for CAFÉ NAND controller
- *
- * © 2006 Marvell, Inc.
- * Author: Tom Chiou
- *
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-
-static unsigned short gf4096_mul(unsigned short, unsigned short);
-static unsigned short gf64_mul(unsigned short, unsigned short);
-static unsigned short gf4096_inv(unsigned short);
-static unsigned short err_pos(unsigned short);
-static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short *);
-static void zero_4x5_col3(unsigned short[4][5]);
-static void zero_4x5_col2(unsigned short[4][5]);
-static void zero_4x5_col1(unsigned short[4][5]);
-static void swap_4x5_rows(unsigned short[4][5], int, int, int);
-static void swap_2x3_rows(unsigned short m[2][3]);
-static void solve_4x5(unsigned short m[4][5], unsigned short *, int *);
-static void sort_coefs(int *, unsigned short *, int);
-static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short *);
-static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short,
-                               unsigned short *);
-static void zero_3x4_col2(unsigned short[3][4]);
-static void zero_3x4_col1(unsigned short[3][4]);
-static void swap_3x4_rows(unsigned short[3][4], int, int, int);
-static void solve_3x4(unsigned short[3][4], unsigned short *, int *);
-static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short,
-                              unsigned short *);
-
-static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short *);
-static void find_2x2_soln(unsigned short, unsigned short, unsigned short,
-                         unsigned short, unsigned short, unsigned short,
-                         unsigned short *);
-static void solve_2x3(unsigned short[2][3], unsigned short *);
-static int chk_no_err_only(unsigned short *, unsigned short *);
-static int chk_1_err_only(unsigned short *, unsigned short *);
-static int chk_2_err_only(unsigned short *, unsigned short *);
-static int chk_3_err_only(unsigned short *, unsigned short *);
-static int chk_4_err_only(unsigned short *, unsigned short *);
-
-static unsigned short gf64_mul(unsigned short a, unsigned short b)
-{
-       unsigned short tmp1, tmp2, tmp3, tmp4, tmp5;
-       unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c;
-
-       tmp1 = ((a) ^ (a >> 5));
-       tmp2 = ((a >> 4) ^ (a >> 5));
-       tmp3 = ((a >> 3) ^ (a >> 4));
-       tmp4 = ((a >> 2) ^ (a >> 3));
-       tmp5 = ((a >> 1) ^ (a >> 2));
-
-       c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^
-                 ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1;
-
-       c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^
-                 (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1;
-
-       c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^
-                 (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1;
-
-       c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^
-                 (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1;
-
-       c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^
-                 ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1;
-
-       c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^
-                 ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1;
-
-       c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5);
-
-       return c;
-}
-
-static unsigned short gf4096_mul(unsigned short a, unsigned short b)
-{
-       unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c;
-
-       ah = (a >> 6) & 0x3f;
-       al = a & 0x3f;
-       bh = (b >> 6) & 0x3f;
-       bl = b & 0x3f;
-       alxah = al ^ ah;
-       blxbh = bl ^ bh;
-
-       ablh = gf64_mul(alxah, blxbh);
-       albl = gf64_mul(al, bl);
-       ahbh = gf64_mul(ah, bh);
-
-       ahbhB = ((ahbh & 0x1) << 5) |
-           ((ahbh & 0x20) >> 1) |
-           ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1);
-
-       c = ((ablh ^ albl) << 6) | (ahbhB ^ albl);
-       return c;
-}
-
-static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats)
-{
-       find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats);
-}
-
-static void find_3bit_err_coefs(unsigned short s0, unsigned short s1,
-                               unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs)
-{
-       unsigned short m[3][4];
-       int row_order[3];
-
-       row_order[0] = 0;
-       row_order[1] = 1;
-       row_order[2] = 2;
-       m[0][0] = s2;
-       m[0][1] = s1;
-       m[0][2] = s0;
-       m[0][3] = s3;
-       m[1][0] = s3;
-       m[1][1] = s2;
-       m[1][2] = s1;
-       m[1][3] = s4;
-       m[2][0] = s4;
-       m[2][1] = s3;
-       m[2][2] = s2;
-       m[2][3] = s5;
-
-       if (m[0][2] != 0x0) {
-               zero_3x4_col2(m);
-       } else if (m[1][2] != 0x0) {
-               swap_3x4_rows(m, 0, 1, 4);
-               zero_3x4_col2(m);
-       } else if (m[2][2] != 0x0) {
-               swap_3x4_rows(m, 0, 2, 4);
-               zero_3x4_col2(m);
-       } else {
-               printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n");
-       }
-
-       if (m[1][1] != 0x0) {
-               zero_3x4_col1(m);
-       } else if (m[2][1] != 0x0) {
-               swap_3x4_rows(m, 1, 2, 4);
-               zero_3x4_col1(m);
-       } else {
-               printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n");
-       }
-
-       /* solve coefs */
-       solve_3x4(m, coefs, row_order);
-}
-
-static void zero_3x4_col2(unsigned short m[3][4])
-{
-       unsigned short minv1, minv2;
-
-       minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2]));
-       minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2]));
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-       m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-       m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1);
-       m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-       m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2);
-}
-
-static void zero_3x4_col1(unsigned short m[3][4])
-{
-       unsigned short minv;
-       minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1]));
-       m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv);
-       m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv);
-}
-
-static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width)
-{
-       unsigned short tmp0;
-       int cnt;
-       for (cnt = 0; cnt < col_width; cnt++) {
-               tmp0 = m[i][cnt];
-               m[i][cnt] = m[j][cnt];
-               m[j][cnt] = tmp0;
-       }
-}
-
-static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order)
-{
-       unsigned short tmp[3];
-       tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0]));
-       tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1]));
-       tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2]));
-       sort_coefs(row_order, tmp, 3);
-       coefs[0] = tmp[0];
-       coefs[1] = tmp[1];
-       coefs[2] = tmp[2];
-}
-
-static void find_3bit_err_pats(unsigned short s0, unsigned short s1,
-                              unsigned short s2, unsigned short r0,
-                              unsigned short r1, unsigned short r2,
-                              unsigned short *pats)
-{
-       find_2x2_soln(r0 ^ r2, r1 ^ r2,
-                     gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2),
-                     gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats);
-       pats[2] = s0 ^ pats[0] ^ pats[1];
-}
-
-static void find_4bit_err_coefs(unsigned short s0, unsigned short s1,
-                               unsigned short s2, unsigned short s3,
-                               unsigned short s4, unsigned short s5,
-                               unsigned short s6, unsigned short s7,
-                               unsigned short *coefs)
-{
-       unsigned short m[4][5];
-       int row_order[4];
-
-       row_order[0] = 0;
-       row_order[1] = 1;
-       row_order[2] = 2;
-       row_order[3] = 3;
-
-       m[0][0] = s3;
-       m[0][1] = s2;
-       m[0][2] = s1;
-       m[0][3] = s0;
-       m[0][4] = s4;
-       m[1][0] = s4;
-       m[1][1] = s3;
-       m[1][2] = s2;
-       m[1][3] = s1;
-       m[1][4] = s5;
-       m[2][0] = s5;
-       m[2][1] = s4;
-       m[2][2] = s3;
-       m[2][3] = s2;
-       m[2][4] = s6;
-       m[3][0] = s6;
-       m[3][1] = s5;
-       m[3][2] = s4;
-       m[3][3] = s3;
-       m[3][4] = s7;
-
-       if (m[0][3] != 0x0) {
-               zero_4x5_col3(m);
-       } else if (m[1][3] != 0x0) {
-               swap_4x5_rows(m, 0, 1, 5);
-               zero_4x5_col3(m);
-       } else if (m[2][3] != 0x0) {
-               swap_4x5_rows(m, 0, 2, 5);
-               zero_4x5_col3(m);
-       } else if (m[3][3] != 0x0) {
-               swap_4x5_rows(m, 0, 3, 5);
-               zero_4x5_col3(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n");
-       }
-
-       if (m[1][2] != 0x0) {
-               zero_4x5_col2(m);
-       } else if (m[2][2] != 0x0) {
-               swap_4x5_rows(m, 1, 2, 5);
-               zero_4x5_col2(m);
-       } else if (m[3][2] != 0x0) {
-               swap_4x5_rows(m, 1, 3, 5);
-               zero_4x5_col2(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n");
-       }
-
-       if (m[2][1] != 0x0) {
-               zero_4x5_col1(m);
-       } else if (m[3][1] != 0x0) {
-               swap_4x5_rows(m, 2, 3, 5);
-               zero_4x5_col1(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n");
-       }
-
-       solve_4x5(m, coefs, row_order);
-}
-
-static void zero_4x5_col3(unsigned short m[4][5])
-{
-       unsigned short minv1, minv2, minv3;
-
-       minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3]));
-       minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3]));
-       minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3]));
-
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-       m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-       m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1);
-       m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1);
-       m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-       m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2);
-       m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2);
-       m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3);
-       m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3);
-       m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3);
-}
-
-static void zero_4x5_col2(unsigned short m[4][5])
-{
-       unsigned short minv2, minv3;
-
-       minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2]));
-       minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2]));
-
-       m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2);
-       m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2);
-       m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3);
-       m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3);
-}
-
-static void zero_4x5_col1(unsigned short m[4][5])
-{
-       unsigned short minv;
-
-       minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1]));
-
-       m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv);
-}
-
-static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width)
-{
-       unsigned short tmp0;
-       int cnt;
-
-       for (cnt = 0; cnt < col_width; cnt++) {
-               tmp0 = m[i][cnt];
-               m[i][cnt] = m[j][cnt];
-               m[j][cnt] = tmp0;
-       }
-}
-
-static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order)
-{
-       unsigned short tmp[4];
-
-       tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0]));
-       tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1]));
-       tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2]));
-       tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^
-                       gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3]));
-       sort_coefs(row_order, tmp, 4);
-       coefs[0] = tmp[0];
-       coefs[1] = tmp[1];
-       coefs[2] = tmp[2];
-       coefs[3] = tmp[3];
-}
-
-static void sort_coefs(int *order, unsigned short *soln, int len)
-{
-       int cnt, start_cnt, least_ord, least_cnt;
-       unsigned short tmp0;
-       for (start_cnt = 0; start_cnt < len; start_cnt++) {
-               for (cnt = start_cnt; cnt < len; cnt++) {
-                       if (cnt == start_cnt) {
-                               least_ord = order[cnt];
-                               least_cnt = start_cnt;
-                       } else {
-                               if (least_ord > order[cnt]) {
-                                       least_ord = order[cnt];
-                                       least_cnt = cnt;
-                               }
-                       }
-               }
-               if (least_cnt != start_cnt) {
-                       tmp0 = order[least_cnt];
-                       order[least_cnt] = order[start_cnt];
-                       order[start_cnt] = tmp0;
-                       tmp0 = soln[least_cnt];
-                       soln[least_cnt] = soln[start_cnt];
-                       soln[start_cnt] = tmp0;
-               }
-       }
-}
-
-static void find_4bit_err_pats(unsigned short s0, unsigned short s1,
-                              unsigned short s2, unsigned short s3,
-                              unsigned short z1, unsigned short z2,
-                              unsigned short z3, unsigned short z4,
-                              unsigned short *pats)
-{
-       unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1,
-               z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3;
-       unsigned short tmp0, tmp1, tmp2, tmp3;
-
-       z4_z1 = z4 ^ z1;
-       z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3);
-       z4_z2 = z4 ^ z2;
-       s0z4_s1 = gf4096_mul(s0, z4) ^ s1;
-       z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1);
-       z4_z3 = z4 ^ z3;
-       z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2);
-       s1z4_s2 = gf4096_mul(s1, z4) ^ s2;
-       z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3);
-       z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1);
-       z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2);
-       s2z4_s3 = gf4096_mul(s2, z4) ^ s3;
-
-       //find err pat 0,1
-       find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^
-                     gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2,
-                                                              z3z4_z3z3) ^
-                     gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1,
-                                                              z3z3z4_z3z3z3) ^
-                     gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3),
-                     gf4096_mul(z2z4_z2z2,
-                                z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2,
-                                                            z3z4_z3z3),
-                     gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2,
-                                                                 z4_z3),
-                     gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats);
-       tmp0 = pats[0];
-       tmp1 = pats[1];
-       tmp2 = pats[0] ^ pats[1] ^ s0;
-       tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1;
-
-       //find err pat 2,3
-       find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats);
-       pats[2] = pats[0];
-       pats[3] = pats[1];
-       pats[0] = tmp0;
-       pats[1] = tmp1;
-}
-
-static void find_2x2_soln(unsigned short c00, unsigned short c01,
-                         unsigned short c10, unsigned short c11,
-                         unsigned short lval0, unsigned short lval1,
-                         unsigned short *soln)
-{
-       unsigned short m[2][3];
-       m[0][0] = c00;
-       m[0][1] = c01;
-       m[0][2] = lval0;
-       m[1][0] = c10;
-       m[1][1] = c11;
-       m[1][2] = lval1;
-
-       if (m[0][1] != 0x0) {
-               /* */
-       } else if (m[1][1] != 0x0) {
-               swap_2x3_rows(m);
-       } else {
-               printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n");
-       }
-
-       solve_2x3(m, soln);
-}
-
-static void swap_2x3_rows(unsigned short m[2][3])
-{
-       unsigned short tmp0;
-       int cnt;
-
-       for (cnt = 0; cnt < 3; cnt++) {
-               tmp0 = m[0][cnt];
-               m[0][cnt] = m[1][cnt];
-               m[1][cnt] = tmp0;
-       }
-}
-
-static void solve_2x3(unsigned short m[2][3], unsigned short *coefs)
-{
-       unsigned short minv;
-
-       minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1]));
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv);
-       m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv);
-       coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0]));
-       coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1]));
-}
-
-static unsigned char gf64_inv[64] = {
-        0,  1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25,
-       61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45,  6,
-       63,  2, 27, 21, 56,  9, 50, 19, 13, 47, 48,  5,  7, 30, 12, 41,
-       42,  4, 38, 18, 10, 29, 17, 60, 36,  8, 59, 58, 55, 16,  3, 32
-};
-
-static unsigned short gf4096_inv(unsigned short din)
-{
-       unsigned short alahxal, ah2B, deno, inv, bl, bh;
-       unsigned short ah, al, ahxal;
-       unsigned short dout;
-
-       ah = (din >> 6) & 0x3f;
-       al = din & 0x3f;
-       ahxal = ah ^ al;
-       ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) |
-               ((ah >> 1) & 0x10) |
-               ((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) |
-               ((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1);
-       alahxal = gf64_mul(ahxal, al);
-       deno = alahxal ^ ah2B;
-       inv = gf64_inv[deno];
-       bl = gf64_mul(inv, ahxal);
-       bh = gf64_mul(inv, ah);
-       dout = ((bh & 0x3f) << 6) | (bl & 0x3f);
-       return (((bh & 0x3f) << 6) | (bl & 0x3f));
-}
-
-static unsigned short err_pos_lut[4096] = {
-       0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff,
-       0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff,
-       0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff,
-       0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff,
-       0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7,
-       0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff,
-       0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff,
-       0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f,
-       0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8,
-       0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe,
-       0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff,
-       0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1,
-       0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff,
-       0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff,
-       0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff,
-       0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8,
-       0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e,
-       0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff,
-       0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff,
-       0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff,
-       0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535,
-       0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d,
-       0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff,
-       0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5,
-       0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff,
-       0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294,
-       0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff,
-       0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4,
-       0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f,
-       0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b,
-       0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff,
-       0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff,
-       0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff,
-       0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158,
-       0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a,
-       0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff,
-       0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff,
-       0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017,
-       0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a,
-       0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351,
-       0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff,
-       0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff,
-       0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074,
-       0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da,
-       0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433,
-       0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285,
-       0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff,
-       0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d,
-       0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff,
-       0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff,
-       0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331,
-       0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff,
-       0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6,
-       0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3,
-       0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff,
-       0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf,
-       0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc,
-       0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381,
-       0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff,
-       0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f,
-       0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff,
-       0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488,
-       0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442,
-       0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6,
-       0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1,
-       0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae,
-       0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff,
-       0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff,
-       0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2,
-       0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec,
-       0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134,
-       0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b,
-       0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff,
-       0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff,
-       0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff,
-       0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5,
-       0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff,
-       0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff,
-       0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff,
-       0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff,
-       0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2,
-       0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff,
-       0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff,
-       0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff,
-       0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff,
-       0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff,
-       0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff,
-       0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff,
-       0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8,
-       0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb,
-       0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff,
-       0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff,
-       0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd,
-       0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff,
-       0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8,
-       0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9,
-       0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f,
-       0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7,
-       0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff,
-       0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d,
-       0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178,
-       0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff,
-       0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba,
-       0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff,
-       0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e,
-       0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff,
-       0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6,
-       0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff,
-       0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff,
-       0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc,
-       0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6,
-       0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5,
-       0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff,
-       0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc,
-       0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff,
-       0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3,
-       0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff,
-       0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6,
-       0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff,
-       0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a,
-       0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff,
-       0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff,
-       0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff,
-       0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff,
-       0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7,
-       0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff,
-       0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff,
-       0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af,
-       0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff,
-       0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2,
-       0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff,
-       0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff,
-       0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff,
-       0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339,
-       0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff,
-       0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff,
-       0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402,
-       0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff,
-       0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368,
-       0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b,
-       0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f,
-       0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff,
-       0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1,
-       0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff,
-       0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff,
-       0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb,
-       0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc,
-       0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097,
-       0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431,
-       0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1,
-       0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff,
-       0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6,
-       0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd,
-       0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff,
-       0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb,
-       0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff,
-       0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd,
-       0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff,
-       0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff,
-       0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519,
-       0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff,
-       0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084,
-       0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0,
-       0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c,
-       0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f,
-       0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a,
-       0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211,
-       0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff,
-       0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff,
-       0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff,
-       0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff,
-       0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff,
-       0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff,
-       0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180,
-       0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0,
-       0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004,
-       0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302,
-       0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff,
-       0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff,
-       0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272,
-       0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff,
-       0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344,
-       0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff,
-       0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e,
-       0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d,
-       0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff,
-       0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330,
-       0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042,
-       0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364,
-       0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff,
-       0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff,
-       0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f,
-       0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb,
-       0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e,
-       0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c,
-       0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194,
-       0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff,
-       0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff,
-       0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff,
-       0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff,
-       0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6,
-       0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff,
-       0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290,
-       0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff,
-       0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9,
-       0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d,
-       0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff,
-       0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9,
-       0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167,
-       0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020,
-       0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347,
-       0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff,
-       0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff,
-       0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff,
-       0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff,
-       0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff,
-       0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039,
-       0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096,
-       0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff,
-       0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8,
-       0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff,
-       0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd,
-       0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e,
-       0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f,
-       0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff,
-       0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7,
-       0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb,
-       0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff,
-       0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078,
-       0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300,
-       0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200,
-       0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f,
-       0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff,
-       0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216,
-       0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d,
-       0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0,
-       0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff,
-       0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff,
-       0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff,
-       0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff,
-       0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff,
-       0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff,
-       0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086,
-       0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff,
-       0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444,
-       0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110,
-       0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099,
-       0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da,
-       0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff,
-       0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff,
-       0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff,
-       0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff,
-       0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff,
-       0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283,
-       0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff,
-       0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff,
-       0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff,
-       0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff,
-       0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff,
-       0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195,
-       0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff,
-       0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff,
-       0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff,
-       0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff,
-       0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff,
-       0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245,
-       0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff,
-       0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6,
-       0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1,
-       0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da,
-       0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff,
-       0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff,
-       0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5,
-       0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223,
-       0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002
-};
-
-static unsigned short err_pos(unsigned short din)
-{
-       BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
-       return err_pos_lut[din];
-}
-static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       if ((chk_syndrome_list[0] | chk_syndrome_list[1] |
-            chk_syndrome_list[2] | chk_syndrome_list[3] |
-            chk_syndrome_list[4] | chk_syndrome_list[5] |
-            chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) {
-               return -EINVAL;
-       } else {
-               err_info[0] = 0x0;
-               return 0;
-       }
-}
-static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
-       tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0]));
-       tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1]));
-       tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2]));
-       tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3]));
-       tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4]));
-       tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5]));
-       tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6]));
-       if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) {
-               err_info[0] = 0x1;      // encode 1-symbol error as 0x1
-               err_info[1] = err_pos(tmp0);
-               err_info[1] = (unsigned short)(0x55e - err_info[1]);
-               err_info[5] = chk_syndrome_list[0];
-               return 0;
-       } else
-               return -EINVAL;
-}
-static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit2_root0, bit2_root1;
-       unsigned short bit2_root0_inv, bit2_root1_inv;
-       unsigned short err_loc_eqn, test_root;
-       unsigned short bit2_loc0, bit2_loc1;
-       unsigned short bit2_pat0, bit2_pat1;
-
-       find_2x2_soln(chk_syndrome_list[1],
-                     chk_syndrome_list[0],
-                     chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs);
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn =
-                   gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit2_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit2_root1 = test_root;
-                               found_num_root = 2;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 2)
-               return -EINVAL;
-       else {
-               bit2_root0_inv = gf4096_inv(bit2_root0);
-               bit2_root1_inv = gf4096_inv(bit2_root1);
-               find_2bit_err_pats(chk_syndrome_list[0],
-                                  chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats);
-               bit2_pat0 = err_pats[0];
-               bit2_pat1 = err_pats[1];
-               //for(x+1)
-               tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv));      //rinv0^4
-               tmp1 = gf4096_mul(bit2_root0_inv, tmp0);        //rinv0^5
-               tmp2 = gf4096_mul(bit2_root0_inv, tmp1);        //rinv0^6
-               tmp3 = gf4096_mul(bit2_root0_inv, tmp2);        //rinv0^7
-               tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv));      //rinv1^4
-               tmp5 = gf4096_mul(bit2_root1_inv, tmp4);        //rinv1^5
-               tmp6 = gf4096_mul(bit2_root1_inv, tmp5);        //rinv1^6
-               tmp7 = gf4096_mul(bit2_root1_inv, tmp6);        //rinv1^7
-               //check if only 2-bit error
-               if ((chk_syndrome_list[4] ==
-                    (gf4096_mul(bit2_pat0, tmp0) ^
-                     gf4096_mul(bit2_pat1,
-                                tmp4))) & (chk_syndrome_list[5] ==
-                                           (gf4096_mul(bit2_pat0, tmp1) ^
-                                            gf4096_mul(bit2_pat1,
-                                                       tmp5))) &
-                   (chk_syndrome_list[6] ==
-                    (gf4096_mul(bit2_pat0, tmp2) ^
-                     gf4096_mul(bit2_pat1,
-                                tmp6))) & (chk_syndrome_list[7] ==
-                                           (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) {
-                       if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) {
-                               return -EINVAL;
-                       } else {
-                               bit2_loc0 = 0x55e - err_pos(bit2_root0_inv);
-                               bit2_loc1 = 0x55e - err_pos(bit2_root1_inv);
-                               err_info[0] = 0x2;      // encode 2-symbol error as 0x2
-                               err_info[1] = bit2_loc0;
-                               err_info[2] = bit2_loc1;
-                               err_info[5] = bit2_pat0;
-                               err_info[6] = bit2_pat1;
-                               return 0;
-                       }
-               } else
-                       return -EINVAL;
-       }
-}
-static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit3_root0, bit3_root1, bit3_root2;
-       unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv;
-       unsigned short err_loc_eqn, test_root;
-
-       find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1],
-                           chk_syndrome_list[2], chk_syndrome_list[3],
-                           chk_syndrome_list[4], chk_syndrome_list[5], coefs);
-
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn = gf4096_mul(coefs[2],
-                                        gf4096_mul(gf4096_mul(test_root, test_root),
-                                                   test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root))
-                       ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit3_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit3_root1 = test_root;
-                               found_num_root = 2;
-                       } else if (found_num_root == 2) {
-                               bit3_root2 = test_root;
-                               found_num_root = 3;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 3)
-               return -EINVAL;
-       else {
-               bit3_root0_inv = gf4096_inv(bit3_root0);
-               bit3_root1_inv = gf4096_inv(bit3_root1);
-               bit3_root2_inv = gf4096_inv(bit3_root2);
-
-               find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1],
-                                  chk_syndrome_list[2], bit3_root0_inv,
-                                  bit3_root1_inv, bit3_root2_inv, err_pats);
-
-               //check if only 3-bit error
-               tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv);
-               tmp0 = gf4096_mul(tmp0, tmp0);
-               tmp0 = gf4096_mul(tmp0, bit3_root0_inv);
-               tmp0 = gf4096_mul(tmp0, bit3_root0_inv);        //rinv0^6
-               tmp1 = gf4096_mul(tmp0, bit3_root0_inv);        //rinv0^7
-               tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv);
-               tmp2 = gf4096_mul(tmp2, tmp2);
-               tmp2 = gf4096_mul(tmp2, bit3_root1_inv);
-               tmp2 = gf4096_mul(tmp2, bit3_root1_inv);        //rinv1^6
-               tmp3 = gf4096_mul(tmp2, bit3_root1_inv);        //rinv1^7
-               tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv);
-               tmp4 = gf4096_mul(tmp4, tmp4);
-               tmp4 = gf4096_mul(tmp4, bit3_root2_inv);
-               tmp4 = gf4096_mul(tmp4, bit3_root2_inv);        //rinv2^6
-               tmp5 = gf4096_mul(tmp4, bit3_root2_inv);        //rinv2^7
-
-               //check if only 3 errors
-               if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^
-                                             gf4096_mul(err_pats[1], tmp2) ^
-                                             gf4096_mul(err_pats[2], tmp4))) &
-                   (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^
-                                             gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) {
-                       if ((err_pos(bit3_root0_inv) == 0xfff) |
-                           (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) {
-                               return -EINVAL;
-                       } else {
-                               err_info[0] = 0x3;
-                               err_info[1] = (0x55e - err_pos(bit3_root0_inv));
-                               err_info[2] = (0x55e - err_pos(bit3_root1_inv));
-                               err_info[3] = (0x55e - err_pos(bit3_root2_inv));
-                               err_info[5] = err_pats[0];
-                               err_info[6] = err_pats[1];
-                               err_info[7] = err_pats[2];
-                               return 0;
-                       }
-               } else
-                       return -EINVAL;
-       }
-}
-static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3;
-       unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv;
-       unsigned short err_loc_eqn, test_root;
-
-       find_4bit_err_coefs(chk_syndrome_list[0],
-                           chk_syndrome_list[1],
-                           chk_syndrome_list[2],
-                           chk_syndrome_list[3],
-                           chk_syndrome_list[4],
-                           chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs);
-
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn =
-                   gf4096_mul(coefs[3],
-                              gf4096_mul(gf4096_mul
-                                         (gf4096_mul(test_root, test_root),
-                                          test_root),
-                                         test_root)) ^ gf4096_mul(coefs[2],
-                                                                  gf4096_mul
-                                                                  (gf4096_mul(test_root, test_root), test_root))
-                   ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root)
-                   ^ 0x1;
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit4_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit4_root1 = test_root;
-                               found_num_root = 2;
-                       } else if (found_num_root == 2) {
-                               bit4_root2 = test_root;
-                               found_num_root = 3;
-                       } else {
-                               found_num_root = 4;
-                               bit4_root3 = test_root;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 4) {
-               return -EINVAL;
-       } else {
-               bit4_root0_inv = gf4096_inv(bit4_root0);
-               bit4_root1_inv = gf4096_inv(bit4_root1);
-               bit4_root2_inv = gf4096_inv(bit4_root2);
-               bit4_root3_inv = gf4096_inv(bit4_root3);
-               find_4bit_err_pats(chk_syndrome_list[0],
-                                  chk_syndrome_list[1],
-                                  chk_syndrome_list[2],
-                                  chk_syndrome_list[3],
-                                  bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats);
-               err_info[0] = 0x4;
-               err_info[1] = (0x55e - err_pos(bit4_root0_inv));
-               err_info[2] = (0x55e - err_pos(bit4_root1_inv));
-               err_info[3] = (0x55e - err_pos(bit4_root2_inv));
-               err_info[4] = (0x55e - err_pos(bit4_root3_inv));
-               err_info[5] = err_pats[0];
-               err_info[6] = err_pats[1];
-               err_info[7] = err_pats[2];
-               err_info[8] = err_pats[3];
-               return 0;
-       }
-}
-
-void correct_12bit_symbol(unsigned char *buf, unsigned short sym,
-                         unsigned short val)
-{
-       if (unlikely(sym > 1366)) {
-               printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym);
-       } else if (sym == 0) {
-               buf[0] ^= val;
-       } else if (sym & 1) {
-               buf[1+(3*(sym-1))/2] ^= (val >> 4);
-               buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4);
-       } else {
-               buf[2+(3*(sym-2))/2] ^= (val >> 8);
-               buf[3+(3*(sym-2))/2] ^= (val & 0xff);
-       }
-}
-
-static int debugecc = 0;
-module_param(debugecc, int, 0644);
-
-int cafe_correct_ecc(unsigned char *buf,
-                    unsigned short *chk_syndrome_list)
-{
-       unsigned short err_info[9];
-       int i;
-
-       if (debugecc) {
-               printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n",
-                      chk_syndrome_list[0], chk_syndrome_list[1],
-                      chk_syndrome_list[2], chk_syndrome_list[3],
-                      chk_syndrome_list[4], chk_syndrome_list[5],
-                      chk_syndrome_list[6], chk_syndrome_list[7]);
-               for (i=0; i < 2048; i+=16) {
-                       printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              i,
-                              buf[i], buf[i+1], buf[i+2], buf[i+3],
-                              buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-                              buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-                              buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-               }
-               for ( ; i < 2112; i+=16) {
-                       printk(KERN_WARNING "O   %02x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              i - 2048,
-                              buf[i], buf[i+1], buf[i+2], buf[i+3],
-                              buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-                              buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-                              buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-               }
-       }
-
-
-
-       if (chk_no_err_only(chk_syndrome_list, err_info) &&
-           chk_1_err_only(chk_syndrome_list, err_info) &&
-           chk_2_err_only(chk_syndrome_list, err_info) &&
-           chk_3_err_only(chk_syndrome_list, err_info) &&
-           chk_4_err_only(chk_syndrome_list, err_info)) {
-               return -EIO;
-       }
-
-       for (i=0; i < err_info[0]; i++) {
-               if (debugecc)
-                       printk(KERN_WARNING "Correct symbol %d with 0x%03x\n",
-                              err_info[1+i], err_info[5+i]);
-
-               correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]);
-       }
-
-       return err_info[0];
-}
-
similarity index 88%
rename from drivers/mtd/nand/cafe.c
rename to drivers/mtd/nand/cafe_nand.c
index c328a7514510d836e843b6657e4bf1f71340389b..cff969d05d4a1824cb18fda1808f89a9f9700000 100644 (file)
@@ -11,6 +11,7 @@
 #undef DEBUG
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/rslib.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #define CAFE_GLOBAL_IRQ_MASK   0x300c
 #define CAFE_NAND_RESET                0x3034
 
-int cafe_correct_ecc(unsigned char *buf,
-                    unsigned short *chk_syndrome_list);
+/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+#define CTRL1_CHIPSELECT       (1<<19)
 
 struct cafe_priv {
        struct nand_chip nand;
        struct pci_dev *pdev;
        void __iomem *mmio;
+       struct rs_control *rs;
        uint32_t ctl1;
        uint32_t ctl2;
        int datalen;
@@ -195,8 +197,8 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 
        cafe->data_pos = cafe->datalen = 0;
 
-       /* Set command valid bit */
-       ctl1 = 0x80000000 | command;
+       /* Set command valid bit, mask in the chip select bit  */
+       ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
 
        /* Set RD or WR bits as appropriate */
        if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
@@ -309,8 +311,16 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 
 static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
 {
-       //struct cafe_priv *cafe = mtd->priv;
-       //      cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+       struct cafe_priv *cafe = mtd->priv;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+
+       /* Mask the appropriate bit into the stored value of ctl1
+          which will be used by cafe_nand_cmdfunc() */
+       if (chipnr)
+               cafe->ctl1 |= CTRL1_CHIPSELECT;
+       else
+               cafe->ctl1 &= ~CTRL1_CHIPSELECT;
 }
 
 static int cafe_nand_interrupt(int irq, void *id)
@@ -374,28 +384,66 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
        if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
-               unsigned short syn[8];
-               int i;
+               unsigned short syn[8], pat[4];
+               int pos[4];
+               u8 *oob = chip->oob_poi;
+               int i, n;
 
                for (i=0; i<8; i+=2) {
                        uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
-                       syn[i] = tmp & 0xfff;
-                       syn[i+1] = (tmp >> 16) & 0xfff;
+                       syn[i] = cafe->rs->index_of[tmp & 0xfff];
+                       syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+               }
+
+               n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+                               pat);
+
+               for (i = 0; i < n; i++) {
+                       int p = pos[i];
+
+                       /* The 12-bit symbols are mapped to bytes here */
+
+                       if (p > 1374) {
+                               /* out of range */
+                               n = -1374;
+                       } else if (p == 0) {
+                               /* high four bits do not correspond to data */
+                               if (pat[i] > 0xff)
+                                       n = -2048;
+                               else
+                                       buf[0] ^= pat[i];
+                       } else if (p == 1365) {
+                               buf[2047] ^= pat[i] >> 4;
+                               oob[0] ^= pat[i] << 4;
+                       } else if (p > 1365) {
+                               if ((p & 1) == 1) {
+                                       oob[3*p/2 - 2048] ^= pat[i] >> 4;
+                                       oob[3*p/2 - 2047] ^= pat[i] << 4;
+                               } else {
+                                       oob[3*p/2 - 2049] ^= pat[i] >> 8;
+                                       oob[3*p/2 - 2048] ^= pat[i];
+                               }
+                       } else if ((p & 1) == 1) {
+                               buf[3*p/2] ^= pat[i] >> 4;
+                               buf[3*p/2 + 1] ^= pat[i] << 4;
+                       } else {
+                               buf[3*p/2 - 1] ^= pat[i] >> 8;
+                               buf[3*p/2] ^= pat[i];
+                       }
                }
 
-               if ((i = cafe_correct_ecc(buf, syn)) < 0) {
+               if (n < 0) {
                        dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
                                cafe_readl(cafe, NAND_ADDR2) * 2048);
-                       for (i=0; i< 0x5c; i+=4)
+                       for (i = 0; i < 0x5c; i += 4)
                                printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
                        mtd->ecc_stats.failed++;
                } else {
-                       dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
-                       mtd->ecc_stats.corrected += i;
+                       dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+                       mtd->ecc_stats.corrected += n;
                }
        }
 
-
        return 0;
 }
 
@@ -416,7 +464,7 @@ static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
 
 static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
        .offs = 14,
        .len = 4,
        .veroffs = 18,
@@ -426,7 +474,7 @@ static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
 
 static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
        .offs = 14,
        .len = 4,
        .veroffs = 18,
@@ -442,7 +490,7 @@ static struct nand_ecclayout cafe_oobinfo_512 = {
 
 static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
        .offs = 14,
        .len = 1,
        .veroffs = 15,
@@ -452,7 +500,7 @@ static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
 
 static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
        .offs = 14,
        .len = 1,
        .veroffs = 15,
@@ -525,6 +573,48 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        return 0;
 }
 
+/* F_2[X]/(X**6+X+1)  */
+static unsigned short __devinit gf64_mul(u8 a, u8 b)
+{
+       u8 c;
+       unsigned int i;
+
+       c = 0;
+       for (i = 0; i < 6; i++) {
+               if (a & 1)
+                       c ^= b;
+               a >>= 1;
+               b <<= 1;
+               if ((b & 0x40) != 0)
+                       b ^= 0x43;
+       }
+
+       return c;
+}
+
+/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
+static u16 __devinit gf4096_mul(u16 a, u16 b)
+{
+       u8 ah, al, bh, bl, ch, cl;
+
+       ah = a >> 6;
+       al = a & 0x3f;
+       bh = b >> 6;
+       bl = b & 0x3f;
+
+       ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+       cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+
+       return (ch << 6) ^ cl;
+}
+
+static int __devinit cafe_mul(int x)
+{
+       if (x == 0)
+               return 1;
+       return gf4096_mul(x, 0xe01);
+}
+
 static int __devinit cafe_nand_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
@@ -564,6 +654,12 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        }
        cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
 
+       cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+       if (!cafe->rs) {
+               err = -ENOMEM;
+               goto out_ior;
+       }
+
        cafe->nand.cmdfunc = cafe_nand_cmdfunc;
        cafe->nand.dev_ready = cafe_device_ready;
        cafe->nand.read_byte = cafe_read_byte;
@@ -646,7 +742,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
                cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
 
        /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 1)) {
+       if (nand_scan_ident(mtd, 2)) {
                err = -ENXIO;
                goto out_irq;
        }
@@ -713,6 +809,7 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
        cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
        free_irq(pdev->irq, mtd);
        nand_release(mtd);
+       free_rs(cafe->rs);
        pci_iounmap(pdev, cafe->mmio);
        dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
        kfree(mtd);
index 04de315e4937c0e650025983b4364ad647c69dac..7e68203fe1ba1c46c779d55a5ae2c9151c5659bf 100644 (file)
@@ -303,28 +303,27 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        struct nand_chip *chip = mtd->priv;
        u16 bad;
 
+       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
        if (getchip) {
-               page = (int)(ofs >> chip->page_shift);
                chipnr = (int)(ofs >> chip->chip_shift);
 
                nand_get_device(chip, mtd, FL_READING);
 
                /* Select the NAND device */
                chip->select_chip(mtd, chipnr);
-       } else
-               page = (int)(ofs >> chip->page_shift);
+       }
 
        if (chip->options & NAND_BUSWIDTH_16) {
                chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-                             page & chip->pagemask);
+                             page);
                bad = cpu_to_le16(chip->read_word(mtd));
                if (chip->badblockpos & 0x1)
                        bad >>= 8;
                if ((bad & 0xFF) != 0xff)
                        res = 1;
        } else {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
-                             page & chip->pagemask);
+               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
                if (chip->read_byte(mtd) != 0xff)
                        res = 1;
        }
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
new file mode 100644 (file)
index 0000000..cd725fc
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Generic NAND driver
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+struct plat_nand_data {
+       struct nand_chip        chip;
+       struct mtd_info         mtd;
+       void __iomem            *io_base;
+#ifdef CONFIG_MTD_PARTITIONS
+       int                     nr_parts;
+       struct mtd_partition    *parts;
+#endif
+};
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init plat_nand_probe(struct platform_device *pdev)
+{
+       struct platform_nand_data *pdata = pdev->dev.platform_data;
+       struct plat_nand_data *data;
+       int res = 0;
+
+       /* Allocate memory for the device structure (and zero it) */
+       data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&pdev->dev, "failed to allocate device structure.\n");
+               return -ENOMEM;
+       }
+
+       data->io_base = ioremap(pdev->resource[0].start,
+                               pdev->resource[0].end - pdev->resource[0].start + 1);
+       if (data->io_base == NULL) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               kfree(data);
+               return -EIO;
+       }
+
+       data->chip.priv = &data;
+       data->mtd.priv = &data->chip;
+       data->mtd.owner = THIS_MODULE;
+
+       data->chip.IO_ADDR_R = data->io_base;
+       data->chip.IO_ADDR_W = data->io_base;
+       data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+       data->chip.dev_ready = pdata->ctrl.dev_ready;
+       data->chip.select_chip = pdata->ctrl.select_chip;
+       data->chip.chip_delay = pdata->chip.chip_delay;
+       data->chip.options |= pdata->chip.options;
+
+       data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+       data->chip.ecc.layout = pdata->chip.ecclayout;
+       data->chip.ecc.mode = NAND_ECC_SOFT;
+
+       platform_set_drvdata(pdev, data);
+
+       /* Scan to find existance of the device */
+       if (nand_scan(&data->mtd, 1)) {
+               res = -ENXIO;
+               goto out;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (pdata->chip.part_probe_types) {
+               res = parse_mtd_partitions(&data->mtd,
+                                       pdata->chip.part_probe_types,
+                                       &data->parts, 0);
+               if (res > 0) {
+                       add_mtd_partitions(&data->mtd, data->parts, res);
+                       return 0;
+               }
+       }
+       if (pdata->chip.partitions) {
+               data->parts = pdata->chip.partitions;
+               res = add_mtd_partitions(&data->mtd, data->parts,
+                       pdata->chip.nr_partitions);
+       } else
+#endif
+       res = add_mtd_device(&data->mtd);
+
+       if (!res)
+               return res;
+
+       nand_release(&data->mtd);
+out:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(data->io_base);
+       kfree(data);
+       return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit plat_nand_remove(struct platform_device *pdev)
+{
+       struct plat_nand_data *data = platform_get_drvdata(pdev);
+       struct platform_nand_data *pdata = pdev->dev.platform_data;
+
+       nand_release(&data->mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+       if (data->parts && data->parts != pdata->chip.partitions)
+               kfree(data->parts);
+#endif
+       iounmap(data->io_base);
+       kfree(data);
+
+       return 0;
+}
+
+static struct platform_driver plat_nand_driver = {
+       .probe          = plat_nand_probe,
+       .remove         = plat_nand_remove,
+       .driver         = {
+               .name   = "gen_nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init plat_nand_init(void)
+{
+       return platform_driver_register(&plat_nand_driver);
+}
+
+static void __exit plat_nand_exit(void)
+{
+       platform_driver_unregister(&plat_nand_driver);
+}
+
+module_init(plat_nand_init);
+module_exit(plat_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Simple generic NAND driver");
index 000794c6caf543682e686d23787f238ddf6d141c..0537fac8de74fd703a6c50d9116213626b010f75 100644 (file)
@@ -2192,7 +2192,7 @@ static int onenand_check_maf(int manuf)
  * @param mtd          MTD device structure
  *
  * OneNAND detection method:
- *   Compare the the values from command with ones from register
+ *   Compare the values from command with ones from register
  */
 static int onenand_probe(struct mtd_info *mtd)
 {
index 9588da3a30e7ccd75b32ff8536d864ee964cb4c7..127f60841b10db37878c081896fcab17a57351cd 100644 (file)
@@ -95,8 +95,7 @@ static int max_interrupt_work = 10;
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
-static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
+static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
 
 #if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA))
 #define EL3_SUSPEND
@@ -360,7 +359,7 @@ static int __init el3_common_init(struct net_device *dev)
        printk(", IRQ %d.\n", dev->irq);
 
        if (el3_debug > 0)
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+               printk(KERN_INFO "%s", version);
        return 0;
 
 }
index 80924f76dee8e8673cd11b7ae93628114746f415..f26ca331615e596e01a3e48d1357fa58494dec20 100644 (file)
@@ -103,7 +103,7 @@ static int vortex_debug = 1;
 
 
 static char version[] __devinitdata =
-DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
+DRV_NAME ": Donald Becker and others.\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
index b86ccd2ecd5b49f8f304bdec90a875ee192df67b..fa489b10c38cf8bd8da0a67ac63c5ea927333724 100644 (file)
@@ -2493,12 +2493,28 @@ config PASEMI_MAC
          This driver supports the on-chip 1/10Gbit Ethernet controller on
          PA Semi's PWRficient line of chips.
 
+config MLX4_CORE
+       tristate
+       depends on PCI
+       default n
+
+config MLX4_DEBUG
+       bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED)
+       default y
+       ---help---
+         This option causes debugging code to be compiled into the
+         mlx4_core driver.  The output can be turned on via the
+         debug_level module parameter (which can also be set after
+         the driver is loaded through sysfs).
+
 endmenu
 
 source "drivers/net/tokenring/Kconfig"
 
 source "drivers/net/wireless/Kconfig"
 
+source "drivers/net/usb/Kconfig"
+
 source "drivers/net/pcmcia/Kconfig"
 
 source "drivers/net/wan/Kconfig"
index 59c0459a037c7d4027ac7d1c7415d98ef687694e..a77affa4f6e66d33b707f0aeb71e6efaa23b6a46 100644 (file)
@@ -197,6 +197,7 @@ obj-$(CONFIG_SMC911X) += smc911x.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
+obj-$(CONFIG_MLX4_CORE) += mlx4/
 
 obj-$(CONFIG_MACB) += macb.o
 
@@ -206,6 +207,14 @@ obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
 obj-$(CONFIG_NET_PCMCIA) += pcmcia/
+
+obj-$(CONFIG_USB_CATC)          += usb/
+obj-$(CONFIG_USB_KAWETH)        += usb/
+obj-$(CONFIG_USB_PEGASUS)       += usb/
+obj-$(CONFIG_USB_RTL8150)       += usb/
+obj-$(CONFIG_USB_USBNET)        += usb/
+obj-$(CONFIG_USB_ZD1201)        += usb/
+
 obj-y += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
index d28f88bbdd5fcd43634104f6d228c0ab874ed83e..78cf00ff3d388d9f3eb899b69846de27daa04181 100644 (file)
@@ -2038,6 +2038,15 @@ static int atl1_close(struct net_device *netdev)
        return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void atl1_poll_controller(struct net_device *netdev)
+{
+       disable_irq(netdev->irq);
+       atl1_intr(netdev->irq, netdev);
+       enable_irq(netdev->irq);
+}
+#endif
+
 /*
  * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
  * will assert. We do soft reset <0x1400=1> according
@@ -2190,6 +2199,9 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        netdev->do_ioctl = &atl1_ioctl;
        netdev->tx_timeout = &atl1_tx_timeout;
        netdev->watchdog_timeo = 5 * HZ;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       netdev->poll_controller = atl1_poll_controller;
+#endif
        netdev->vlan_rx_register = atl1_vlan_rx_register;
        netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
        netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
index 18aba838c1ff231dc44c27d80e41647f32d9e86a..82d78ff8399bbeea1046b1efa241e3bf2fd181bd 100644 (file)
 
 */
 
-static const char versionA[] =
+static const char version[] =
 "atp.c:v1.09=ac 2002/10/01 Donald Becker <becker@scyld.com>\n";
-static const char versionB[] =
-"  http://www.scyld.com/network/atp.html\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -324,7 +322,7 @@ static int __init atp_probe1(long ioaddr)
 
 #ifndef MODULE
        if (net_debug)
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+               printk(KERN_INFO "%s", version);
 #endif
 
        printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
@@ -926,7 +924,7 @@ static void set_rx_mode_8012(struct net_device *dev)
 
 static int __init atp_init_module(void) {
        if (debug)                                      /* Emit version even if no cards detected. */
-               printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+               printk(KERN_INFO "%s", version);
        return atp_init();
 }
 
index 724bce51f936b52450764463b7faf1b707487483..223517dcbcfd48ba48c75710d99b3eeb22ceaa46 100644 (file)
@@ -3461,7 +3461,7 @@ void bond_unregister_arp(struct bonding *bond)
 /*---------------------------- Hashing Policies -----------------------------*/
 
 /*
- * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * Hash for the output device based upon layer 3 and layer 4 data. If
  * the packet is a frag or not TCP or UDP, just use layer 3 data.  If it is
  * altogether not IP, mimic bond_xmit_hash_policy_l2()
  */
index 3a03a74c0609b89172941ccb9e6a9586005bbf31..637ae8f6879199444716e0c8025ec56a3eaacdc0 100644 (file)
@@ -1214,7 +1214,7 @@ e1000_remove(struct pci_dev *pdev)
        int i;
 #endif
 
-       flush_scheduled_work();
+       cancel_work_sync(&adapter->reset_task);
 
        e1000_release_manageability(adapter);
 
index 39654e1e2bed09450bb67206729c17761d5b8798..47680237f783f04b05a5c233012b6c48d4d0d491 100644 (file)
@@ -1126,7 +1126,7 @@ static void eepro_tx_timeout (struct net_device *dev)
        printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
                "network cable problem");
        /* This is not a duplicate. One message for the console,
-          one for the the log file  */
+          one for the log file  */
        printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
                "network cable problem");
        eepro_complete_selreset(ioaddr);
index 6c267c38df97a7080b2094ce08b31da4cdaaadc4..9800341956a2e36a1277e9f9830547abdbc737ba 100644 (file)
@@ -28,7 +28,7 @@
 */
 
 static const char * const version =
-"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://www.scyld.com/network/eepro100.html\n"
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n"
 "eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
 
 /* A few user-configurable values that apply to all boards.
index 4e3f14c9c7174d1667bed0393e6289974f9af3b1..5e517946f46a6c1deaee52eb25664467cd233528 100644 (file)
@@ -93,8 +93,6 @@ static int rx_copybreak;
 static char version[] __devinitdata =
 DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
 static char version2[] __devinitdata =
-"  http://www.scyld.com/network/epic100.html\n";
-static char version3[] __devinitdata =
 "  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -323,8 +321,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
 #ifndef MODULE
        static int printed_version;
        if (!printed_version++)
-               printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-                       version, version2, version3);
+               printk (KERN_INFO "%s" KERN_INFO "%s",
+                       version, version2);
 #endif
 
        card_idx++;
@@ -1596,8 +1594,8 @@ static int __init epic_init (void)
 {
 /* when a module, this is printed whether or not devices are found in probe */
 #ifdef MODULE
-       printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
-               version, version2, version3);
+       printk (KERN_INFO "%s" KERN_INFO "%s",
+               version, version2);
 #endif
 
        return pci_register_driver(&epic_driver);
index d0f28981b55a92d08a4eabe9234c7a02b8009f81..7540966687ec24a84cc2064b9cb8b752e7c37947 100644 (file)
@@ -167,7 +167,7 @@ static int allocate_bd(struct net_device *dev)
 
        fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) *
                                         sizeof(cbd_t), 8);
-       if (IS_DPERR(fep->ring_mem_addr))
+       if (IS_ERR_VALUE(fep->ring_mem_addr))
                return -ENOMEM;
 
        fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
index 6e90619b3b41d483cef4e12a51c9e1188cf29395..36d2c7d4f4d089ab3e22ab559ef5a00a336a2e16 100644 (file)
@@ -140,7 +140,7 @@ config BAYCOM_SER_HDX
          modems that connect to a serial interface. The driver supports the
          ser12 design in half-duplex mode. This is the old driver.  It is
          still provided in case your serial interface chip does not work with
-         the full-duplex driver. This driver is depreciated.  To configure
+         the full-duplex driver. This driver is deprecated.  To configure
          the driver, use the sethdlc utility available in the standard ax25
          utilities package. For information on the modems, see
          <http://www.baycom.de/> and
index 7c8ccc09b60126a448a70c1ef4e3f77975a1f434..829da9a1d113e01768dd6ae3973a672bc3fd09ed 100644 (file)
@@ -141,6 +141,20 @@ config ACT200L_DONGLE
          To activate support for ACTiSYS IR-200L dongle you will have to
          start irattach like this: "irattach -d act200l".
 
+config KINGSUN_DONGLE
+       tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
+       depends on IRDA && USB && EXPERIMENTAL
+       help
+         Say Y or M here if you want to build support for the KingSun/DonShine
+         DS-620 IrDA-USB bridge device driver.
+
+         This USB bridge does not conform to the IrDA-USB device class
+         specification, and therefore needs its own specific driver. This
+         dongle supports SIR speed only (9600 bps).
+
+         To compile it as a module, choose M here: the module will be called
+         kingsun-sir.
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
index 5be09f1b9ee2f4b8dc056540342955405b72b215..233a2f9237307835934ecbde083ec2e82e149ad4 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE)  += mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)   += act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)     += ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)  += toim3232-sir.o
+obj-$(CONFIG_KINGSUN_DONGLE)   += kingsun-sir.o
 
 # The SIR helper module
 sir-dev-objs := sir_dev.o sir_dongle.o
index 2ab173d9a0e424001efcd5a0f77640381fde02ef..1e67720f1066f5952bd67225aaa2269c96ca23c0 100644 (file)
 /* RxOver  overflow in Recv FIFO                                */
 /* SipRcv  received serial gap  (or other condition you set)    */
 /* Interrupts are enabled by writing a one to the IER register  */
-/* Interrupts are cleared by writting a one to the ISR register */
+/* Interrupts are cleared by writing a one to the ISR register */
 /*                                                              */
 /* 6. The remaining registers: 0x6 and 0x3 appear to be         */
 /*    reserved parts of 16 or 32 bit registersthe remainder     */
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
new file mode 100644 (file)
index 0000000..2174291
--- /dev/null
@@ -0,0 +1,657 @@
+/*****************************************************************************
+*
+* Filename:      kingsun-sir.c
+* Version:       0.1.1
+* Description:   Irda KingSun/DonShine USB Dongle
+* Status:        Experimental
+* Author:        Alex Villac�s Lasso <a_villacis@palosanto.com>
+*
+*      Based on stir4200 and mcs7780 drivers, with (strange?) differences
+*
+*      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.
+*
+*      This program is distributed in the hope that it will be useful,
+*      but WITHOUT ANY WARRANTY; without even the implied warranty of
+*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*      GNU General Public License for more details.
+*
+*      You should have received a copy of the GNU General Public License
+*      along with this program; if not, write to the Free Software
+*      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * This is my current (2007-04-25) understanding of how this dongle is supposed
+ * to work. This is based on reverse-engineering and examination of the packet
+ * data sent and received by the WinXP driver using USBSnoopy. Feel free to
+ * update here as more of this dongle is known:
+ *
+ * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
+ * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
+ * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
+ * order to receive data.
+ * Transmission: Just like stir4200, this dongle uses a raw stream of data,
+ * which needs to be wrapped and escaped in a similar way as in stir4200.c.
+ * Reception: Poll-based, as in stir4200. Each read returns the contents of a
+ * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
+ * (1-7) of valid data contained within the remaining 7 bytes. For example, if
+ * the buffer had the following contents:
+ *  06 ff ff ff c0 01 04 aa
+ * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
+ * end is garbage (left over from a previous reception) and is discarded.
+ * If a read returns an "impossible" value as the length of valid data (such as
+ * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
+ * first plug-in) and its contents should be discarded. There is currently no
+ * evidence that the top 5 bits of the 1st byte of the buffer can have values
+ * other than 0 once reception begins.
+ * Once valid bytes are collected, the assembled stream is a sequence of
+ * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
+ * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
+ * a successful read from the host, which means that in absence of further
+ * reception, repeated reads from the dongle will return the exact same
+ * contents repeatedly. Attempts to be smart and cache a previous read seem
+ * to result in corrupted packets, so this driver depends on the unwrap logic
+ * to sort out any repeated reads.
+ * Speed change: no commands observed so far to change speed, assumed fixed
+ * 9600bps (SIR).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+/*
+ * According to lsusb, 0x07c0 is assigned to
+ * "Code Mercenaries Hard- und Software GmbH"
+ */
+#define KING_VENDOR_ID 0x07c0
+#define KING_PRODUCT_ID 0x4200
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+    /* KingSun Co,Ltd  IrDA/USB Bridge */
+    { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
+    { }
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+
+#define KINGSUN_FIFO_SIZE              4096
+#define KINGSUN_EP_IN                  0
+#define KINGSUN_EP_OUT                 1
+
+struct kingsun_cb {
+       struct usb_device *usbdev;      /* init: probe_irda */
+       struct net_device *netdev;      /* network layer */
+       struct irlap_cb   *irlap;       /* The link layer we are binded to */
+       struct net_device_stats stats;  /* network statistics */
+       struct qos_info   qos;
+
+       __u8              *in_buf;      /* receive buffer */
+       __u8              *out_buf;     /* transmit buffer */
+       __u8              max_rx;       /* max. atomic read from dongle
+                                          (usually 8), also size of in_buf */
+       __u8              max_tx;       /* max. atomic write to dongle
+                                          (usually 8) */
+
+       iobuff_t          rx_buff;      /* receive unwrap state machine */
+       struct timeval    rx_time;
+       spinlock_t lock;
+       int receiving;
+
+       __u8 ep_in;
+       __u8 ep_out;
+
+       struct urb       *tx_urb;
+       struct urb       *rx_urb;
+};
+
+/* Callback transmission routine */
+static void kingsun_send_irq(struct urb *urb)
+{
+       struct kingsun_cb *kingsun = urb->context;
+       struct net_device *netdev = kingsun->netdev;
+
+       /* in process of stopping, just drop data */
+       if (!netif_running(kingsun->netdev)) {
+               err("kingsun_send_irq: Network not running!");
+               return;
+       }
+
+       /* unlink, shutdown, unplug, other nasties */
+       if (urb->status != 0) {
+               err("kingsun_send_irq: urb asynchronously failed - %d",
+                   urb->status);
+       }
+       netif_wake_queue(netdev);
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun;
+       int wraplen;
+       int ret = 0;
+
+       if (skb == NULL || netdev == NULL)
+               return -EINVAL;
+
+       netif_stop_queue(netdev);
+
+       /* the IRDA wrapping routines don't deal with non linear skb */
+       SKB_LINEAR_ASSERT(skb);
+
+       kingsun = netdev_priv(netdev);
+
+       spin_lock(&kingsun->lock);
+
+       /* Append data to the end of whatever data remains to be transmitted */
+       wraplen = async_wrap_skb(skb,
+               kingsun->out_buf,
+               KINGSUN_FIFO_SIZE);
+
+       /* Calculate how much data can be transmitted in this urb */
+       usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+               usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+               kingsun->out_buf, wraplen, kingsun_send_irq,
+               kingsun, 1);
+
+       if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
+               err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+               switch (ret) {
+               case -ENODEV:
+               case -EPIPE:
+                       break;
+               default:
+                       kingsun->stats.tx_errors++;
+                       netif_start_queue(netdev);
+               }
+       } else {
+               kingsun->stats.tx_packets++;
+               kingsun->stats.tx_bytes += skb->len;
+       }
+
+       dev_kfree_skb(skb);
+       spin_unlock(&kingsun->lock);
+
+       return ret;
+}
+
+/* Receive callback function */
+static void kingsun_rcv_irq(struct urb *urb)
+{
+       struct kingsun_cb *kingsun = urb->context;
+       int ret;
+
+       /* in process of stopping, just drop data */
+       if (!netif_running(kingsun->netdev)) {
+               kingsun->receiving = 0;
+               return;
+       }
+
+       /* unlink, shutdown, unplug, other nasties */
+       if (urb->status != 0) {
+               err("kingsun_rcv_irq: urb asynchronously failed - %d",
+                   urb->status);
+               kingsun->receiving = 0;
+               return;
+       }
+
+       if (urb->actual_length == kingsun->max_rx) {
+               __u8 *bytes = urb->transfer_buffer;
+               int i;
+
+               /* The very first byte in the buffer indicates the length of
+                  valid data in the read. This byte must be in the range
+                  1..kingsun->max_rx -1 . Values outside this range indicate
+                  an uninitialized Rx buffer when the dongle has just been
+                  plugged in. */
+               if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
+                       for (i = 1; i <= bytes[0]; i++) {
+                               async_unwrap_char(kingsun->netdev,
+                                                 &kingsun->stats,
+                                                 &kingsun->rx_buff, bytes[i]);
+                       }
+                       kingsun->netdev->last_rx = jiffies;
+                       do_gettimeofday(&kingsun->rx_time);
+                       kingsun->receiving =
+                               (kingsun->rx_buff.state != OUTSIDE_FRAME)
+                               ? 1 : 0;
+               }
+       } else if (urb->actual_length > 0) {
+               err("%s(): Unexpected response length, expected %d got %d",
+                   __FUNCTION__, kingsun->max_rx, urb->actual_length);
+       }
+       /* This urb has already been filled in kingsun_net_open */
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int kingsun_net_open(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       int err = -ENOMEM;
+       char hwname[16];
+
+       /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+       kingsun->receiving = 0;
+
+       /* Initialize for SIR to copy data directly into skb.  */
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+       kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+       if (!kingsun->rx_buff.skb)
+               goto free_mem;
+
+       skb_reserve(kingsun->rx_buff.skb, 1);
+       kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
+       do_gettimeofday(&kingsun->rx_time);
+
+       kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kingsun->rx_urb)
+               goto free_mem;
+
+       kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kingsun->tx_urb)
+               goto free_mem;
+
+       /*
+        * Now that everything should be initialized properly,
+        * Open new IrLAP layer instance to take care of us...
+        */
+       sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+       kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+       if (!kingsun->irlap) {
+               err("kingsun-sir: irlap_open failed");
+               goto free_mem;
+       }
+
+       /* Start first reception */
+       usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+                         usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+                         kingsun->in_buf, kingsun->max_rx,
+                         kingsun_rcv_irq, kingsun, 1);
+       kingsun->rx_urb->status = 0;
+       err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+       if (err) {
+               err("kingsun-sir: first urb-submit failed: %d", err);
+               goto close_irlap;
+       }
+
+       netif_start_queue(netdev);
+
+       /* Situation at this point:
+          - all work buffers allocated
+          - urbs allocated and ready to fill
+          - max rx packet known (in max_rx)
+          - unwrap state machine initialized, in state outside of any frame
+          - receive request in progress
+          - IrLAP layer started, about to hand over packets to send
+        */
+
+       return 0;
+
+ close_irlap:
+       irlap_close(kingsun->irlap);
+ free_mem:
+       if (kingsun->tx_urb) {
+               usb_free_urb(kingsun->tx_urb);
+               kingsun->tx_urb = NULL;
+       }
+       if (kingsun->rx_urb) {
+               usb_free_urb(kingsun->rx_urb);
+               kingsun->rx_urb = NULL;
+       }
+       if (kingsun->rx_buff.skb) {
+               kfree_skb(kingsun->rx_buff.skb);
+               kingsun->rx_buff.skb = NULL;
+               kingsun->rx_buff.head = NULL;
+       }
+       return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ *    Network device is taken down. Usually this is done by
+ *    "ifconfig irda0 down"
+ */
+static int kingsun_net_close(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+
+       /* Stop transmit processing */
+       netif_stop_queue(netdev);
+
+       /* Mop up receive && transmit urb's */
+       usb_kill_urb(kingsun->tx_urb);
+       usb_kill_urb(kingsun->rx_urb);
+
+       usb_free_urb(kingsun->tx_urb);
+       usb_free_urb(kingsun->rx_urb);
+
+       kingsun->tx_urb = NULL;
+       kingsun->rx_urb = NULL;
+
+       kfree_skb(kingsun->rx_buff.skb);
+       kingsun->rx_buff.skb = NULL;
+       kingsun->rx_buff.head = NULL;
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->receiving = 0;
+
+       /* Stop and remove instance of IrLAP */
+       if (kingsun->irlap)
+               irlap_close(kingsun->irlap);
+
+       kingsun->irlap = NULL;
+
+       return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+                            int cmd)
+{
+       struct if_irda_req *irq = (struct if_irda_req *) rq;
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       int ret = 0;
+
+       switch (cmd) {
+       case SIOCSBANDWIDTH: /* Set bandwidth */
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               /* Check if the device is still there */
+               if (netif_device_present(kingsun->netdev))
+                       /* No observed commands for speed change */
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case SIOCSMEDIABUSY: /* Set media busy */
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               /* Check if the IrDA stack is still there */
+               if (netif_running(kingsun->netdev))
+                       irda_device_set_media_busy(kingsun->netdev, TRUE);
+               break;
+
+       case SIOCGRECEIVING:
+               /* Only approximately true */
+               irq->ifr_receiving = kingsun->receiving;
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *
+kingsun_net_get_stats(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int kingsun_probe(struct usb_interface *intf,
+                     const struct usb_device_id *id)
+{
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct kingsun_cb *kingsun = NULL;
+       struct net_device *net = NULL;
+       int ret = -ENOMEM;
+       int pipe, maxp_in, maxp_out;
+       __u8 ep_in;
+       __u8 ep_out;
+
+       /* Check that there really are two interrupt endpoints.
+          Check based on the one in drivers/usb/input/usbmouse.c
+        */
+       interface = intf->cur_altsetting;
+       if (interface->desc.bNumEndpoints != 2) {
+               err("kingsun-sir: expected 2 endpoints, found %d",
+                   interface->desc.bNumEndpoints);
+               return -ENODEV;
+       }
+       endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+       if (!usb_endpoint_is_int_in(endpoint)) {
+               err("kingsun-sir: endpoint 0 is not interrupt IN");
+               return -ENODEV;
+       }
+
+       ep_in = endpoint->bEndpointAddress;
+       pipe = usb_rcvintpipe(dev, ep_in);
+       maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+       if (maxp_in > 255 || maxp_in <= 1) {
+               err("%s: endpoint 0 has max packet size %d not in range",
+                   __FILE__, maxp_in);
+               return -ENODEV;
+       }
+
+       endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+       if (!usb_endpoint_is_int_out(endpoint)) {
+               err("kingsun-sir: endpoint 1 is not interrupt OUT");
+               return -ENODEV;
+       }
+
+       ep_out = endpoint->bEndpointAddress;
+       pipe = usb_sndintpipe(dev, ep_out);
+       maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       /* Allocate network device container. */
+       net = alloc_irdadev(sizeof(*kingsun));
+       if(!net)
+               goto err_out1;
+
+       SET_MODULE_OWNER(net);
+       SET_NETDEV_DEV(net, &intf->dev);
+       kingsun = netdev_priv(net);
+       kingsun->irlap = NULL;
+       kingsun->tx_urb = NULL;
+       kingsun->rx_urb = NULL;
+       kingsun->ep_in = ep_in;
+       kingsun->ep_out = ep_out;
+       kingsun->in_buf = NULL;
+       kingsun->out_buf = NULL;
+       kingsun->max_rx = (__u8)maxp_in;
+       kingsun->max_tx = (__u8)maxp_out;
+       kingsun->netdev = net;
+       kingsun->usbdev = dev;
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->rx_buff.skb = NULL;
+       kingsun->receiving = 0;
+       spin_lock_init(&kingsun->lock);
+
+       /* Allocate input buffer */
+       kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+       if (!kingsun->in_buf)
+               goto free_mem;
+
+       /* Allocate output buffer */
+       kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+       if (!kingsun->out_buf)
+               goto free_mem;
+
+       printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
+               "Vendor: %x, Product: %x\n",
+              dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+              le16_to_cpu(dev->descriptor.idProduct));
+
+       /* Initialize QoS for this device */
+       irda_init_max_qos_capabilies(&kingsun->qos);
+
+       /* That's the Rx capability. */
+       kingsun->qos.baud_rate.bits       &= IR_9600;
+       kingsun->qos.min_turn_time.bits   &= KINGSUN_MTT;
+       irda_qos_bits_to_value(&kingsun->qos);
+
+       /* Override the network functions we need to use */
+       net->hard_start_xmit = kingsun_hard_xmit;
+       net->open            = kingsun_net_open;
+       net->stop            = kingsun_net_close;
+       net->get_stats       = kingsun_net_get_stats;
+       net->do_ioctl        = kingsun_net_ioctl;
+
+       ret = register_netdev(net);
+       if (ret != 0)
+               goto free_mem;
+
+       info("IrDA: Registered KingSun/DonShine device %s", net->name);
+
+       usb_set_intfdata(intf, kingsun);
+
+       /* Situation at this point:
+          - all work buffers allocated
+          - urbs not allocated, set to NULL
+          - max rx packet known (in max_rx)
+          - unwrap state machine (partially) initialized, but skb == NULL
+        */
+
+       return 0;
+
+free_mem:
+       if (kingsun->out_buf) kfree(kingsun->out_buf);
+       if (kingsun->in_buf) kfree(kingsun->in_buf);
+       free_netdev(net);
+err_out1:
+       return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void kingsun_disconnect(struct usb_interface *intf)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       if (!kingsun)
+               return;
+
+       unregister_netdev(kingsun->netdev);
+
+       /* Mop up receive && transmit urb's */
+       if (kingsun->tx_urb != NULL) {
+               usb_kill_urb(kingsun->tx_urb);
+               usb_free_urb(kingsun->tx_urb);
+               kingsun->tx_urb = NULL;
+       }
+       if (kingsun->rx_urb != NULL) {
+               usb_kill_urb(kingsun->rx_urb);
+               usb_free_urb(kingsun->rx_urb);
+               kingsun->rx_urb = NULL;
+       }
+
+       kfree(kingsun->out_buf);
+       kfree(kingsun->in_buf);
+       free_netdev(kingsun->netdev);
+
+       usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       netif_device_detach(kingsun->netdev);
+       if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
+       if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
+       return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int kingsun_resume(struct usb_interface *intf)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       if (kingsun->rx_urb != NULL)
+               usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+       netif_device_attach(kingsun->netdev);
+
+       return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+       .name           = "kingsun-sir",
+       .probe          = kingsun_probe,
+       .disconnect     = kingsun_disconnect,
+       .id_table       = dongles,
+#ifdef CONFIG_PM
+       .suspend        = kingsun_suspend,
+       .resume         = kingsun_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init kingsun_init(void)
+{
+       return usb_register(&irda_driver);
+}
+module_init(kingsun_init);
+
+/*
+ * Module removal
+ */
+static void __exit kingsun_cleanup(void)
+{
+       /* Deregister the driver and remove all pending instances */
+       usb_deregister(&irda_driver);
+}
+module_exit(kingsun_cleanup);
+
+MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
+MODULE_LICENSE("GPL");
index f15aebde7b9026bea724f90785e08847889c84f0..52c99d01d5681f33c9c51242e887c52240debe5b 100644 (file)
@@ -315,7 +315,7 @@ ixgb_wait_eeprom_command(struct ixgb_hw *hw)
  * hw - Struct containing variables accessed by shared code
  *
  * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * If the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
  * valid.
  *
  * Returns:
index 84960dae2a2235a07ad82dec7fb534f62377b385..ea3b8fc86d1ef239cef9b6557f1468ad0cdf4a95 100644 (file)
@@ -126,7 +126,7 @@ typedef struct rx_packet {
                                       /*   Note: when loopback is set this bit becomes collision control.  Setting this bit will */
                                       /*         cause a collision to be reported. */
 
-                                      /* Bits 5 and 6 are used to determine the the Destination address filter mode */
+                                      /* Bits 5 and 6 are used to determine the Destination address filter mode */
 #define METH_ACCEPT_MY 0                       /* 00: Accept PHY address only */
 #define METH_ACCEPT_MCAST 0x20 /* 01: Accept physical, broadcast, and multicast filter matches only */
 #define METH_ACCEPT_AMCAST 0x40        /* 10: Accept physical, broadcast, and all multicast packets */
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
new file mode 100644 (file)
index 0000000..0952a65
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_MLX4_CORE)                += mlx4_core.o
+
+mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
+               mr.o pd.o profile.o qp.o reset.o srq.o
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
new file mode 100644 (file)
index 0000000..9ffdb9d
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/bitmap.h>
+
+#include "mlx4.h"
+
+u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
+{
+       u32 obj;
+
+       spin_lock(&bitmap->lock);
+
+       obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last);
+       if (obj >= bitmap->max) {
+               bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+               obj = find_first_zero_bit(bitmap->table, bitmap->max);
+       }
+
+       if (obj < bitmap->max) {
+               set_bit(obj, bitmap->table);
+               obj |= bitmap->top;
+               bitmap->last = obj + 1;
+       } else
+               obj = -1;
+
+       spin_unlock(&bitmap->lock);
+
+       return obj;
+}
+
+void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj)
+{
+       obj &= bitmap->max - 1;
+
+       spin_lock(&bitmap->lock);
+       clear_bit(obj, bitmap->table);
+       bitmap->last = min(bitmap->last, obj);
+       bitmap->top = (bitmap->top + bitmap->max) & bitmap->mask;
+       spin_unlock(&bitmap->lock);
+}
+
+int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved)
+{
+       int i;
+
+       /* num must be a power of 2 */
+       if (num != roundup_pow_of_two(num))
+               return -EINVAL;
+
+       bitmap->last = 0;
+       bitmap->top  = 0;
+       bitmap->max  = num;
+       bitmap->mask = mask;
+       spin_lock_init(&bitmap->lock);
+       bitmap->table = kzalloc(BITS_TO_LONGS(num) * sizeof (long), GFP_KERNEL);
+       if (!bitmap->table)
+               return -ENOMEM;
+
+       for (i = 0; i < reserved; ++i)
+               set_bit(i, bitmap->table);
+
+       return 0;
+}
+
+void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap)
+{
+       kfree(bitmap->table);
+}
+
+/*
+ * Handling for queue buffers -- we allocate a bunch of memory and
+ * register it in a memory region at HCA virtual address 0.  If the
+ * requested size is > max_direct, we split the allocation into
+ * multiple pages, so we don't require too much contiguous memory.
+ */
+
+int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
+                  struct mlx4_buf *buf)
+{
+       dma_addr_t t;
+
+       if (size <= max_direct) {
+               buf->nbufs        = 1;
+               buf->npages       = 1;
+               buf->page_shift   = get_order(size) + PAGE_SHIFT;
+               buf->u.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+                                                      size, &t, GFP_KERNEL);
+               if (!buf->u.direct.buf)
+                       return -ENOMEM;
+
+               buf->u.direct.map = t;
+
+               while (t & ((1 << buf->page_shift) - 1)) {
+                       --buf->page_shift;
+                       buf->npages *= 2;
+               }
+
+               memset(buf->u.direct.buf, 0, size);
+       } else {
+               int i;
+
+               buf->nbufs       = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+               buf->npages      = buf->nbufs;
+               buf->page_shift  = PAGE_SHIFT;
+               buf->u.page_list = kzalloc(buf->nbufs * sizeof *buf->u.page_list,
+                                          GFP_KERNEL);
+               if (!buf->u.page_list)
+                       return -ENOMEM;
+
+               for (i = 0; i < buf->nbufs; ++i) {
+                       buf->u.page_list[i].buf =
+                               dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                                  &t, GFP_KERNEL);
+                       if (!buf->u.page_list[i].buf)
+                               goto err_free;
+
+                       buf->u.page_list[i].map = t;
+
+                       memset(buf->u.page_list[i].buf, 0, PAGE_SIZE);
+               }
+       }
+
+       return 0;
+
+err_free:
+       mlx4_buf_free(dev, size, buf);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(mlx4_buf_alloc);
+
+void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
+{
+       int i;
+
+       if (buf->nbufs == 1)
+               dma_free_coherent(&dev->pdev->dev, size, buf->u.direct.buf,
+                                 buf->u.direct.map);
+       else {
+               for (i = 0; i < buf->nbufs; ++i)
+                       dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                         buf->u.page_list[i].buf,
+                                         buf->u.page_list[i].map);
+               kfree(buf->u.page_list);
+       }
+}
+EXPORT_SYMBOL_GPL(mlx4_buf_free);
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
new file mode 100644 (file)
index 0000000..1bb088a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "mlx4.h"
+
+void mlx4_handle_catas_err(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       int i;
+
+       mlx4_err(dev, "Catastrophic error detected:\n");
+       for (i = 0; i < priv->fw.catas_size; ++i)
+               mlx4_err(dev, "  buf[%02x]: %08x\n",
+                        i, swab32(readl(priv->catas_err.map + i)));
+
+       mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+}
+
+void mlx4_map_catas_buf(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       unsigned long addr;
+
+       addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
+               priv->fw.catas_offset;
+
+       priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
+       if (!priv->catas_err.map)
+               mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+                         addr);
+
+}
+
+void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (priv->catas_err.map)
+               iounmap(priv->catas_err.map);
+}
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
new file mode 100644 (file)
index 0000000..c1f81a9
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include <asm/io.h>
+
+#include "mlx4.h"
+
+#define CMD_POLL_TOKEN 0xffff
+
+enum {
+       /* command completed successfully: */
+       CMD_STAT_OK             = 0x00,
+       /* Internal error (such as a bus error) occurred while processing command: */
+       CMD_STAT_INTERNAL_ERR   = 0x01,
+       /* Operation/command not supported or opcode modifier not supported: */
+       CMD_STAT_BAD_OP         = 0x02,
+       /* Parameter not supported or parameter out of range: */
+       CMD_STAT_BAD_PARAM      = 0x03,
+       /* System not enabled or bad system state: */
+       CMD_STAT_BAD_SYS_STATE  = 0x04,
+       /* Attempt to access reserved or unallocaterd resource: */
+       CMD_STAT_BAD_RESOURCE   = 0x05,
+       /* Requested resource is currently executing a command, or is otherwise busy: */
+       CMD_STAT_RESOURCE_BUSY  = 0x06,
+       /* Required capability exceeds device limits: */
+       CMD_STAT_EXCEED_LIM     = 0x08,
+       /* Resource is not in the appropriate state or ownership: */
+       CMD_STAT_BAD_RES_STATE  = 0x09,
+       /* Index out of range: */
+       CMD_STAT_BAD_INDEX      = 0x0a,
+       /* FW image corrupted: */
+       CMD_STAT_BAD_NVMEM      = 0x0b,
+       /* Attempt to modify a QP/EE which is not in the presumed state: */
+       CMD_STAT_BAD_QP_STATE   = 0x10,
+       /* Bad segment parameters (Address/Size): */
+       CMD_STAT_BAD_SEG_PARAM  = 0x20,
+       /* Memory Region has Memory Windows bound to: */
+       CMD_STAT_REG_BOUND      = 0x21,
+       /* HCA local attached memory not present: */
+       CMD_STAT_LAM_NOT_PRE    = 0x22,
+       /* Bad management packet (silently discarded): */
+       CMD_STAT_BAD_PKT        = 0x30,
+       /* More outstanding CQEs in CQ than new CQ size: */
+       CMD_STAT_BAD_SIZE       = 0x40
+};
+
+enum {
+       HCR_IN_PARAM_OFFSET     = 0x00,
+       HCR_IN_MODIFIER_OFFSET  = 0x08,
+       HCR_OUT_PARAM_OFFSET    = 0x0c,
+       HCR_TOKEN_OFFSET        = 0x14,
+       HCR_STATUS_OFFSET       = 0x18,
+
+       HCR_OPMOD_SHIFT         = 12,
+       HCR_T_BIT               = 21,
+       HCR_E_BIT               = 22,
+       HCR_GO_BIT              = 23
+};
+
+enum {
+       GO_BIT_TIMEOUT          = 10000
+};
+
+struct mlx4_cmd_context {
+       struct completion       done;
+       int                     result;
+       int                     next;
+       u64                     out_param;
+       u16                     token;
+};
+
+static int mlx4_status_to_errno(u8 status) {
+       static const int trans_table[] = {
+               [CMD_STAT_INTERNAL_ERR]   = -EIO,
+               [CMD_STAT_BAD_OP]         = -EPERM,
+               [CMD_STAT_BAD_PARAM]      = -EINVAL,
+               [CMD_STAT_BAD_SYS_STATE]  = -ENXIO,
+               [CMD_STAT_BAD_RESOURCE]   = -EBADF,
+               [CMD_STAT_RESOURCE_BUSY]  = -EBUSY,
+               [CMD_STAT_EXCEED_LIM]     = -ENOMEM,
+               [CMD_STAT_BAD_RES_STATE]  = -EBADF,
+               [CMD_STAT_BAD_INDEX]      = -EBADF,
+               [CMD_STAT_BAD_NVMEM]      = -EFAULT,
+               [CMD_STAT_BAD_QP_STATE]   = -EINVAL,
+               [CMD_STAT_BAD_SEG_PARAM]  = -EFAULT,
+               [CMD_STAT_REG_BOUND]      = -EBUSY,
+               [CMD_STAT_LAM_NOT_PRE]    = -EAGAIN,
+               [CMD_STAT_BAD_PKT]        = -EINVAL,
+               [CMD_STAT_BAD_SIZE]       = -ENOMEM,
+       };
+
+       if (status >= ARRAY_SIZE(trans_table) ||
+           (status != CMD_STAT_OK && trans_table[status] == 0))
+               return -EIO;
+
+       return trans_table[status];
+}
+
+static int cmd_pending(struct mlx4_dev *dev)
+{
+       u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
+
+       return (status & swab32(1 << HCR_GO_BIT)) ||
+               (mlx4_priv(dev)->cmd.toggle ==
+                !!(status & swab32(1 << HCR_T_BIT)));
+}
+
+static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
+                        u32 in_modifier, u8 op_modifier, u16 op, u16 token,
+                        int event)
+{
+       struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
+       u32 __iomem *hcr = cmd->hcr;
+       int ret = -EAGAIN;
+       unsigned long end;
+
+       mutex_lock(&cmd->hcr_mutex);
+
+       end = jiffies;
+       if (event)
+               end += HZ * 10;
+
+       while (cmd_pending(dev)) {
+               if (time_after_eq(jiffies, end))
+                       goto out;
+               cond_resched();
+       }
+
+       /*
+        * We use writel (instead of something like memcpy_toio)
+        * because writes of less than 32 bits to the HCR don't work
+        * (and some architectures such as ia64 implement memcpy_toio
+        * in terms of writeb).
+        */
+       __raw_writel((__force u32) cpu_to_be32(in_param >> 32),           hcr + 0);
+       __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful),  hcr + 1);
+       __raw_writel((__force u32) cpu_to_be32(in_modifier),              hcr + 2);
+       __raw_writel((__force u32) cpu_to_be32(out_param >> 32),          hcr + 3);
+       __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4);
+       __raw_writel((__force u32) cpu_to_be32(token << 16),              hcr + 5);
+
+       /* __raw_writel may not order writes. */
+       wmb();
+
+       __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT)                |
+                                              (cmd->toggle << HCR_T_BIT)       |
+                                              (event ? (1 << HCR_E_BIT) : 0)   |
+                                              (op_modifier << HCR_OPMOD_SHIFT) |
+                                              op),                       hcr + 6);
+       cmd->toggle = cmd->toggle ^ 1;
+
+       ret = 0;
+
+out:
+       mutex_unlock(&cmd->hcr_mutex);
+       return ret;
+}
+
+static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
+                        int out_is_imm, u32 in_modifier, u8 op_modifier,
+                        u16 op, unsigned long timeout)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       void __iomem *hcr = priv->cmd.hcr;
+       int err = 0;
+       unsigned long end;
+
+       down(&priv->cmd.poll_sem);
+
+       err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
+                           in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
+       if (err)
+               goto out;
+
+       end = msecs_to_jiffies(timeout) + jiffies;
+       while (cmd_pending(dev) && time_before(jiffies, end))
+               cond_resched();
+
+       if (cmd_pending(dev)) {
+               err = -ETIMEDOUT;
+               goto out;
+       }
+
+       if (out_is_imm)
+               *out_param =
+                       (u64) be32_to_cpu((__force __be32)
+                                         __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 |
+                       (u64) be32_to_cpu((__force __be32)
+                                         __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4));
+
+       err = mlx4_status_to_errno(be32_to_cpu((__force __be32)
+                                              __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24);
+
+out:
+       up(&priv->cmd.poll_sem);
+       return err;
+}
+
+void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cmd_context *context =
+               &priv->cmd.context[token & priv->cmd.token_mask];
+
+       /* previously timed out command completing at long last */
+       if (token != context->token)
+               return;
+
+       context->result    = mlx4_status_to_errno(status);
+       context->out_param = out_param;
+
+       context->token += priv->cmd.token_mask + 1;
+
+       complete(&context->done);
+}
+
+static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
+                        int out_is_imm, u32 in_modifier, u8 op_modifier,
+                        u16 op, unsigned long timeout)
+{
+       struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
+       struct mlx4_cmd_context *context;
+       int err = 0;
+
+       down(&cmd->event_sem);
+
+       spin_lock(&cmd->context_lock);
+       BUG_ON(cmd->free_head < 0);
+       context = &cmd->context[cmd->free_head];
+       cmd->free_head = context->next;
+       spin_unlock(&cmd->context_lock);
+
+       init_completion(&context->done);
+
+       mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
+                     in_modifier, op_modifier, op, context->token, 1);
+
+       if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       err = context->result;
+       if (err)
+               goto out;
+
+       if (out_is_imm)
+               *out_param = context->out_param;
+
+out:
+       spin_lock(&cmd->context_lock);
+       context->next = cmd->free_head;
+       cmd->free_head = context - cmd->context;
+       spin_unlock(&cmd->context_lock);
+
+       up(&cmd->event_sem);
+       return err;
+}
+
+int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
+              int out_is_imm, u32 in_modifier, u8 op_modifier,
+              u16 op, unsigned long timeout)
+{
+       if (mlx4_priv(dev)->cmd.use_events)
+               return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm,
+                                    in_modifier, op_modifier, op, timeout);
+       else
+               return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm,
+                                    in_modifier, op_modifier, op, timeout);
+}
+EXPORT_SYMBOL_GPL(__mlx4_cmd);
+
+int mlx4_cmd_init(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       mutex_init(&priv->cmd.hcr_mutex);
+       sema_init(&priv->cmd.poll_sem, 1);
+       priv->cmd.use_events = 0;
+       priv->cmd.toggle     = 1;
+
+       priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE,
+                               MLX4_HCR_SIZE);
+       if (!priv->cmd.hcr) {
+               mlx4_err(dev, "Couldn't map command register.");
+               return -ENOMEM;
+       }
+
+       priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
+                                        MLX4_MAILBOX_SIZE,
+                                        MLX4_MAILBOX_SIZE, 0);
+       if (!priv->cmd.pool) {
+               iounmap(priv->cmd.hcr);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void mlx4_cmd_cleanup(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       pci_pool_destroy(priv->cmd.pool);
+       iounmap(priv->cmd.hcr);
+}
+
+/*
+ * Switch to using events to issue FW commands (can only be called
+ * after event queue for command events has been initialized).
+ */
+int mlx4_cmd_use_events(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i;
+
+       priv->cmd.context = kmalloc(priv->cmd.max_cmds *
+                                  sizeof (struct mlx4_cmd_context),
+                                  GFP_KERNEL);
+       if (!priv->cmd.context)
+               return -ENOMEM;
+
+       for (i = 0; i < priv->cmd.max_cmds; ++i) {
+               priv->cmd.context[i].token = i;
+               priv->cmd.context[i].next  = i + 1;
+       }
+
+       priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
+       priv->cmd.free_head = 0;
+
+       sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds);
+       spin_lock_init(&priv->cmd.context_lock);
+
+       for (priv->cmd.token_mask = 1;
+            priv->cmd.token_mask < priv->cmd.max_cmds;
+            priv->cmd.token_mask <<= 1)
+               ; /* nothing */
+       --priv->cmd.token_mask;
+
+       priv->cmd.use_events = 1;
+
+       down(&priv->cmd.poll_sem);
+
+       return 0;
+}
+
+/*
+ * Switch back to polling (used when shutting down the device)
+ */
+void mlx4_cmd_use_polling(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i;
+
+       priv->cmd.use_events = 0;
+
+       for (i = 0; i < priv->cmd.max_cmds; ++i)
+               down(&priv->cmd.event_sem);
+
+       kfree(priv->cmd.context);
+
+       up(&priv->cmd.poll_sem);
+}
+
+struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+
+       mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL);
+       if (!mailbox)
+               return ERR_PTR(-ENOMEM);
+
+       mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL,
+                                     &mailbox->dma);
+       if (!mailbox->buf) {
+               kfree(mailbox);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return mailbox;
+}
+EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox);
+
+void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox)
+{
+       if (!mailbox)
+               return;
+
+       pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma);
+       kfree(mailbox);
+}
+EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox);
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
new file mode 100644 (file)
index 0000000..437d78a
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/hardirq.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+#include "icm.h"
+
+struct mlx4_cq_context {
+       __be32                  flags;
+       u16                     reserved1[3];
+       __be16                  page_offset;
+       __be32                  logsize_usrpage;
+       u8                      reserved2;
+       u8                      cq_period;
+       u8                      reserved3;
+       u8                      cq_max_count;
+       u8                      reserved4[3];
+       u8                      comp_eqn;
+       u8                      log_page_size;
+       u8                      reserved5[2];
+       u8                      mtt_base_addr_h;
+       __be32                  mtt_base_addr_l;
+       __be32                  last_notified_index;
+       __be32                  solicit_producer_index;
+       __be32                  consumer_index;
+       __be32                  producer_index;
+       u8                      reserved6[2];
+       __be64                  db_rec_addr;
+};
+
+#define MLX4_CQ_STATUS_OK              ( 0 << 28)
+#define MLX4_CQ_STATUS_OVERFLOW                ( 9 << 28)
+#define MLX4_CQ_STATUS_WRITE_FAIL      (10 << 28)
+#define MLX4_CQ_FLAG_CC                        ( 1 << 18)
+#define MLX4_CQ_FLAG_OI                        ( 1 << 17)
+#define MLX4_CQ_STATE_ARMED            ( 9 <<  8)
+#define MLX4_CQ_STATE_ARMED_SOL                ( 6 <<  8)
+#define MLX4_EQ_STATE_FIRED            (10 <<  8)
+
+void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn)
+{
+       struct mlx4_cq *cq;
+
+       cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
+                              cqn & (dev->caps.num_cqs - 1));
+       if (!cq) {
+               mlx4_warn(dev, "Completion event for bogus CQ %08x\n", cqn);
+               return;
+       }
+
+       ++cq->arm_sn;
+
+       cq->comp(cq);
+}
+
+void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type)
+{
+       struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
+       struct mlx4_cq *cq;
+
+       spin_lock(&cq_table->lock);
+
+       cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
+       if (cq)
+               atomic_inc(&cq->refcount);
+
+       spin_unlock(&cq_table->lock);
+
+       if (!cq) {
+               mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+               return;
+       }
+
+       cq->event(cq, event_type);
+
+       if (atomic_dec_and_test(&cq->refcount))
+               complete(&cq->free);
+}
+
+static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                        int cq_num)
+{
+       return mlx4_cmd(dev, mailbox->dma, cq_num, 0, MLX4_CMD_SW2HW_CQ,
+                       MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                        int cq_num)
+{
+       return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, cq_num,
+                           mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ,
+                           MLX4_CMD_TIME_CLASS_A);
+}
+
+int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
+                 struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cq_table *cq_table = &priv->cq_table;
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_cq_context *cq_context;
+       u64 mtt_addr;
+       int err;
+
+       cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap);
+       if (cq->cqn == -1)
+               return -ENOMEM;
+
+       err = mlx4_table_get(dev, &cq_table->table, cq->cqn);
+       if (err)
+               goto err_out;
+
+       err = mlx4_table_get(dev, &cq_table->cmpt_table, cq->cqn);
+       if (err)
+               goto err_put;
+
+       spin_lock_irq(&cq_table->lock);
+       err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
+       spin_unlock_irq(&cq_table->lock);
+       if (err)
+               goto err_cmpt_put;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
+               goto err_radix;
+       }
+
+       cq_context = mailbox->buf;
+       memset(cq_context, 0, sizeof *cq_context);
+
+       cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
+       cq_context->comp_eqn        = priv->eq_table.eq[MLX4_EQ_COMP].eqn;
+       cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
+
+       mtt_addr = mlx4_mtt_addr(dev, mtt);
+       cq_context->mtt_base_addr_h = mtt_addr >> 32;
+       cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
+       cq_context->db_rec_addr     = cpu_to_be64(db_rec);
+
+       err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn);
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       if (err)
+               goto err_radix;
+
+       cq->cons_index = 0;
+       cq->arm_sn     = 1;
+       cq->uar        = uar;
+       atomic_set(&cq->refcount, 1);
+       init_completion(&cq->free);
+
+       return 0;
+
+err_radix:
+       spin_lock_irq(&cq_table->lock);
+       radix_tree_delete(&cq_table->tree, cq->cqn);
+       spin_unlock_irq(&cq_table->lock);
+
+err_cmpt_put:
+       mlx4_table_put(dev, &cq_table->cmpt_table, cq->cqn);
+
+err_put:
+       mlx4_table_put(dev, &cq_table->table, cq->cqn);
+
+err_out:
+       mlx4_bitmap_free(&cq_table->bitmap, cq->cqn);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_cq_alloc);
+
+void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cq_table *cq_table = &priv->cq_table;
+       int err;
+
+       err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn);
+       if (err)
+               mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
+
+       synchronize_irq(priv->eq_table.eq[MLX4_EQ_COMP].irq);
+
+       spin_lock_irq(&cq_table->lock);
+       radix_tree_delete(&cq_table->tree, cq->cqn);
+       spin_unlock_irq(&cq_table->lock);
+
+       if (atomic_dec_and_test(&cq->refcount))
+               complete(&cq->free);
+       wait_for_completion(&cq->free);
+
+       mlx4_table_put(dev, &cq_table->table, cq->cqn);
+       mlx4_bitmap_free(&cq_table->bitmap, cq->cqn);
+}
+EXPORT_SYMBOL_GPL(mlx4_cq_free);
+
+int __devinit mlx4_init_cq_table(struct mlx4_dev *dev)
+{
+       struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
+       int err;
+
+       spin_lock_init(&cq_table->lock);
+       INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC);
+
+       err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs,
+                              dev->caps.num_cqs - 1, dev->caps.reserved_cqs);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+void mlx4_cleanup_cq_table(struct mlx4_dev *dev)
+{
+       /* Nothing to do to clean up radix_tree */
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap);
+}
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
new file mode 100644 (file)
index 0000000..acf1c80
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+#include "fw.h"
+
+enum {
+       MLX4_NUM_ASYNC_EQE      = 0x100,
+       MLX4_NUM_SPARE_EQE      = 0x80,
+       MLX4_EQ_ENTRY_SIZE      = 0x20
+};
+
+/*
+ * Must be packed because start is 64 bits but only aligned to 32 bits.
+ */
+struct mlx4_eq_context {
+       __be32                  flags;
+       u16                     reserved1[3];
+       __be16                  page_offset;
+       u8                      log_eq_size;
+       u8                      reserved2[4];
+       u8                      eq_period;
+       u8                      reserved3;
+       u8                      eq_max_count;
+       u8                      reserved4[3];
+       u8                      intr;
+       u8                      log_page_size;
+       u8                      reserved5[2];
+       u8                      mtt_base_addr_h;
+       __be32                  mtt_base_addr_l;
+       u32                     reserved6[2];
+       __be32                  consumer_index;
+       __be32                  producer_index;
+       u32                     reserved7[4];
+};
+
+#define MLX4_EQ_STATUS_OK         ( 0 << 28)
+#define MLX4_EQ_STATUS_WRITE_FAIL  (10 << 28)
+#define MLX4_EQ_OWNER_SW          ( 0 << 24)
+#define MLX4_EQ_OWNER_HW          ( 1 << 24)
+#define MLX4_EQ_FLAG_EC                   ( 1 << 18)
+#define MLX4_EQ_FLAG_OI                   ( 1 << 17)
+#define MLX4_EQ_STATE_ARMED       ( 9 <<  8)
+#define MLX4_EQ_STATE_FIRED       (10 <<  8)
+#define MLX4_EQ_STATE_ALWAYS_ARMED (11 <<  8)
+
+#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG)          | \
+                              (1ull << MLX4_EVENT_TYPE_COMM_EST)           | \
+                              (1ull << MLX4_EVENT_TYPE_SQ_DRAINED)         | \
+                              (1ull << MLX4_EVENT_TYPE_CQ_ERROR)           | \
+                              (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR)     | \
+                              (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR)    | \
+                              (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED)    | \
+                              (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
+                              (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
+                              (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \
+                              (1ull << MLX4_EVENT_TYPE_PORT_CHANGE)        | \
+                              (1ull << MLX4_EVENT_TYPE_ECC_DETECT)         | \
+                              (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
+                              (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
+                              (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)          | \
+                              (1ull << MLX4_EVENT_TYPE_CMD))
+#define MLX4_CATAS_EVENT_MASK  (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
+
+struct mlx4_eqe {
+       u8                      reserved1;
+       u8                      type;
+       u8                      reserved2;
+       u8                      subtype;
+       union {
+               u32             raw[6];
+               struct {
+                       __be32  cqn;
+               } __attribute__((packed)) comp;
+               struct {
+                       u16     reserved1;
+                       __be16  token;
+                       u32     reserved2;
+                       u8      reserved3[3];
+                       u8      status;
+                       __be64  out_param;
+               } __attribute__((packed)) cmd;
+               struct {
+                       __be32  qpn;
+               } __attribute__((packed)) qp;
+               struct {
+                       __be32  srqn;
+               } __attribute__((packed)) srq;
+               struct {
+                       __be32  cqn;
+                       u32     reserved1;
+                       u8      reserved2[3];
+                       u8      syndrome;
+               } __attribute__((packed)) cq_err;
+               struct {
+                       u32     reserved1[2];
+                       __be32  port;
+               } __attribute__((packed)) port_change;
+       }                       event;
+       u8                      reserved3[3];
+       u8                      owner;
+} __attribute__((packed));
+
+static void eq_set_ci(struct mlx4_eq *eq, int req_not)
+{
+       __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) |
+                                              req_not << 31),
+                    eq->doorbell);
+       /* We still want ordering, just not swabbing, so add a barrier */
+       mb();
+}
+
+static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry)
+{
+       unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE;
+       return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE;
+}
+
+static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq)
+{
+       struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index);
+       return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe;
+}
+
+static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
+{
+       struct mlx4_eqe *eqe;
+       int cqn;
+       int eqes_found = 0;
+       int set_ci = 0;
+
+       while ((eqe = next_eqe_sw(eq))) {
+               /*
+                * Make sure we read EQ entry contents after we've
+                * checked the ownership bit.
+                */
+               rmb();
+
+               switch (eqe->type) {
+               case MLX4_EVENT_TYPE_COMP:
+                       cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff;
+                       mlx4_cq_completion(dev, cqn);
+                       break;
+
+               case MLX4_EVENT_TYPE_PATH_MIG:
+               case MLX4_EVENT_TYPE_COMM_EST:
+               case MLX4_EVENT_TYPE_SQ_DRAINED:
+               case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
+               case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
+               case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
+               case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+               case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
+                       mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
+                                     eqe->type);
+                       break;
+
+               case MLX4_EVENT_TYPE_SRQ_LIMIT:
+               case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
+                       mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff,
+                                     eqe->type);
+                       break;
+
+               case MLX4_EVENT_TYPE_CMD:
+                       mlx4_cmd_event(dev,
+                                      be16_to_cpu(eqe->event.cmd.token),
+                                      eqe->event.cmd.status,
+                                      be64_to_cpu(eqe->event.cmd.out_param));
+                       break;
+
+               case MLX4_EVENT_TYPE_PORT_CHANGE:
+                       mlx4_dispatch_event(dev, eqe->type, eqe->subtype,
+                                           be32_to_cpu(eqe->event.port_change.port) >> 28);
+                       break;
+
+               case MLX4_EVENT_TYPE_CQ_ERROR:
+                       mlx4_warn(dev, "CQ %s on CQN %06x\n",
+                                 eqe->event.cq_err.syndrome == 1 ?
+                                 "overrun" : "access violation",
+                                 be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff);
+                       mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn),
+                                     eqe->type);
+                       break;
+
+               case MLX4_EVENT_TYPE_EQ_OVERFLOW:
+                       mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
+                       break;
+
+               case MLX4_EVENT_TYPE_EEC_CATAS_ERROR:
+               case MLX4_EVENT_TYPE_ECC_DETECT:
+               default:
+                       mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at index %u\n",
+                                 eqe->type, eqe->subtype, eq->eqn, eq->cons_index);
+                       break;
+               };
+
+               ++eq->cons_index;
+               eqes_found = 1;
+               ++set_ci;
+
+               /*
+                * The HCA will think the queue has overflowed if we
+                * don't tell it we've been processing events.  We
+                * create our EQs with MLX4_NUM_SPARE_EQE extra
+                * entries, so we must update our consumer index at
+                * least that often.
+                */
+               if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) {
+                       /*
+                        * Conditional on hca_type is OK here because
+                        * this is a rare case, not the fast path.
+                        */
+                       eq_set_ci(eq, 0);
+                       set_ci = 0;
+               }
+       }
+
+       eq_set_ci(eq, 1);
+
+       return eqes_found;
+}
+
+static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
+{
+       struct mlx4_dev *dev = dev_ptr;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int work = 0;
+       int i;
+
+       writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
+
+       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+               work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
+
+       return IRQ_RETVAL(work);
+}
+
+static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
+{
+       struct mlx4_eq  *eq  = eq_ptr;
+       struct mlx4_dev *dev = eq->dev;
+
+       mlx4_eq_int(dev, eq);
+
+       /* MSI-X vectors always belong to us */
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
+{
+       mlx4_handle_catas_err(dev_ptr);
+
+       /* MSI-X vectors always belong to us */
+       return IRQ_HANDLED;
+}
+
+static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
+                       int eq_num)
+{
+       return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num,
+                       0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B);
+}
+
+static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                        int eq_num)
+{
+       return mlx4_cmd(dev, mailbox->dma, eq_num, 0, MLX4_CMD_SW2HW_EQ,
+                       MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                        int eq_num)
+{
+       return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, 0, MLX4_CMD_HW2SW_EQ,
+                           MLX4_CMD_TIME_CLASS_A);
+}
+
+static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
+                                              struct mlx4_eq *eq)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int index;
+
+       index = eq->eqn / 4 - dev->caps.reserved_eqs / 4;
+
+       if (!priv->eq_table.uar_map[index]) {
+               priv->eq_table.uar_map[index] =
+                       ioremap(pci_resource_start(dev->pdev, 2) +
+                               ((eq->eqn / 4) << PAGE_SHIFT),
+                               PAGE_SIZE);
+               if (!priv->eq_table.uar_map[index]) {
+                       mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",
+                                eq->eqn);
+                       return NULL;
+               }
+       }
+
+       return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
+}
+
+static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent,
+                                   u8 intr, struct mlx4_eq *eq)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_eq_context *eq_context;
+       int npages;
+       u64 *dma_list = NULL;
+       dma_addr_t t;
+       u64 mtt_addr;
+       int err = -ENOMEM;
+       int i;
+
+       eq->dev   = dev;
+       eq->nent  = roundup_pow_of_two(max(nent, 2));
+       npages = PAGE_ALIGN(eq->nent * MLX4_EQ_ENTRY_SIZE) / PAGE_SIZE;
+
+       eq->page_list = kmalloc(npages * sizeof *eq->page_list,
+                               GFP_KERNEL);
+       if (!eq->page_list)
+               goto err_out;
+
+       for (i = 0; i < npages; ++i)
+               eq->page_list[i].buf = NULL;
+
+       dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);
+       if (!dma_list)
+               goto err_out_free;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               goto err_out_free;
+       eq_context = mailbox->buf;
+
+       for (i = 0; i < npages; ++i) {
+               eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
+                                                         PAGE_SIZE, &t, GFP_KERNEL);
+               if (!eq->page_list[i].buf)
+                       goto err_out_free_pages;
+
+               dma_list[i] = t;
+               eq->page_list[i].map = t;
+
+               memset(eq->page_list[i].buf, 0, PAGE_SIZE);
+       }
+
+       eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap);
+       if (eq->eqn == -1)
+               goto err_out_free_pages;
+
+       eq->doorbell = mlx4_get_eq_uar(dev, eq);
+       if (!eq->doorbell) {
+               err = -ENOMEM;
+               goto err_out_free_eq;
+       }
+
+       err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt);
+       if (err)
+               goto err_out_free_eq;
+
+       err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list);
+       if (err)
+               goto err_out_free_mtt;
+
+       memset(eq_context, 0, sizeof *eq_context);
+       eq_context->flags         = cpu_to_be32(MLX4_EQ_STATUS_OK   |
+                                               MLX4_EQ_STATE_ARMED);
+       eq_context->log_eq_size   = ilog2(eq->nent);
+       eq_context->intr          = intr;
+       eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT;
+
+       mtt_addr = mlx4_mtt_addr(dev, &eq->mtt);
+       eq_context->mtt_base_addr_h = mtt_addr >> 32;
+       eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
+
+       err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn);
+       if (err) {
+               mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err);
+               goto err_out_free_mtt;
+       }
+
+       kfree(dma_list);
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+       eq->cons_index = 0;
+
+       return err;
+
+err_out_free_mtt:
+       mlx4_mtt_cleanup(dev, &eq->mtt);
+
+err_out_free_eq:
+       mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn);
+
+err_out_free_pages:
+       for (i = 0; i < npages; ++i)
+               if (eq->page_list[i].buf)
+                       dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+                                         eq->page_list[i].buf,
+                                         eq->page_list[i].map);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+err_out_free:
+       kfree(eq->page_list);
+       kfree(dma_list);
+
+err_out:
+       return err;
+}
+
+static void mlx4_free_eq(struct mlx4_dev *dev,
+                        struct mlx4_eq *eq)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cmd_mailbox *mailbox;
+       int err;
+       int npages = PAGE_ALIGN(MLX4_EQ_ENTRY_SIZE * eq->nent) / PAGE_SIZE;
+       int i;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return;
+
+       err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn);
+       if (err)
+               mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err);
+
+       if (0) {
+               mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
+               for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) {
+                       if (i % 4 == 0)
+                               printk("[%02x] ", i * 4);
+                       printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
+                       if ((i + 1) % 4 == 0)
+                               printk("\n");
+               }
+       }
+
+       mlx4_mtt_cleanup(dev, &eq->mtt);
+       for (i = 0; i < npages; ++i)
+               pci_free_consistent(dev->pdev, PAGE_SIZE,
+                                   eq->page_list[i].buf,
+                                   eq->page_list[i].map);
+
+       kfree(eq->page_list);
+       mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn);
+       mlx4_free_cmd_mailbox(dev, mailbox);
+}
+
+static void mlx4_free_irqs(struct mlx4_dev *dev)
+{
+       struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table;
+       int i;
+
+       if (eq_table->have_irq)
+               free_irq(dev->pdev->irq, dev);
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
+               if (eq_table->eq[i].have_irq)
+                       free_irq(eq_table->eq[i].irq, eq_table->eq + i);
+}
+
+static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) +
+                                priv->fw.clr_int_base, MLX4_CLR_INT_SIZE);
+       if (!priv->clr_base) {
+               mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       iounmap(priv->clr_base);
+}
+
+int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int ret;
+
+       /*
+        * We assume that mapping one page is enough for the whole EQ
+        * context table.  This is fine with all current HCAs, because
+        * we only use 32 EQs and each EQ uses 64 bytes of context
+        * memory, or 1 KB total.
+        */
+       priv->eq_table.icm_virt = icm_virt;
+       priv->eq_table.icm_page = alloc_page(GFP_HIGHUSER);
+       if (!priv->eq_table.icm_page)
+               return -ENOMEM;
+       priv->eq_table.icm_dma  = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0,
+                                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(priv->eq_table.icm_dma)) {
+               __free_page(priv->eq_table.icm_page);
+               return -ENOMEM;
+       }
+
+       ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma, icm_virt);
+       if (ret) {
+               pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
+                              PCI_DMA_BIDIRECTIONAL);
+               __free_page(priv->eq_table.icm_page);
+       }
+
+       return ret;
+}
+
+void mlx4_unmap_eq_icm(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1);
+       pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
+                      PCI_DMA_BIDIRECTIONAL);
+       __free_page(priv->eq_table.icm_page);
+}
+
+int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+       int i;
+
+       err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
+                              dev->caps.num_eqs - 1, dev->caps.reserved_eqs);
+       if (err)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i)
+               priv->eq_table.uar_map[i] = NULL;
+
+       err = mlx4_map_clr_int(dev);
+       if (err)
+               goto err_out_free;
+
+       priv->eq_table.clr_mask =
+               swab32(1 << (priv->eq_table.inta_pin & 31));
+       priv->eq_table.clr_int  = priv->clr_base +
+               (priv->eq_table.inta_pin < 32 ? 4 : 0);
+
+       err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
+                            (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_COMP : 0,
+                            &priv->eq_table.eq[MLX4_EQ_COMP]);
+       if (err)
+               goto err_out_unmap;
+
+       err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
+                            (dev->flags & MLX4_FLAG_MSI_X) ? MLX4_EQ_ASYNC : 0,
+                            &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+       if (err)
+               goto err_out_comp;
+
+       if (dev->flags & MLX4_FLAG_MSI_X) {
+               static const char *eq_name[] = {
+                       [MLX4_EQ_COMP]  = DRV_NAME " (comp)",
+                       [MLX4_EQ_ASYNC] = DRV_NAME " (async)",
+                       [MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+               };
+
+               err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
+                                    &priv->eq_table.eq[MLX4_EQ_CATAS]);
+               if (err)
+                       goto err_out_async;
+
+               for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+                       err = request_irq(priv->eq_table.eq[i].irq,
+                                         mlx4_msi_x_interrupt,
+                                         0, eq_name[i], priv->eq_table.eq + i);
+                       if (err)
+                               goto err_out_catas;
+
+                       priv->eq_table.eq[i].have_irq = 1;
+               }
+
+               err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
+                                 mlx4_catas_interrupt, 0,
+                                 eq_name[MLX4_EQ_CATAS], dev);
+               if (err)
+                       goto err_out_catas;
+
+               priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
+       } else {
+               err = request_irq(dev->pdev->irq, mlx4_interrupt,
+                                 SA_SHIRQ, DRV_NAME, dev);
+               if (err)
+                       goto err_out_async;
+
+               priv->eq_table.have_irq = 1;
+       }
+
+       err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+                         priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+       if (err)
+               mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
+                          priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
+
+       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+               eq_set_ci(&priv->eq_table.eq[i], 1);
+
+       if (dev->flags & MLX4_FLAG_MSI_X) {
+               err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
+                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
+               if (err)
+                       mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
+                                 priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
+       }
+
+       return 0;
+
+err_out_catas:
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
+
+err_out_async:
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
+
+err_out_comp:
+       mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_COMP]);
+
+err_out_unmap:
+       mlx4_unmap_clr_int(dev);
+       mlx4_free_irqs(dev);
+
+err_out_free:
+       mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
+       return err;
+}
+
+void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i;
+
+       if (dev->flags & MLX4_FLAG_MSI_X)
+               mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
+                           priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
+
+       mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
+                   priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
+
+       mlx4_free_irqs(dev);
+
+       for (i = 0; i < MLX4_EQ_CATAS; ++i)
+               mlx4_free_eq(dev, &priv->eq_table.eq[i]);
+       if (dev->flags & MLX4_FLAG_MSI_X)
+               mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
+
+       mlx4_unmap_clr_int(dev);
+
+       for (i = 0; i < ARRAY_SIZE(priv->eq_table.uar_map); ++i)
+               if (priv->eq_table.uar_map[i])
+                       iounmap(priv->eq_table.uar_map[i]);
+
+       mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
+}
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
new file mode 100644 (file)
index 0000000..c427173
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx4/cmd.h>
+
+#include "fw.h"
+#include "icm.h"
+
+extern void __buggy_use_of_MLX4_GET(void);
+extern void __buggy_use_of_MLX4_PUT(void);
+
+#define MLX4_GET(dest, source, offset)                               \
+       do {                                                          \
+               void *__p = (char *) (source) + (offset);             \
+               switch (sizeof (dest)) {                              \
+               case 1: (dest) = *(u8 *) __p;       break;            \
+               case 2: (dest) = be16_to_cpup(__p); break;            \
+               case 4: (dest) = be32_to_cpup(__p); break;            \
+               case 8: (dest) = be64_to_cpup(__p); break;            \
+               default: __buggy_use_of_MLX4_GET();                   \
+               }                                                     \
+       } while (0)
+
+#define MLX4_PUT(dest, source, offset)                               \
+       do {                                                          \
+               void *__d = ((char *) (dest) + (offset));             \
+               switch (sizeof(source)) {                             \
+               case 1: *(u8 *) __d = (source);                break; \
+               case 2: *(__be16 *) __d = cpu_to_be16(source); break; \
+               case 4: *(__be32 *) __d = cpu_to_be32(source); break; \
+               case 8: *(__be64 *) __d = cpu_to_be64(source); break; \
+               default: __buggy_use_of_MLX4_PUT();                   \
+               }                                                     \
+       } while (0)
+
+static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
+{
+       static const char *fname[] = {
+               [ 0] = "RC transport",
+               [ 1] = "UC transport",
+               [ 2] = "UD transport",
+               [ 3] = "SRC transport",
+               [ 4] = "reliable multicast",
+               [ 5] = "FCoIB support",
+               [ 6] = "SRQ support",
+               [ 7] = "IPoIB checksum offload",
+               [ 8] = "P_Key violation counter",
+               [ 9] = "Q_Key violation counter",
+               [10] = "VMM",
+               [16] = "MW support",
+               [17] = "APM support",
+               [18] = "Atomic ops support",
+               [19] = "Raw multicast support",
+               [20] = "Address vector port checking support",
+               [21] = "UD multicast support",
+               [24] = "Demand paging support",
+               [25] = "Router support"
+       };
+       int i;
+
+       mlx4_dbg(dev, "DEV_CAP flags:\n");
+       for (i = 0; i < 32; ++i)
+               if (fname[i] && (flags & (1 << i)))
+                       mlx4_dbg(dev, "    %s\n", fname[i]);
+}
+
+int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       u8 field;
+       u16 size;
+       u16 stat_rate;
+       int err;
+
+#define QUERY_DEV_CAP_OUT_SIZE                0x100
+#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET                0x10
+#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET         0x11
+#define QUERY_DEV_CAP_RSVD_QP_OFFSET           0x12
+#define QUERY_DEV_CAP_MAX_QP_OFFSET            0x13
+#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET          0x14
+#define QUERY_DEV_CAP_MAX_SRQ_OFFSET           0x15
+#define QUERY_DEV_CAP_RSVD_EEC_OFFSET          0x16
+#define QUERY_DEV_CAP_MAX_EEC_OFFSET           0x17
+#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET         0x19
+#define QUERY_DEV_CAP_RSVD_CQ_OFFSET           0x1a
+#define QUERY_DEV_CAP_MAX_CQ_OFFSET            0x1b
+#define QUERY_DEV_CAP_MAX_MPT_OFFSET           0x1d
+#define QUERY_DEV_CAP_RSVD_EQ_OFFSET           0x1e
+#define QUERY_DEV_CAP_MAX_EQ_OFFSET            0x1f
+#define QUERY_DEV_CAP_RSVD_MTT_OFFSET          0x20
+#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET                0x21
+#define QUERY_DEV_CAP_RSVD_MRW_OFFSET          0x22
+#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET       0x23
+#define QUERY_DEV_CAP_MAX_AV_OFFSET            0x27
+#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET                0x29
+#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET                0x2b
+#define QUERY_DEV_CAP_MAX_RDMA_OFFSET          0x2f
+#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET           0x33
+#define QUERY_DEV_CAP_ACK_DELAY_OFFSET         0x35
+#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET         0x36
+#define QUERY_DEV_CAP_VL_PORT_OFFSET           0x37
+#define QUERY_DEV_CAP_MAX_GID_OFFSET           0x3b
+#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET      0x3c
+#define QUERY_DEV_CAP_MAX_PKEY_OFFSET          0x3f
+#define QUERY_DEV_CAP_FLAGS_OFFSET             0x44
+#define QUERY_DEV_CAP_RSVD_UAR_OFFSET          0x48
+#define QUERY_DEV_CAP_UAR_SZ_OFFSET            0x49
+#define QUERY_DEV_CAP_PAGE_SZ_OFFSET           0x4b
+#define QUERY_DEV_CAP_BF_OFFSET                        0x4c
+#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET     0x4d
+#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET  0x4e
+#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET  0x4f
+#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET         0x51
+#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET    0x52
+#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET         0x55
+#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET    0x56
+#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET                0x61
+#define QUERY_DEV_CAP_RSVD_MCG_OFFSET          0x62
+#define QUERY_DEV_CAP_MAX_MCG_OFFSET           0x63
+#define QUERY_DEV_CAP_RSVD_PD_OFFSET           0x64
+#define QUERY_DEV_CAP_MAX_PD_OFFSET            0x65
+#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET   0x80
+#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET      0x82
+#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET      0x84
+#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET     0x86
+#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET      0x88
+#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET      0x8a
+#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET      0x8c
+#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET    0x8e
+#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET      0x90
+#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET    0x92
+#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET                0x97
+#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET         0x98
+#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET                0xa0
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
+                          MLX4_CMD_TIME_CLASS_A);
+
+       if (err)
+               goto out;
+
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET);
+       dev_cap->reserved_qps = 1 << (field & 0xf);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET);
+       dev_cap->max_qps = 1 << (field & 0x1f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET);
+       dev_cap->reserved_srqs = 1 << (field >> 4);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET);
+       dev_cap->max_srqs = 1 << (field & 0x1f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET);
+       dev_cap->max_cq_sz = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET);
+       dev_cap->reserved_cqs = 1 << (field & 0xf);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET);
+       dev_cap->max_cqs = 1 << (field & 0x1f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET);
+       dev_cap->max_mpts = 1 << (field & 0x3f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
+       dev_cap->reserved_eqs = 1 << (field & 0xf);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
+       dev_cap->max_eqs = 1 << (field & 0x7);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
+       dev_cap->reserved_mtts = 1 << (field >> 4);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
+       dev_cap->max_mrw_sz = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET);
+       dev_cap->reserved_mrws = 1 << (field & 0xf);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET);
+       dev_cap->max_mtt_seg = 1 << (field & 0x3f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET);
+       dev_cap->max_requester_per_qp = 1 << (field & 0x3f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET);
+       dev_cap->max_responder_per_qp = 1 << (field & 0x3f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
+       dev_cap->max_rdma_global = 1 << (field & 0x3f);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
+       dev_cap->local_ca_ack_delay = field & 0x1f;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
+       dev_cap->max_mtu        = field >> 4;
+       dev_cap->max_port_width = field & 0xf;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
+       dev_cap->max_vl    = field >> 4;
+       dev_cap->num_ports = field & 0xf;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET);
+       dev_cap->max_gids = 1 << (field & 0xf);
+       MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
+       dev_cap->stat_rate_support = stat_rate;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET);
+       dev_cap->max_pkeys = 1 << (field & 0xf);
+       MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
+       dev_cap->reserved_uars = field >> 4;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET);
+       dev_cap->uar_size = 1 << ((field & 0x3f) + 20);
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET);
+       dev_cap->min_page_sz = 1 << field;
+
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET);
+       if (field & 0x80) {
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET);
+               dev_cap->bf_reg_size = 1 << (field & 0x1f);
+               MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET);
+               dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
+               mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
+                        dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
+       } else {
+               dev_cap->bf_reg_size = 0;
+               mlx4_dbg(dev, "BlueFlame not available\n");
+       }
+
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET);
+       dev_cap->max_sq_sg = field;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET);
+       dev_cap->max_sq_desc_sz = size;
+
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET);
+       dev_cap->max_qp_per_mcg = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET);
+       dev_cap->reserved_mgms = field & 0xf;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET);
+       dev_cap->max_mcgs = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET);
+       dev_cap->reserved_pds = field >> 4;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET);
+       dev_cap->max_pds = 1 << (field & 0x3f);
+
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET);
+       dev_cap->rdmarc_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET);
+       dev_cap->qpc_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET);
+       dev_cap->aux_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET);
+       dev_cap->altc_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET);
+       dev_cap->eqc_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET);
+       dev_cap->cqc_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET);
+       dev_cap->srq_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET);
+       dev_cap->cmpt_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET);
+       dev_cap->mtt_entry_sz = size;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET);
+       dev_cap->dmpt_entry_sz = size;
+
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET);
+       dev_cap->max_srq_sz = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET);
+       dev_cap->max_qp_sz = 1 << field;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET);
+       dev_cap->resize_srq = field & 1;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET);
+       dev_cap->max_rq_sg = field;
+       MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET);
+       dev_cap->max_rq_desc_sz = size;
+
+       MLX4_GET(dev_cap->bmme_flags, outbox,
+                QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+       MLX4_GET(dev_cap->reserved_lkey, outbox,
+                QUERY_DEV_CAP_RSVD_LKEY_OFFSET);
+       MLX4_GET(dev_cap->max_icm_sz, outbox,
+                QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET);
+
+       if (dev_cap->bmme_flags & 1)
+               mlx4_dbg(dev, "Base MM extensions: yes "
+                        "(flags %d, rsvd L_Key %08x)\n",
+                        dev_cap->bmme_flags, dev_cap->reserved_lkey);
+       else
+               mlx4_dbg(dev, "Base MM extensions: no\n");
+
+       /*
+        * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then
+        * we can't use any EQs whose doorbell falls on that page,
+        * even if the EQ itself isn't reserved.
+        */
+       dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4,
+                                   dev_cap->reserved_eqs);
+
+       mlx4_dbg(dev, "Max ICM size %lld MB\n",
+                (unsigned long long) dev_cap->max_icm_sz >> 20);
+       mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
+                dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz);
+       mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n",
+                dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz);
+       mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n",
+                dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz);
+       mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n",
+                dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz);
+       mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n",
+                dev_cap->reserved_mrws, dev_cap->reserved_mtts);
+       mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n",
+                dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars);
+       mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n",
+                dev_cap->max_pds, dev_cap->reserved_mgms);
+       mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n",
+                dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz);
+       mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n",
+                dev_cap->local_ca_ack_delay, 128 << dev_cap->max_mtu,
+                dev_cap->max_port_width);
+       mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n",
+                dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg);
+       mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n",
+                dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
+
+       dump_dev_cap_flags(dev, dev_cap->flags);
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_icm_iter iter;
+       __be64 *pages;
+       int lg;
+       int nent = 0;
+       int i;
+       int err = 0;
+       int ts = 0, tc = 0;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
+       pages = mailbox->buf;
+
+       for (mlx4_icm_first(icm, &iter);
+            !mlx4_icm_last(&iter);
+            mlx4_icm_next(&iter)) {
+               /*
+                * We have to pass pages that are aligned to their
+                * size, so find the least significant 1 in the
+                * address or size and use that as our log2 size.
+                */
+               lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1;
+               if (lg < MLX4_ICM_PAGE_SHIFT) {
+                       mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n",
+                                  MLX4_ICM_PAGE_SIZE,
+                                  (unsigned long long) mlx4_icm_addr(&iter),
+                                  mlx4_icm_size(&iter));
+                       err = -EINVAL;
+                       goto out;
+               }
+
+               for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) {
+                       if (virt != -1) {
+                               pages[nent * 2] = cpu_to_be64(virt);
+                               virt += 1 << lg;
+                       }
+
+                       pages[nent * 2 + 1] =
+                               cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) |
+                                           (lg - MLX4_ICM_PAGE_SHIFT));
+                       ts += 1 << (lg - 10);
+                       ++tc;
+
+                       if (++nent == MLX4_MAILBOX_SIZE / 16) {
+                               err = mlx4_cmd(dev, mailbox->dma, nent, 0, op,
+                                               MLX4_CMD_TIME_CLASS_B);
+                               if (err)
+                                       goto out;
+                               nent = 0;
+                       }
+               }
+       }
+
+       if (nent)
+               err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, MLX4_CMD_TIME_CLASS_B);
+       if (err)
+               goto out;
+
+       switch (op) {
+       case MLX4_CMD_MAP_FA:
+               mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts);
+               break;
+       case MLX4_CMD_MAP_ICM_AUX:
+               mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts);
+               break;
+       case MLX4_CMD_MAP_ICM:
+               mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n",
+                         tc, ts, (unsigned long long) virt - (ts << 10));
+               break;
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm)
+{
+       return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1);
+}
+
+int mlx4_UNMAP_FA(struct mlx4_dev *dev)
+{
+       return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, MLX4_CMD_TIME_CLASS_B);
+}
+
+
+int mlx4_RUN_FW(struct mlx4_dev *dev)
+{
+       return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, MLX4_CMD_TIME_CLASS_A);
+}
+
+int mlx4_QUERY_FW(struct mlx4_dev *dev)
+{
+       struct mlx4_fw  *fw  = &mlx4_priv(dev)->fw;
+       struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       int err = 0;
+       u64 fw_ver;
+       u8 lg;
+
+#define QUERY_FW_OUT_SIZE             0x100
+#define QUERY_FW_VER_OFFSET            0x00
+#define QUERY_FW_MAX_CMD_OFFSET        0x0f
+#define QUERY_FW_ERR_START_OFFSET      0x30
+#define QUERY_FW_ERR_SIZE_OFFSET       0x38
+#define QUERY_FW_ERR_BAR_OFFSET        0x3c
+
+#define QUERY_FW_SIZE_OFFSET           0x00
+#define QUERY_FW_CLR_INT_BASE_OFFSET   0x20
+#define QUERY_FW_CLR_INT_BAR_OFFSET    0x28
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW,
+                           MLX4_CMD_TIME_CLASS_A);
+       if (err)
+               goto out;
+
+       MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET);
+       /*
+        * FW subminor version is at more signifant bits than minor
+        * version, so swap here.
+        */
+       dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) |
+               ((fw_ver & 0xffff0000ull) >> 16) |
+               ((fw_ver & 0x0000ffffull) << 16);
+
+       MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
+       cmd->max_cmds = 1 << lg;
+
+       mlx4_dbg(dev, "FW version %d.%d.%03d, max commands %d\n",
+                (int) (dev->caps.fw_ver >> 32),
+                (int) (dev->caps.fw_ver >> 16) & 0xffff,
+                (int) dev->caps.fw_ver & 0xffff,
+                cmd->max_cmds);
+
+       MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET);
+       MLX4_GET(fw->catas_size,   outbox, QUERY_FW_ERR_SIZE_OFFSET);
+       MLX4_GET(fw->catas_bar,    outbox, QUERY_FW_ERR_BAR_OFFSET);
+       fw->catas_bar = (fw->catas_bar >> 6) * 2;
+
+       mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n",
+                (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar);
+
+       MLX4_GET(fw->fw_pages,     outbox, QUERY_FW_SIZE_OFFSET);
+       MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET);
+       MLX4_GET(fw->clr_int_bar,  outbox, QUERY_FW_CLR_INT_BAR_OFFSET);
+       fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2;
+
+       mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
+
+       /*
+        * Round up number of system pages needed in case
+        * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
+        */
+       fw->fw_pages =
+               ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
+               (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
+
+       mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n",
+                (unsigned long long) fw->clr_int_base, fw->clr_int_bar);
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+static void get_board_id(void *vsd, char *board_id)
+{
+       int i;
+
+#define VSD_OFFSET_SIG1                0x00
+#define VSD_OFFSET_SIG2                0xde
+#define VSD_OFFSET_MLX_BOARD_ID        0xd0
+#define VSD_OFFSET_TS_BOARD_ID 0x20
+
+#define VSD_SIGNATURE_TOPSPIN  0x5ad
+
+       memset(board_id, 0, MLX4_BOARD_ID_LEN);
+
+       if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN &&
+           be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) {
+               strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN);
+       } else {
+               /*
+                * The board ID is a string but the firmware byte
+                * swaps each 4-byte word before passing it back to
+                * us.  Therefore we need to swab it before printing.
+                */
+               for (i = 0; i < 4; ++i)
+                       ((u32 *) board_id)[i] =
+                               swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4));
+       }
+}
+
+int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *outbox;
+       int err;
+
+#define QUERY_ADAPTER_OUT_SIZE             0x100
+#define QUERY_ADAPTER_VENDOR_ID_OFFSET     0x00
+#define QUERY_ADAPTER_DEVICE_ID_OFFSET     0x04
+#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
+#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
+#define QUERY_ADAPTER_VSD_OFFSET           0x20
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       outbox = mailbox->buf;
+
+       err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER,
+                          MLX4_CMD_TIME_CLASS_A);
+       if (err)
+               goto out;
+
+       MLX4_GET(adapter->vendor_id, outbox,   QUERY_ADAPTER_VENDOR_ID_OFFSET);
+       MLX4_GET(adapter->device_id, outbox,   QUERY_ADAPTER_DEVICE_ID_OFFSET);
+       MLX4_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
+       MLX4_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
+
+       get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4,
+                    adapter->board_id);
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       __be32 *inbox;
+       int err;
+
+#define INIT_HCA_IN_SIZE                0x200
+#define INIT_HCA_VERSION_OFFSET                 0x000
+#define         INIT_HCA_VERSION                2
+#define INIT_HCA_FLAGS_OFFSET           0x014
+#define INIT_HCA_QPC_OFFSET             0x020
+#define         INIT_HCA_QPC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x10)
+#define         INIT_HCA_LOG_QP_OFFSET          (INIT_HCA_QPC_OFFSET + 0x17)
+#define         INIT_HCA_SRQC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x28)
+#define         INIT_HCA_LOG_SRQ_OFFSET         (INIT_HCA_QPC_OFFSET + 0x2f)
+#define         INIT_HCA_CQC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x30)
+#define         INIT_HCA_LOG_CQ_OFFSET          (INIT_HCA_QPC_OFFSET + 0x37)
+#define         INIT_HCA_ALTC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x40)
+#define         INIT_HCA_AUXC_BASE_OFFSET       (INIT_HCA_QPC_OFFSET + 0x50)
+#define         INIT_HCA_EQC_BASE_OFFSET        (INIT_HCA_QPC_OFFSET + 0x60)
+#define         INIT_HCA_LOG_EQ_OFFSET          (INIT_HCA_QPC_OFFSET + 0x67)
+#define         INIT_HCA_RDMARC_BASE_OFFSET     (INIT_HCA_QPC_OFFSET + 0x70)
+#define         INIT_HCA_LOG_RD_OFFSET          (INIT_HCA_QPC_OFFSET + 0x77)
+#define INIT_HCA_MCAST_OFFSET           0x0c0
+#define         INIT_HCA_MC_BASE_OFFSET         (INIT_HCA_MCAST_OFFSET + 0x00)
+#define         INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12)
+#define         INIT_HCA_LOG_MC_HASH_SZ_OFFSET  (INIT_HCA_MCAST_OFFSET + 0x16)
+#define         INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b)
+#define INIT_HCA_TPT_OFFSET             0x0f0
+#define         INIT_HCA_DMPT_BASE_OFFSET       (INIT_HCA_TPT_OFFSET + 0x00)
+#define         INIT_HCA_LOG_MPT_SZ_OFFSET      (INIT_HCA_TPT_OFFSET + 0x0b)
+#define         INIT_HCA_MTT_BASE_OFFSET        (INIT_HCA_TPT_OFFSET + 0x10)
+#define         INIT_HCA_CMPT_BASE_OFFSET       (INIT_HCA_TPT_OFFSET + 0x18)
+#define INIT_HCA_UAR_OFFSET             0x120
+#define         INIT_HCA_LOG_UAR_SZ_OFFSET      (INIT_HCA_UAR_OFFSET + 0x0a)
+#define  INIT_HCA_UAR_PAGE_SZ_OFFSET     (INIT_HCA_UAR_OFFSET + 0x0b)
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
+
+       memset(inbox, 0, INIT_HCA_IN_SIZE);
+
+       *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION;
+
+#if defined(__LITTLE_ENDIAN)
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1);
+#elif defined(__BIG_ENDIAN)
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1);
+#else
+#error Host endianness not defined
+#endif
+       /* Check port for UD address vector: */
+       *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1);
+
+       /* QPC/EEC/CQC/EQC/RDMARC attributes */
+
+       MLX4_PUT(inbox, param->qpc_base,      INIT_HCA_QPC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_num_qps,   INIT_HCA_LOG_QP_OFFSET);
+       MLX4_PUT(inbox, param->srqc_base,     INIT_HCA_SRQC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_num_srqs,  INIT_HCA_LOG_SRQ_OFFSET);
+       MLX4_PUT(inbox, param->cqc_base,      INIT_HCA_CQC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_num_cqs,   INIT_HCA_LOG_CQ_OFFSET);
+       MLX4_PUT(inbox, param->altc_base,     INIT_HCA_ALTC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->auxc_base,     INIT_HCA_AUXC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->eqc_base,      INIT_HCA_EQC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_num_eqs,   INIT_HCA_LOG_EQ_OFFSET);
+       MLX4_PUT(inbox, param->rdmarc_base,   INIT_HCA_RDMARC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET);
+
+       /* multicast attributes */
+
+       MLX4_PUT(inbox, param->mc_base,         INIT_HCA_MC_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET);
+       MLX4_PUT(inbox, param->log_mc_hash_sz,  INIT_HCA_LOG_MC_HASH_SZ_OFFSET);
+       MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET);
+
+       /* TPT attributes */
+
+       MLX4_PUT(inbox, param->dmpt_base,  INIT_HCA_DMPT_BASE_OFFSET);
+       MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET);
+       MLX4_PUT(inbox, param->mtt_base,   INIT_HCA_MTT_BASE_OFFSET);
+       MLX4_PUT(inbox, param->cmpt_base,  INIT_HCA_CMPT_BASE_OFFSET);
+
+       /* UAR attributes */
+
+       MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET);
+       MLX4_PUT(inbox, param->log_uar_sz,      INIT_HCA_LOG_UAR_SZ_OFFSET);
+
+       err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 1000);
+
+       if (err)
+               mlx4_err(dev, "INIT_HCA returns %d\n", err);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_INIT_PORT(struct mlx4_dev *dev, struct mlx4_init_port_param *param, int port)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       u32 *inbox;
+       int err;
+       u32 flags;
+
+#define INIT_PORT_IN_SIZE          256
+#define INIT_PORT_FLAGS_OFFSET     0x00
+#define INIT_PORT_FLAG_SIG         (1 << 18)
+#define INIT_PORT_FLAG_NG          (1 << 17)
+#define INIT_PORT_FLAG_G0          (1 << 16)
+#define INIT_PORT_VL_SHIFT         4
+#define INIT_PORT_PORT_WIDTH_SHIFT 8
+#define INIT_PORT_MTU_OFFSET       0x04
+#define INIT_PORT_MAX_GID_OFFSET   0x06
+#define INIT_PORT_MAX_PKEY_OFFSET  0x0a
+#define INIT_PORT_GUID0_OFFSET     0x10
+#define INIT_PORT_NODE_GUID_OFFSET 0x18
+#define INIT_PORT_SI_GUID_OFFSET   0x20
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
+
+       memset(inbox, 0, INIT_PORT_IN_SIZE);
+
+       flags = 0;
+       flags |= param->set_guid0     ? INIT_PORT_FLAG_G0  : 0;
+       flags |= param->set_node_guid ? INIT_PORT_FLAG_NG  : 0;
+       flags |= param->set_si_guid   ? INIT_PORT_FLAG_SIG : 0;
+       flags |= (param->vl_cap & 0xf) << INIT_PORT_VL_SHIFT;
+       flags |= (param->port_width_cap & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT;
+       MLX4_PUT(inbox, flags,            INIT_PORT_FLAGS_OFFSET);
+
+       MLX4_PUT(inbox, param->mtu,       INIT_PORT_MTU_OFFSET);
+       MLX4_PUT(inbox, param->max_gid,   INIT_PORT_MAX_GID_OFFSET);
+       MLX4_PUT(inbox, param->max_pkey,  INIT_PORT_MAX_PKEY_OFFSET);
+       MLX4_PUT(inbox, param->guid0,     INIT_PORT_GUID0_OFFSET);
+       MLX4_PUT(inbox, param->node_guid, INIT_PORT_NODE_GUID_OFFSET);
+       MLX4_PUT(inbox, param->si_guid,   INIT_PORT_SI_GUID_OFFSET);
+
+       err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT,
+                      MLX4_CMD_TIME_CLASS_A);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_INIT_PORT);
+
+int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port)
+{
+       return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000);
+}
+EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT);
+
+int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
+{
+       return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000);
+}
+
+int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
+{
+       int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
+                              MLX4_CMD_SET_ICM_SIZE,
+                              MLX4_CMD_TIME_CLASS_A);
+       if (ret)
+               return ret;
+
+       /*
+        * Round up number of system pages needed in case
+        * MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
+        */
+       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >>
+               (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT);
+
+       return 0;
+}
+
+int mlx4_NOP(struct mlx4_dev *dev)
+{
+       /* Input modifier of 0x1f means "finish as soon as possible." */
+       return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100);
+}
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
new file mode 100644 (file)
index 0000000..2616fa5
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_FW_H
+#define MLX4_FW_H
+
+#include "mlx4.h"
+#include "icm.h"
+
+struct mlx4_dev_cap {
+       int max_srq_sz;
+       int max_qp_sz;
+       int reserved_qps;
+       int max_qps;
+       int reserved_srqs;
+       int max_srqs;
+       int max_cq_sz;
+       int reserved_cqs;
+       int max_cqs;
+       int max_mpts;
+       int reserved_eqs;
+       int max_eqs;
+       int reserved_mtts;
+       int max_mrw_sz;
+       int reserved_mrws;
+       int max_mtt_seg;
+       int max_requester_per_qp;
+       int max_responder_per_qp;
+       int max_rdma_global;
+       int local_ca_ack_delay;
+       int max_mtu;
+       int max_port_width;
+       int max_vl;
+       int num_ports;
+       int max_gids;
+       u16 stat_rate_support;
+       int max_pkeys;
+       u32 flags;
+       int reserved_uars;
+       int uar_size;
+       int min_page_sz;
+       int bf_reg_size;
+       int bf_regs_per_page;
+       int max_sq_sg;
+       int max_sq_desc_sz;
+       int max_rq_sg;
+       int max_rq_desc_sz;
+       int max_qp_per_mcg;
+       int reserved_mgms;
+       int max_mcgs;
+       int reserved_pds;
+       int max_pds;
+       int qpc_entry_sz;
+       int rdmarc_entry_sz;
+       int altc_entry_sz;
+       int aux_entry_sz;
+       int srq_entry_sz;
+       int cqc_entry_sz;
+       int eqc_entry_sz;
+       int dmpt_entry_sz;
+       int cmpt_entry_sz;
+       int mtt_entry_sz;
+       int resize_srq;
+       u8  bmme_flags;
+       u32 reserved_lkey;
+       u64 max_icm_sz;
+};
+
+struct mlx4_adapter {
+       u32  vendor_id;
+       u32  device_id;
+       u32  revision_id;
+       char board_id[MLX4_BOARD_ID_LEN];
+       u8   inta_pin;
+};
+
+struct mlx4_init_hca_param {
+       u64 qpc_base;
+       u64 rdmarc_base;
+       u64 auxc_base;
+       u64 altc_base;
+       u64 srqc_base;
+       u64 cqc_base;
+       u64 eqc_base;
+       u64 mc_base;
+       u64 dmpt_base;
+       u64 cmpt_base;
+       u64 mtt_base;
+       u16 log_mc_entry_sz;
+       u16 log_mc_hash_sz;
+       u8  log_num_qps;
+       u8  log_num_srqs;
+       u8  log_num_cqs;
+       u8  log_num_eqs;
+       u8  log_rd_per_qp;
+       u8  log_mc_table_sz;
+       u8  log_mpt_sz;
+       u8  log_uar_sz;
+};
+
+struct mlx4_init_ib_param {
+       int port_width;
+       int vl_cap;
+       int mtu_cap;
+       u16 gid_cap;
+       u16 pkey_cap;
+       int set_guid0;
+       u64 guid0;
+       int set_node_guid;
+       u64 node_guid;
+       int set_si_guid;
+       u64 si_guid;
+};
+
+struct mlx4_set_ib_param {
+       int set_si_guid;
+       int reset_qkey_viol;
+       u64 si_guid;
+       u32 cap_mask;
+};
+
+int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
+int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm);
+int mlx4_UNMAP_FA(struct mlx4_dev *dev);
+int mlx4_RUN_FW(struct mlx4_dev *dev);
+int mlx4_QUERY_FW(struct mlx4_dev *dev);
+int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter);
+int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param);
+int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic);
+int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt);
+int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages);
+int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
+int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
+int mlx4_NOP(struct mlx4_dev *dev);
+
+#endif /* MLX4_FW_H */
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
new file mode 100644 (file)
index 0000000..e96feae
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+#include "icm.h"
+#include "fw.h"
+
+/*
+ * We allocate in as big chunks as we can, up to a maximum of 256 KB
+ * per chunk.
+ */
+enum {
+       MLX4_ICM_ALLOC_SIZE     = 1 << 18,
+       MLX4_TABLE_CHUNK_SIZE   = 1 << 18
+};
+
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
+{
+       struct mlx4_icm_chunk *chunk, *tmp;
+       int i;
+
+       list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
+               if (chunk->nsg > 0)
+                       pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+                                    PCI_DMA_BIDIRECTIONAL);
+
+               for (i = 0; i < chunk->npages; ++i)
+                       __free_pages(chunk->mem[i].page,
+                                    get_order(chunk->mem[i].length));
+
+               kfree(chunk);
+       }
+
+       kfree(icm);
+}
+
+struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
+                               gfp_t gfp_mask)
+{
+       struct mlx4_icm *icm;
+       struct mlx4_icm_chunk *chunk = NULL;
+       int cur_order;
+
+       icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
+       if (!icm)
+               return icm;
+
+       icm->refcount = 0;
+       INIT_LIST_HEAD(&icm->chunk_list);
+
+       cur_order = get_order(MLX4_ICM_ALLOC_SIZE);
+
+       while (npages > 0) {
+               if (!chunk) {
+                       chunk = kmalloc(sizeof *chunk,
+                                       gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
+                       if (!chunk)
+                               goto fail;
+
+                       chunk->npages = 0;
+                       chunk->nsg    = 0;
+                       list_add_tail(&chunk->list, &icm->chunk_list);
+               }
+
+               while (1 << cur_order > npages)
+                       --cur_order;
+
+               chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order);
+               if (chunk->mem[chunk->npages].page) {
+                       chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order;
+                       chunk->mem[chunk->npages].offset = 0;
+
+                       if (++chunk->npages == MLX4_ICM_CHUNK_LEN) {
+                               chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
+                                                       chunk->npages,
+                                                       PCI_DMA_BIDIRECTIONAL);
+
+                               if (chunk->nsg <= 0)
+                                       goto fail;
+
+                               chunk = NULL;
+                       }
+
+                       npages -= 1 << cur_order;
+               } else {
+                       --cur_order;
+                       if (cur_order < 0)
+                               goto fail;
+               }
+       }
+
+       if (chunk) {
+               chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
+                                       chunk->npages,
+                                       PCI_DMA_BIDIRECTIONAL);
+
+               if (chunk->nsg <= 0)
+                       goto fail;
+       }
+
+       return icm;
+
+fail:
+       mlx4_free_icm(dev, icm);
+       return NULL;
+}
+
+static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt)
+{
+       return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt);
+}
+
+int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count)
+{
+       return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM,
+                       MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       __be64 *inbox;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       inbox = mailbox->buf;
+
+       inbox[0] = cpu_to_be64(virt);
+       inbox[1] = cpu_to_be64(dma_addr);
+
+       err = mlx4_cmd(dev, mailbox->dma, 1, 0, MLX4_CMD_MAP_ICM,
+                      MLX4_CMD_TIME_CLASS_B);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+       if (!err)
+               mlx4_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
+                         (unsigned long long) dma_addr, (unsigned long long) virt);
+
+       return err;
+}
+
+int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm)
+{
+       return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, -1);
+}
+
+int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev)
+{
+       return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_ICM_AUX, MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
+{
+       int i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+       int ret = 0;
+
+       mutex_lock(&table->mutex);
+
+       if (table->icm[i]) {
+               ++table->icm[i]->refcount;
+               goto out;
+       }
+
+       table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
+                                      (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
+                                      __GFP_NOWARN);
+       if (!table->icm[i]) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (mlx4_MAP_ICM(dev, table->icm[i], table->virt +
+                        (u64) i * MLX4_TABLE_CHUNK_SIZE)) {
+               mlx4_free_icm(dev, table->icm[i]);
+               table->icm[i] = NULL;
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ++table->icm[i]->refcount;
+
+out:
+       mutex_unlock(&table->mutex);
+       return ret;
+}
+
+void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
+{
+       int i;
+
+       i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+
+       mutex_lock(&table->mutex);
+
+       if (--table->icm[i]->refcount == 0) {
+               mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
+                              MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
+               mlx4_free_icm(dev, table->icm[i]);
+               table->icm[i] = NULL;
+       }
+
+       mutex_unlock(&table->mutex);
+}
+
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
+{
+       int idx, offset, i;
+       struct mlx4_icm_chunk *chunk;
+       struct mlx4_icm *icm;
+       struct page *page = NULL;
+
+       if (!table->lowmem)
+               return NULL;
+
+       mutex_lock(&table->mutex);
+
+       idx = obj & (table->num_obj - 1);
+       icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)];
+       offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+
+       if (!icm)
+               goto out;
+
+       list_for_each_entry(chunk, &icm->chunk_list, list) {
+               for (i = 0; i < chunk->npages; ++i) {
+                       if (chunk->mem[i].length > offset) {
+                               page = chunk->mem[i].page;
+                               goto out;
+                       }
+                       offset -= chunk->mem[i].length;
+               }
+       }
+
+out:
+       mutex_unlock(&table->mutex);
+       return page ? lowmem_page_address(page) + offset : NULL;
+}
+
+int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                        int start, int end)
+{
+       int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size;
+       int i, err;
+
+       for (i = start; i <= end; i += inc) {
+               err = mlx4_table_get(dev, table, i);
+               if (err)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       while (i > start) {
+               i -= inc;
+               mlx4_table_put(dev, table, i);
+       }
+
+       return err;
+}
+
+void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                         int start, int end)
+{
+       int i;
+
+       for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size)
+               mlx4_table_put(dev, table, i);
+}
+
+int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                       u64 virt, int obj_size, int nobj, int reserved,
+                       int use_lowmem)
+{
+       int obj_per_chunk;
+       int num_icm;
+       unsigned chunk_size;
+       int i;
+
+       obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size;
+       num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+
+       table->icm      = kcalloc(num_icm, sizeof *table->icm, GFP_KERNEL);
+       if (!table->icm)
+               return -ENOMEM;
+       table->virt     = virt;
+       table->num_icm  = num_icm;
+       table->num_obj  = nobj;
+       table->obj_size = obj_size;
+       table->lowmem   = use_lowmem;
+       mutex_init(&table->mutex);
+
+       for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
+               chunk_size = MLX4_TABLE_CHUNK_SIZE;
+               if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > nobj * obj_size)
+                       chunk_size = PAGE_ALIGN(nobj * obj_size - i * MLX4_TABLE_CHUNK_SIZE);
+
+               table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
+                                              (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
+                                              __GFP_NOWARN);
+               if (!table->icm[i])
+                       goto err;
+               if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) {
+                       mlx4_free_icm(dev, table->icm[i]);
+                       table->icm[i] = NULL;
+                       goto err;
+               }
+
+               /*
+                * Add a reference to this ICM chunk so that it never
+                * gets freed (since it contains reserved firmware objects).
+                */
+               ++table->icm[i]->refcount;
+       }
+
+       return 0;
+
+err:
+       for (i = 0; i < num_icm; ++i)
+               if (table->icm[i]) {
+                       mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE,
+                                      MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
+                       mlx4_free_icm(dev, table->icm[i]);
+               }
+
+       return -ENOMEM;
+}
+
+void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table)
+{
+       int i;
+
+       for (i = 0; i < table->num_icm; ++i)
+               if (table->icm[i]) {
+                       mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
+                                      MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
+                       mlx4_free_icm(dev, table->icm[i]);
+               }
+
+       kfree(table->icm);
+}
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h
new file mode 100644 (file)
index 0000000..bea223d
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_ICM_H
+#define MLX4_ICM_H
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#define MLX4_ICM_CHUNK_LEN                                             \
+       ((256 - sizeof (struct list_head) - 2 * sizeof (int)) /         \
+        (sizeof (struct scatterlist)))
+
+enum {
+       MLX4_ICM_PAGE_SHIFT     = 12,
+       MLX4_ICM_PAGE_SIZE      = 1 << MLX4_ICM_PAGE_SHIFT,
+};
+
+struct mlx4_icm_chunk {
+       struct list_head        list;
+       int                     npages;
+       int                     nsg;
+       struct scatterlist      mem[MLX4_ICM_CHUNK_LEN];
+};
+
+struct mlx4_icm {
+       struct list_head        chunk_list;
+       int                     refcount;
+};
+
+struct mlx4_icm_iter {
+       struct mlx4_icm        *icm;
+       struct mlx4_icm_chunk  *chunk;
+       int                     page_idx;
+};
+
+struct mlx4_dev;
+
+struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask);
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm);
+
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
+void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
+int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                        int start, int end);
+void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                         int start, int end);
+int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                       u64 virt, int obj_size, int nobj, int reserved,
+                       int use_lowmem);
+void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
+int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
+void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj);
+int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                        int start, int end);
+void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
+                         int start, int end);
+
+static inline void mlx4_icm_first(struct mlx4_icm *icm,
+                                 struct mlx4_icm_iter *iter)
+{
+       iter->icm      = icm;
+       iter->chunk    = list_empty(&icm->chunk_list) ?
+               NULL : list_entry(icm->chunk_list.next,
+                                 struct mlx4_icm_chunk, list);
+       iter->page_idx = 0;
+}
+
+static inline int mlx4_icm_last(struct mlx4_icm_iter *iter)
+{
+       return !iter->chunk;
+}
+
+static inline void mlx4_icm_next(struct mlx4_icm_iter *iter)
+{
+       if (++iter->page_idx >= iter->chunk->nsg) {
+               if (iter->chunk->list.next == &iter->icm->chunk_list) {
+                       iter->chunk = NULL;
+                       return;
+               }
+
+               iter->chunk = list_entry(iter->chunk->list.next,
+                                        struct mlx4_icm_chunk, list);
+               iter->page_idx = 0;
+       }
+}
+
+static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter)
+{
+       return sg_dma_address(&iter->chunk->mem[iter->page_idx]);
+}
+
+static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter)
+{
+       return sg_dma_len(&iter->chunk->mem[iter->page_idx]);
+}
+
+int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count);
+int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt);
+int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm);
+int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev);
+
+#endif /* MLX4_ICM_H */
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c
new file mode 100644 (file)
index 0000000..65854f9
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/mlx4/driver.h>
+
+#include "mlx4.h"
+
+struct mlx4_device_context {
+       struct list_head        list;
+       struct mlx4_interface  *intf;
+       void                   *context;
+};
+
+static LIST_HEAD(intf_list);
+static LIST_HEAD(dev_list);
+static DEFINE_MUTEX(intf_mutex);
+
+static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
+{
+       struct mlx4_device_context *dev_ctx;
+
+       dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL);
+       if (!dev_ctx)
+               return;
+
+       dev_ctx->intf    = intf;
+       dev_ctx->context = intf->add(&priv->dev);
+
+       if (dev_ctx->context) {
+               spin_lock_irq(&priv->ctx_lock);
+               list_add_tail(&dev_ctx->list, &priv->ctx_list);
+               spin_unlock_irq(&priv->ctx_lock);
+       } else
+               kfree(dev_ctx);
+}
+
+static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv)
+{
+       struct mlx4_device_context *dev_ctx;
+
+       list_for_each_entry(dev_ctx, &priv->ctx_list, list)
+               if (dev_ctx->intf == intf) {
+                       spin_lock_irq(&priv->ctx_lock);
+                       list_del(&dev_ctx->list);
+                       spin_unlock_irq(&priv->ctx_lock);
+
+                       intf->remove(&priv->dev, dev_ctx->context);
+                       kfree(dev_ctx);
+                       return;
+               }
+}
+
+int mlx4_register_interface(struct mlx4_interface *intf)
+{
+       struct mlx4_priv *priv;
+
+       if (!intf->add || !intf->remove)
+               return -EINVAL;
+
+       mutex_lock(&intf_mutex);
+
+       list_add_tail(&intf->list, &intf_list);
+       list_for_each_entry(priv, &dev_list, dev_list)
+               mlx4_add_device(intf, priv);
+
+       mutex_unlock(&intf_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_register_interface);
+
+void mlx4_unregister_interface(struct mlx4_interface *intf)
+{
+       struct mlx4_priv *priv;
+
+       mutex_lock(&intf_mutex);
+
+       list_for_each_entry(priv, &dev_list, dev_list)
+               mlx4_remove_device(intf, priv);
+
+       list_del(&intf->list);
+
+       mutex_unlock(&intf_mutex);
+}
+EXPORT_SYMBOL_GPL(mlx4_unregister_interface);
+
+void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
+                        int subtype, int port)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_device_context *dev_ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->ctx_lock, flags);
+
+       list_for_each_entry(dev_ctx, &priv->ctx_list, list)
+               if (dev_ctx->intf->event)
+                       dev_ctx->intf->event(dev, dev_ctx->context, type,
+                                            subtype, port);
+
+       spin_unlock_irqrestore(&priv->ctx_lock, flags);
+}
+
+int mlx4_register_device(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_interface *intf;
+
+       INIT_LIST_HEAD(&priv->ctx_list);
+       spin_lock_init(&priv->ctx_lock);
+
+       mutex_lock(&intf_mutex);
+
+       list_add_tail(&priv->dev_list, &dev_list);
+       list_for_each_entry(intf, &intf_list, list)
+               mlx4_add_device(intf, priv);
+
+       mutex_unlock(&intf_mutex);
+
+       return 0;
+}
+
+void mlx4_unregister_device(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_interface *intf;
+
+       mutex_lock(&intf_mutex);
+
+       list_for_each_entry(intf, &intf_list, list)
+               mlx4_remove_device(intf, priv);
+
+       list_del(&priv->dev_list);
+
+       mutex_unlock(&intf_mutex);
+}
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
new file mode 100644 (file)
index 0000000..4debb02
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/doorbell.h>
+
+#include "mlx4.h"
+#include "fw.h"
+#include "icm.h"
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("Mellanox ConnectX HCA low-level driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#ifdef CONFIG_MLX4_DEBUG
+
+int mlx4_debug_level = 0;
+module_param_named(debug_level, mlx4_debug_level, int, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
+
+#endif /* CONFIG_MLX4_DEBUG */
+
+#ifdef CONFIG_PCI_MSI
+
+static int msi_x;
+module_param(msi_x, int, 0444);
+MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
+
+#else /* CONFIG_PCI_MSI */
+
+#define msi_x (0)
+
+#endif /* CONFIG_PCI_MSI */
+
+static const char mlx4_version[] __devinitdata =
+       DRV_NAME ": Mellanox ConnectX core driver v"
+       DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static struct mlx4_profile default_profile = {
+       .num_qp         = 1 << 16,
+       .num_srq        = 1 << 16,
+       .rdmarc_per_qp  = 4,
+       .num_cq         = 1 << 16,
+       .num_mcg        = 1 << 13,
+       .num_mpt        = 1 << 17,
+       .num_mtt        = 1 << 20,
+};
+
+static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+{
+       int err;
+
+       err = mlx4_QUERY_DEV_CAP(dev, dev_cap);
+       if (err) {
+               mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
+               return err;
+       }
+
+       if (dev_cap->min_page_sz > PAGE_SIZE) {
+               mlx4_err(dev, "HCA minimum page size of %d bigger than "
+                        "kernel PAGE_SIZE of %ld, aborting.\n",
+                        dev_cap->min_page_sz, PAGE_SIZE);
+               return -ENODEV;
+       }
+       if (dev_cap->num_ports > MLX4_MAX_PORTS) {
+               mlx4_err(dev, "HCA has %d ports, but we only support %d, "
+                        "aborting.\n",
+                        dev_cap->num_ports, MLX4_MAX_PORTS);
+               return -ENODEV;
+       }
+
+       if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) {
+               mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than "
+                        "PCI resource 2 size of 0x%llx, aborting.\n",
+                        dev_cap->uar_size,
+                        (unsigned long long) pci_resource_len(dev->pdev, 2));
+               return -ENODEV;
+       }
+
+       dev->caps.num_ports          = dev_cap->num_ports;
+       dev->caps.num_uars           = dev_cap->uar_size / PAGE_SIZE;
+       dev->caps.vl_cap             = dev_cap->max_vl;
+       dev->caps.mtu_cap            = dev_cap->max_mtu;
+       dev->caps.gid_table_len      = dev_cap->max_gids;
+       dev->caps.pkey_table_len     = dev_cap->max_pkeys;
+       dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay;
+       dev->caps.bf_reg_size        = dev_cap->bf_reg_size;
+       dev->caps.bf_regs_per_page   = dev_cap->bf_regs_per_page;
+       dev->caps.max_sq_sg          = dev_cap->max_sq_sg;
+       dev->caps.max_rq_sg          = dev_cap->max_rq_sg;
+       dev->caps.max_wqes           = dev_cap->max_qp_sz;
+       dev->caps.max_qp_init_rdma   = dev_cap->max_requester_per_qp;
+       dev->caps.reserved_qps       = dev_cap->reserved_qps;
+       dev->caps.max_srq_wqes       = dev_cap->max_srq_sz;
+       dev->caps.max_srq_sge        = dev_cap->max_rq_sg - 1;
+       dev->caps.reserved_srqs      = dev_cap->reserved_srqs;
+       dev->caps.max_sq_desc_sz     = dev_cap->max_sq_desc_sz;
+       dev->caps.max_rq_desc_sz     = dev_cap->max_rq_desc_sz;
+       dev->caps.num_qp_per_mgm     = MLX4_QP_PER_MGM;
+       /*
+        * Subtract 1 from the limit because we need to allocate a
+        * spare CQE so the HCA HW can tell the difference between an
+        * empty CQ and a full CQ.
+        */
+       dev->caps.max_cqes           = dev_cap->max_cq_sz - 1;
+       dev->caps.reserved_cqs       = dev_cap->reserved_cqs;
+       dev->caps.reserved_eqs       = dev_cap->reserved_eqs;
+       dev->caps.reserved_mtts      = dev_cap->reserved_mtts;
+       dev->caps.reserved_mrws      = dev_cap->reserved_mrws;
+       dev->caps.reserved_uars      = dev_cap->reserved_uars;
+       dev->caps.reserved_pds       = dev_cap->reserved_pds;
+       dev->caps.port_width_cap     = dev_cap->max_port_width;
+       dev->caps.mtt_entry_sz       = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz;
+       dev->caps.page_size_cap      = ~(u32) (dev_cap->min_page_sz - 1);
+       dev->caps.flags              = dev_cap->flags;
+       dev->caps.stat_rate_support  = dev_cap->stat_rate_support;
+
+       return 0;
+}
+
+static int __devinit mlx4_load_fw(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+
+       priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,
+                                        GFP_HIGHUSER | __GFP_NOWARN);
+       if (!priv->fw.fw_icm) {
+               mlx4_err(dev, "Couldn't allocate FW area, aborting.\n");
+               return -ENOMEM;
+       }
+
+       err = mlx4_MAP_FA(dev, priv->fw.fw_icm);
+       if (err) {
+               mlx4_err(dev, "MAP_FA command failed, aborting.\n");
+               goto err_free;
+       }
+
+       err = mlx4_RUN_FW(dev);
+       if (err) {
+               mlx4_err(dev, "RUN_FW command failed, aborting.\n");
+               goto err_unmap_fa;
+       }
+
+       return 0;
+
+err_unmap_fa:
+       mlx4_UNMAP_FA(dev);
+
+err_free:
+       mlx4_free_icm(dev, priv->fw.fw_icm);
+       return err;
+}
+
+static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
+                                         int cmpt_entry_sz)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+
+       err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table,
+                                 cmpt_base +
+                                 ((u64) (MLX4_CMPT_TYPE_QP *
+                                         cmpt_entry_sz) << MLX4_CMPT_SHIFT),
+                                 cmpt_entry_sz, dev->caps.num_qps,
+                                 dev->caps.reserved_qps, 0);
+       if (err)
+               goto err;
+
+       err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table,
+                                 cmpt_base +
+                                 ((u64) (MLX4_CMPT_TYPE_SRQ *
+                                         cmpt_entry_sz) << MLX4_CMPT_SHIFT),
+                                 cmpt_entry_sz, dev->caps.num_srqs,
+                                 dev->caps.reserved_srqs, 0);
+       if (err)
+               goto err_qp;
+
+       err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table,
+                                 cmpt_base +
+                                 ((u64) (MLX4_CMPT_TYPE_CQ *
+                                         cmpt_entry_sz) << MLX4_CMPT_SHIFT),
+                                 cmpt_entry_sz, dev->caps.num_cqs,
+                                 dev->caps.reserved_cqs, 0);
+       if (err)
+               goto err_srq;
+
+       err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table,
+                                 cmpt_base +
+                                 ((u64) (MLX4_CMPT_TYPE_EQ *
+                                         cmpt_entry_sz) << MLX4_CMPT_SHIFT),
+                                 cmpt_entry_sz,
+                                 roundup_pow_of_two(MLX4_NUM_EQ +
+                                                    dev->caps.reserved_eqs),
+                                 MLX4_NUM_EQ + dev->caps.reserved_eqs, 0);
+       if (err)
+               goto err_cq;
+
+       return 0;
+
+err_cq:
+       mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
+
+err_srq:
+       mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
+
+err_qp:
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
+
+err:
+       return err;
+}
+
+static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
+                                  struct mlx4_dev_cap *dev_cap,
+                                  struct mlx4_init_hca_param *init_hca,
+                                  u64 icm_size)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       u64 aux_pages;
+       int err;
+
+       err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages);
+       if (err) {
+               mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n");
+               return err;
+       }
+
+       mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n",
+                (unsigned long long) icm_size >> 10,
+                (unsigned long long) aux_pages << 2);
+
+       priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages,
+                                         GFP_HIGHUSER | __GFP_NOWARN);
+       if (!priv->fw.aux_icm) {
+               mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n");
+               return -ENOMEM;
+       }
+
+       err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm);
+       if (err) {
+               mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n");
+               goto err_free_aux;
+       }
+
+       err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz);
+       if (err) {
+               mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n");
+               goto err_unmap_aux;
+       }
+
+       err = mlx4_map_eq_icm(dev, init_hca->eqc_base);
+       if (err) {
+               mlx4_err(dev, "Failed to map EQ context memory, aborting.\n");
+               goto err_unmap_cmpt;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table,
+                                 init_hca->mtt_base,
+                                 dev->caps.mtt_entry_sz,
+                                 dev->caps.num_mtt_segs,
+                                 dev->caps.reserved_mtts, 1);
+       if (err) {
+               mlx4_err(dev, "Failed to map MTT context memory, aborting.\n");
+               goto err_unmap_eq;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table,
+                                 init_hca->dmpt_base,
+                                 dev_cap->dmpt_entry_sz,
+                                 dev->caps.num_mpts,
+                                 dev->caps.reserved_mrws, 1);
+       if (err) {
+               mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n");
+               goto err_unmap_mtt;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table,
+                                 init_hca->qpc_base,
+                                 dev_cap->qpc_entry_sz,
+                                 dev->caps.num_qps,
+                                 dev->caps.reserved_qps, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
+               goto err_unmap_dmpt;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table,
+                                 init_hca->auxc_base,
+                                 dev_cap->aux_entry_sz,
+                                 dev->caps.num_qps,
+                                 dev->caps.reserved_qps, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
+               goto err_unmap_qp;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table,
+                                 init_hca->altc_base,
+                                 dev_cap->altc_entry_sz,
+                                 dev->caps.num_qps,
+                                 dev->caps.reserved_qps, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
+               goto err_unmap_auxc;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table,
+                                 init_hca->rdmarc_base,
+                                 dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
+                                 dev->caps.num_qps,
+                                 dev->caps.reserved_qps, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
+               goto err_unmap_altc;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->cq_table.table,
+                                 init_hca->cqc_base,
+                                 dev_cap->cqc_entry_sz,
+                                 dev->caps.num_cqs,
+                                 dev->caps.reserved_cqs, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map CQ context memory, aborting.\n");
+               goto err_unmap_rdmarc;
+       }
+
+       err = mlx4_init_icm_table(dev, &priv->srq_table.table,
+                                 init_hca->srqc_base,
+                                 dev_cap->srq_entry_sz,
+                                 dev->caps.num_srqs,
+                                 dev->caps.reserved_srqs, 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n");
+               goto err_unmap_cq;
+       }
+
+       /*
+        * It's not strictly required, but for simplicity just map the
+        * whole multicast group table now.  The table isn't very big
+        * and it's a lot easier than trying to track ref counts.
+        */
+       err = mlx4_init_icm_table(dev, &priv->mcg_table.table,
+                                 init_hca->mc_base, MLX4_MGM_ENTRY_SIZE,
+                                 dev->caps.num_mgms + dev->caps.num_amgms,
+                                 dev->caps.num_mgms + dev->caps.num_amgms,
+                                 0);
+       if (err) {
+               mlx4_err(dev, "Failed to map MCG context memory, aborting.\n");
+               goto err_unmap_srq;
+       }
+
+       return 0;
+
+err_unmap_srq:
+       mlx4_cleanup_icm_table(dev, &priv->srq_table.table);
+
+err_unmap_cq:
+       mlx4_cleanup_icm_table(dev, &priv->cq_table.table);
+
+err_unmap_rdmarc:
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table);
+
+err_unmap_altc:
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table);
+
+err_unmap_auxc:
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table);
+
+err_unmap_qp:
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
+
+err_unmap_dmpt:
+       mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
+
+err_unmap_mtt:
+       mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
+
+err_unmap_eq:
+       mlx4_unmap_eq_icm(dev);
+
+err_unmap_cmpt:
+       mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
+
+err_unmap_aux:
+       mlx4_UNMAP_ICM_AUX(dev);
+
+err_free_aux:
+       mlx4_free_icm(dev, priv->fw.aux_icm);
+
+       return err;
+}
+
+static void mlx4_free_icms(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       mlx4_cleanup_icm_table(dev, &priv->mcg_table.table);
+       mlx4_cleanup_icm_table(dev, &priv->srq_table.table);
+       mlx4_cleanup_icm_table(dev, &priv->cq_table.table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
+       mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
+       mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
+       mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
+       mlx4_unmap_eq_icm(dev);
+
+       mlx4_UNMAP_ICM_AUX(dev);
+       mlx4_free_icm(dev, priv->fw.aux_icm);
+}
+
+static void mlx4_close_hca(struct mlx4_dev *dev)
+{
+       mlx4_CLOSE_HCA(dev, 0);
+       mlx4_free_icms(dev);
+       mlx4_UNMAP_FA(dev);
+       mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm);
+}
+
+static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
+{
+       struct mlx4_priv          *priv = mlx4_priv(dev);
+       struct mlx4_adapter        adapter;
+       struct mlx4_dev_cap        dev_cap;
+       struct mlx4_profile        profile;
+       struct mlx4_init_hca_param init_hca;
+       u64 icm_size;
+       int err;
+
+       err = mlx4_QUERY_FW(dev);
+       if (err) {
+               mlx4_err(dev, "QUERY_FW command failed, aborting.\n");
+               return err;
+       }
+
+       err = mlx4_load_fw(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to start FW, aborting.\n");
+               return err;
+       }
+
+       err = mlx4_dev_cap(dev, &dev_cap);
+       if (err) {
+               mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n");
+               goto err_stop_fw;
+       }
+
+       profile = default_profile;
+
+       icm_size = mlx4_make_profile(dev, &profile, &dev_cap, &init_hca);
+       if ((long long) icm_size < 0) {
+               err = icm_size;
+               goto err_stop_fw;
+       }
+
+       init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
+
+       err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size);
+       if (err)
+               goto err_stop_fw;
+
+       err = mlx4_INIT_HCA(dev, &init_hca);
+       if (err) {
+               mlx4_err(dev, "INIT_HCA command failed, aborting.\n");
+               goto err_free_icm;
+       }
+
+       err = mlx4_QUERY_ADAPTER(dev, &adapter);
+       if (err) {
+               mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n");
+               goto err_close;
+       }
+
+       priv->eq_table.inta_pin = adapter.inta_pin;
+       priv->rev_id            = adapter.revision_id;
+       memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id);
+
+       return 0;
+
+err_close:
+       mlx4_close_hca(dev);
+
+err_free_icm:
+       mlx4_free_icms(dev);
+
+err_stop_fw:
+       mlx4_UNMAP_FA(dev);
+       mlx4_free_icm(dev, priv->fw.fw_icm);
+
+       return err;
+}
+
+static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+
+       MLX4_INIT_DOORBELL_LOCK(&priv->doorbell_lock);
+
+       err = mlx4_init_uar_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "user access region table, aborting.\n");
+               return err;
+       }
+
+       err = mlx4_uar_alloc(dev, &priv->driver_uar);
+       if (err) {
+               mlx4_err(dev, "Failed to allocate driver access region, "
+                        "aborting.\n");
+               goto err_uar_table_free;
+       }
+
+       priv->kar = ioremap(priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+       if (!priv->kar) {
+               mlx4_err(dev, "Couldn't map kernel access region, "
+                        "aborting.\n");
+               err = -ENOMEM;
+               goto err_uar_free;
+       }
+
+       err = mlx4_init_pd_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "protection domain table, aborting.\n");
+               goto err_kar_unmap;
+       }
+
+       err = mlx4_init_mr_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "memory region table, aborting.\n");
+               goto err_pd_table_free;
+       }
+
+       mlx4_map_catas_buf(dev);
+
+       err = mlx4_init_eq_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "event queue table, aborting.\n");
+               goto err_catas_buf;
+       }
+
+       err = mlx4_cmd_use_events(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to switch to event-driven "
+                        "firmware commands, aborting.\n");
+               goto err_eq_table_free;
+       }
+
+       err = mlx4_NOP(dev);
+       if (err) {
+               mlx4_err(dev, "NOP command failed to generate interrupt "
+                        "(IRQ %d), aborting.\n",
+                        priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+               if (dev->flags & MLX4_FLAG_MSI_X)
+                       mlx4_err(dev, "Try again with MSI-X disabled.\n");
+               else
+                       mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+
+               goto err_cmd_poll;
+       }
+
+       mlx4_dbg(dev, "NOP command IRQ test passed\n");
+
+       err = mlx4_init_cq_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "completion queue table, aborting.\n");
+               goto err_cmd_poll;
+       }
+
+       err = mlx4_init_srq_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "shared receive queue table, aborting.\n");
+               goto err_cq_table_free;
+       }
+
+       err = mlx4_init_qp_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "queue pair table, aborting.\n");
+               goto err_srq_table_free;
+       }
+
+       err = mlx4_init_mcg_table(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to initialize "
+                        "multicast group table, aborting.\n");
+               goto err_qp_table_free;
+       }
+
+       return 0;
+
+err_qp_table_free:
+       mlx4_cleanup_qp_table(dev);
+
+err_srq_table_free:
+       mlx4_cleanup_srq_table(dev);
+
+err_cq_table_free:
+       mlx4_cleanup_cq_table(dev);
+
+err_cmd_poll:
+       mlx4_cmd_use_polling(dev);
+
+err_eq_table_free:
+       mlx4_cleanup_eq_table(dev);
+
+err_catas_buf:
+       mlx4_unmap_catas_buf(dev);
+       mlx4_cleanup_mr_table(dev);
+
+err_pd_table_free:
+       mlx4_cleanup_pd_table(dev);
+
+err_kar_unmap:
+       iounmap(priv->kar);
+
+err_uar_free:
+       mlx4_uar_free(dev, &priv->driver_uar);
+
+err_uar_table_free:
+       mlx4_cleanup_uar_table(dev);
+       return err;
+}
+
+static void __devinit mlx4_enable_msi_x(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct msix_entry entries[MLX4_NUM_EQ];
+       int err;
+       int i;
+
+       if (msi_x) {
+               for (i = 0; i < MLX4_NUM_EQ; ++i)
+                       entries[i].entry = i;
+
+               err = pci_enable_msix(dev->pdev, entries, ARRAY_SIZE(entries));
+               if (err) {
+                       if (err > 0)
+                               mlx4_info(dev, "Only %d MSI-X vectors available, "
+                                         "not using MSI-X\n", err);
+                       goto no_msi;
+               }
+
+               for (i = 0; i < MLX4_NUM_EQ; ++i)
+                       priv->eq_table.eq[i].irq = entries[i].vector;
+
+               dev->flags |= MLX4_FLAG_MSI_X;
+               return;
+       }
+
+no_msi:
+       for (i = 0; i < MLX4_NUM_EQ; ++i)
+               priv->eq_table.eq[i].irq = dev->pdev->irq;
+}
+
+static int __devinit mlx4_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *id)
+{
+       static int mlx4_version_printed;
+       struct mlx4_priv *priv;
+       struct mlx4_dev *dev;
+       int err;
+
+       if (!mlx4_version_printed) {
+               printk(KERN_INFO "%s", mlx4_version);
+               ++mlx4_version_printed;
+       }
+
+       printk(KERN_INFO PFX "Initializing %s\n",
+              pci_name(pdev));
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot enable PCI device, "
+                       "aborting.\n");
+               return err;
+       }
+
+       /*
+        * Check for BARs.  We expect 0: 1MB, 2: 8MB, 4: DDR (may not
+        * be present)
+        */
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+           pci_resource_len(pdev, 0) != 1 << 20) {
+               dev_err(&pdev->dev, "Missing DCS, aborting.\n");
+               err = -ENODEV;
+               goto err_disable_pdev;
+       }
+       if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+               dev_err(&pdev->dev, "Missing UAR, aborting.\n");
+               err = -ENODEV;
+               goto err_disable_pdev;
+       }
+
+       err = pci_request_region(pdev, 0, DRV_NAME);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot request control region, aborting.\n");
+               goto err_disable_pdev;
+       }
+
+       err = pci_request_region(pdev, 2, DRV_NAME);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot request UAR region, aborting.\n");
+               goto err_release_bar0;
+       }
+
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+       if (err) {
+               dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n");
+               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (err) {
+                       dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n");
+                       goto err_release_bar2;
+               }
+       }
+       err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+       if (err) {
+               dev_warn(&pdev->dev, "Warning: couldn't set 64-bit "
+                        "consistent PCI DMA mask.\n");
+               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               if (err) {
+                       dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, "
+                               "aborting.\n");
+                       goto err_release_bar2;
+               }
+       }
+
+       priv = kzalloc(sizeof *priv, GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "Device struct alloc failed, "
+                       "aborting.\n");
+               err = -ENOMEM;
+               goto err_release_bar2;
+       }
+
+       dev       = &priv->dev;
+       dev->pdev = pdev;
+
+       /*
+        * Now reset the HCA before we touch the PCI capabilities or
+        * attempt a firmware command, since a boot ROM may have left
+        * the HCA in an undefined state.
+        */
+       err = mlx4_reset(dev);
+       if (err) {
+               mlx4_err(dev, "Failed to reset HCA, aborting.\n");
+               goto err_free_dev;
+       }
+
+       mlx4_enable_msi_x(dev);
+
+       if (mlx4_cmd_init(dev)) {
+               mlx4_err(dev, "Failed to init command interface, aborting.\n");
+               goto err_free_dev;
+       }
+
+       err = mlx4_init_hca(dev);
+       if (err)
+               goto err_cmd;
+
+       err = mlx4_setup_hca(dev);
+       if (err)
+               goto err_close;
+
+       err = mlx4_register_device(dev);
+       if (err)
+               goto err_cleanup;
+
+       pci_set_drvdata(pdev, dev);
+
+       return 0;
+
+err_cleanup:
+       mlx4_cleanup_mcg_table(dev);
+       mlx4_cleanup_qp_table(dev);
+       mlx4_cleanup_srq_table(dev);
+       mlx4_cleanup_cq_table(dev);
+       mlx4_cmd_use_polling(dev);
+       mlx4_cleanup_eq_table(dev);
+
+       mlx4_unmap_catas_buf(dev);
+
+       mlx4_cleanup_mr_table(dev);
+       mlx4_cleanup_pd_table(dev);
+       mlx4_cleanup_uar_table(dev);
+
+err_close:
+       mlx4_close_hca(dev);
+
+err_cmd:
+       mlx4_cmd_cleanup(dev);
+
+err_free_dev:
+       if (dev->flags & MLX4_FLAG_MSI_X)
+               pci_disable_msix(pdev);
+
+       kfree(priv);
+
+err_release_bar2:
+       pci_release_region(pdev, 2);
+
+err_release_bar0:
+       pci_release_region(pdev, 0);
+
+err_disable_pdev:
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return err;
+}
+
+static void __devexit mlx4_remove_one(struct pci_dev *pdev)
+{
+       struct mlx4_dev  *dev  = pci_get_drvdata(pdev);
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int p;
+
+       if (dev) {
+               mlx4_unregister_device(dev);
+
+               for (p = 1; p <= dev->caps.num_ports; ++p)
+                       mlx4_CLOSE_PORT(dev, p);
+
+               mlx4_cleanup_mcg_table(dev);
+               mlx4_cleanup_qp_table(dev);
+               mlx4_cleanup_srq_table(dev);
+               mlx4_cleanup_cq_table(dev);
+               mlx4_cmd_use_polling(dev);
+               mlx4_cleanup_eq_table(dev);
+
+               mlx4_unmap_catas_buf(dev);
+
+               mlx4_cleanup_mr_table(dev);
+               mlx4_cleanup_pd_table(dev);
+
+               iounmap(priv->kar);
+               mlx4_uar_free(dev, &priv->driver_uar);
+               mlx4_cleanup_uar_table(dev);
+               mlx4_close_hca(dev);
+               mlx4_cmd_cleanup(dev);
+
+               if (dev->flags & MLX4_FLAG_MSI_X)
+                       pci_disable_msix(pdev);
+
+               kfree(priv);
+               pci_release_region(pdev, 2);
+               pci_release_region(pdev, 0);
+               pci_disable_device(pdev);
+               pci_set_drvdata(pdev, NULL);
+       }
+}
+
+static struct pci_device_id mlx4_pci_table[] = {
+       { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
+       { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
+       { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
+
+static struct pci_driver mlx4_driver = {
+       .name           = DRV_NAME,
+       .id_table       = mlx4_pci_table,
+       .probe          = mlx4_init_one,
+       .remove         = __devexit_p(mlx4_remove_one)
+};
+
+static int __init mlx4_init(void)
+{
+       int ret;
+
+       ret = pci_register_driver(&mlx4_driver);
+       return ret < 0 ? ret : 0;
+}
+
+static void __exit mlx4_cleanup(void)
+{
+       pci_unregister_driver(&mlx4_driver);
+}
+
+module_init(mlx4_init);
+module_exit(mlx4_cleanup);
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
new file mode 100644 (file)
index 0000000..672024a
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+
+struct mlx4_mgm {
+       __be32                  next_gid_index;
+       __be32                  members_count;
+       u32                     reserved[2];
+       u8                      gid[16];
+       __be32                  qp[MLX4_QP_PER_MGM];
+};
+
+static const u8 zero_gid[16];  /* automatically initialized to 0 */
+
+static int mlx4_READ_MCG(struct mlx4_dev *dev, int index,
+                        struct mlx4_cmd_mailbox *mailbox)
+{
+       return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
+                           MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index,
+                         struct mlx4_cmd_mailbox *mailbox)
+{
+       return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
+                       MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         u16 *hash)
+{
+       u64 imm;
+       int err;
+
+       err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH,
+                          MLX4_CMD_TIME_CLASS_A);
+
+       if (!err)
+               *hash = imm;
+
+       return err;
+}
+
+/*
+ * Caller must hold MCG table semaphore.  gid and mgm parameters must
+ * be properly aligned for command interface.
+ *
+ *  Returns 0 unless a firmware command error occurs.
+ *
+ * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
+ * and *mgm holds MGM entry.
+ *
+ * if GID is found in AMGM, *index = index in AMGM, *prev = index of
+ * previous entry in hash chain and *mgm holds AMGM entry.
+ *
+ * If no AMGM exists for given gid, *index = -1, *prev = index of last
+ * entry in hash chain and *mgm holds end of hash chain.
+ */
+static int find_mgm(struct mlx4_dev *dev,
+                   u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox,
+                   u16 *hash, int *prev, int *index)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mgm *mgm = mgm_mailbox->buf;
+       u8 *mgid;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return -ENOMEM;
+       mgid = mailbox->buf;
+
+       memcpy(mgid, gid, 16);
+
+       err = mlx4_MGID_HASH(dev, mailbox, hash);
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       if (err)
+               return err;
+
+       if (0)
+               mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
+                         "%04x:%04x:%04x:%04x is %04x\n",
+                         be16_to_cpu(((__be16 *) gid)[0]),
+                         be16_to_cpu(((__be16 *) gid)[1]),
+                         be16_to_cpu(((__be16 *) gid)[2]),
+                         be16_to_cpu(((__be16 *) gid)[3]),
+                         be16_to_cpu(((__be16 *) gid)[4]),
+                         be16_to_cpu(((__be16 *) gid)[5]),
+                         be16_to_cpu(((__be16 *) gid)[6]),
+                         be16_to_cpu(((__be16 *) gid)[7]),
+                         *hash);
+
+       *index = *hash;
+       *prev  = -1;
+
+       do {
+               err = mlx4_READ_MCG(dev, *index, mgm_mailbox);
+               if (err)
+                       return err;
+
+               if (!memcmp(mgm->gid, zero_gid, 16)) {
+                       if (*index != *hash) {
+                               mlx4_err(dev, "Found zero MGID in AMGM.\n");
+                               err = -EINVAL;
+                       }
+                       return err;
+               }
+
+               if (!memcmp(mgm->gid, gid, 16))
+                       return err;
+
+               *prev = *index;
+               *index = be32_to_cpu(mgm->next_gid_index) >> 6;
+       } while (*index);
+
+       *index = -1;
+       return err;
+}
+
+int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mgm *mgm;
+       u32 members_count;
+       u16 hash;
+       int index, prev;
+       int link = 0;
+       int i;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
+
+       mutex_lock(&priv->mcg_table.mutex);
+
+       err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
+       if (err)
+               goto out;
+
+       if (index != -1) {
+               if (!memcmp(mgm->gid, zero_gid, 16))
+                       memcpy(mgm->gid, gid, 16);
+       } else {
+               link = 1;
+
+               index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
+               if (index == -1) {
+                       mlx4_err(dev, "No AMGM entries left\n");
+                       err = -ENOMEM;
+                       goto out;
+               }
+               index += dev->caps.num_mgms;
+
+               err = mlx4_READ_MCG(dev, index, mailbox);
+               if (err)
+                       goto out;
+
+               memset(mgm, 0, sizeof *mgm);
+               memcpy(mgm->gid, gid, 16);
+       }
+
+       members_count = be32_to_cpu(mgm->members_count);
+       if (members_count == MLX4_QP_PER_MGM) {
+               mlx4_err(dev, "MGM at index %x is full.\n", index);
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < members_count; ++i)
+               if (mgm->qp[i] == cpu_to_be32(qp->qpn)) {
+                       mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
+                       err = 0;
+                       goto out;
+               }
+
+       mgm->qp[members_count++] = cpu_to_be32(qp->qpn);
+       mgm->members_count       = cpu_to_be32(members_count);
+
+       err = mlx4_WRITE_MCG(dev, index, mailbox);
+       if (err)
+               goto out;
+
+       if (!link)
+               goto out;
+
+       err = mlx4_READ_MCG(dev, prev, mailbox);
+       if (err)
+               goto out;
+
+       mgm->next_gid_index = cpu_to_be32(index << 6);
+
+       err = mlx4_WRITE_MCG(dev, prev, mailbox);
+       if (err)
+               goto out;
+
+out:
+       if (err && link && index != -1) {
+               if (index < dev->caps.num_mgms)
+                       mlx4_warn(dev, "Got AMGM index %d < %d",
+                                 index, dev->caps.num_mgms);
+               else
+                       mlx4_bitmap_free(&priv->mcg_table.bitmap,
+                                        index - dev->caps.num_mgms);
+       }
+       mutex_unlock(&priv->mcg_table.mutex);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
+
+int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mgm *mgm;
+       u32 members_count;
+       u16 hash;
+       int prev, index;
+       int i, loc;
+       int err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
+
+       mutex_lock(&priv->mcg_table.mutex);
+
+       err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
+       if (err)
+               goto out;
+
+       if (index == -1) {
+               mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
+                         "not found\n",
+                         be16_to_cpu(((__be16 *) gid)[0]),
+                         be16_to_cpu(((__be16 *) gid)[1]),
+                         be16_to_cpu(((__be16 *) gid)[2]),
+                         be16_to_cpu(((__be16 *) gid)[3]),
+                         be16_to_cpu(((__be16 *) gid)[4]),
+                         be16_to_cpu(((__be16 *) gid)[5]),
+                         be16_to_cpu(((__be16 *) gid)[6]),
+                         be16_to_cpu(((__be16 *) gid)[7]));
+               err = -EINVAL;
+               goto out;
+       }
+
+       members_count = be32_to_cpu(mgm->members_count);
+       for (loc = -1, i = 0; i < members_count; ++i)
+               if (mgm->qp[i] == cpu_to_be32(qp->qpn))
+                       loc = i;
+
+       if (loc == -1) {
+               mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
+               err = -EINVAL;
+               goto out;
+       }
+
+
+       mgm->members_count = cpu_to_be32(--members_count);
+       mgm->qp[loc]       = mgm->qp[i - 1];
+       mgm->qp[i - 1]     = 0;
+
+       err = mlx4_WRITE_MCG(dev, index, mailbox);
+       if (err)
+               goto out;
+
+       if (i != 1)
+               goto out;
+
+       if (prev == -1) {
+               /* Remove entry from MGM */
+               int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
+               if (amgm_index) {
+                       err = mlx4_READ_MCG(dev, amgm_index, mailbox);
+                       if (err)
+                               goto out;
+               } else
+                       memset(mgm->gid, 0, 16);
+
+               err = mlx4_WRITE_MCG(dev, index, mailbox);
+               if (err)
+                       goto out;
+
+               if (amgm_index) {
+                       if (amgm_index < dev->caps.num_mgms)
+                               mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
+                                         index, amgm_index, dev->caps.num_mgms);
+                       else
+                               mlx4_bitmap_free(&priv->mcg_table.bitmap,
+                                                amgm_index - dev->caps.num_mgms);
+               }
+       } else {
+               /* Remove entry from AMGM */
+               int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
+               err = mlx4_READ_MCG(dev, prev, mailbox);
+               if (err)
+                       goto out;
+
+               mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
+
+               err = mlx4_WRITE_MCG(dev, prev, mailbox);
+               if (err)
+                       goto out;
+
+               if (index < dev->caps.num_mgms)
+                       mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
+                                 prev, index, dev->caps.num_mgms);
+               else
+                       mlx4_bitmap_free(&priv->mcg_table.bitmap,
+                                        index - dev->caps.num_mgms);
+       }
+
+out:
+       mutex_unlock(&priv->mcg_table.mutex);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
+
+int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+
+       err = mlx4_bitmap_init(&priv->mcg_table.bitmap,
+                              dev->caps.num_amgms, dev->caps.num_amgms - 1, 0);
+       if (err)
+               return err;
+
+       mutex_init(&priv->mcg_table.mutex);
+
+       return 0;
+}
+
+void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
+{
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
+}
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
new file mode 100644 (file)
index 0000000..9befbae
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_H
+#define MLX4_H
+
+#include <linux/radix-tree.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/doorbell.h>
+
+#define DRV_NAME       "mlx4_core"
+#define PFX            DRV_NAME ": "
+#define DRV_VERSION    "0.01"
+#define DRV_RELDATE    "May 1, 2007"
+
+enum {
+       MLX4_HCR_BASE           = 0x80680,
+       MLX4_HCR_SIZE           = 0x0001c,
+       MLX4_CLR_INT_SIZE       = 0x00008
+};
+
+enum {
+       MLX4_BOARD_ID_LEN       = 64
+};
+
+enum {
+       MLX4_MGM_ENTRY_SIZE     =  0x40,
+       MLX4_QP_PER_MGM         = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2),
+       MLX4_MTT_ENTRY_PER_SEG  = 8
+};
+
+enum {
+       MLX4_EQ_ASYNC,
+       MLX4_EQ_COMP,
+       MLX4_EQ_CATAS,
+       MLX4_NUM_EQ
+};
+
+enum {
+       MLX4_NUM_PDS            = 1 << 15
+};
+
+enum {
+       MLX4_CMPT_TYPE_QP       = 0,
+       MLX4_CMPT_TYPE_SRQ      = 1,
+       MLX4_CMPT_TYPE_CQ       = 2,
+       MLX4_CMPT_TYPE_EQ       = 3,
+       MLX4_CMPT_NUM_TYPE
+};
+
+enum {
+       MLX4_CMPT_SHIFT         = 24,
+       MLX4_NUM_CMPTS          = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT
+};
+
+#ifdef CONFIG_MLX4_DEBUG
+extern int mlx4_debug_level;
+
+#define mlx4_dbg(mdev, format, arg...)                                 \
+       do {                                                            \
+               if (mlx4_debug_level)                                   \
+                       dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \
+       } while (0)
+
+#else /* CONFIG_MLX4_DEBUG */
+
+#define mlx4_dbg(mdev, format, arg...) do { (void) mdev; } while (0)
+
+#endif /* CONFIG_MLX4_DEBUG */
+
+#define mlx4_err(mdev, format, arg...) \
+       dev_err(&mdev->pdev->dev, format, ## arg)
+#define mlx4_info(mdev, format, arg...) \
+       dev_info(&mdev->pdev->dev, format, ## arg)
+#define mlx4_warn(mdev, format, arg...) \
+       dev_warn(&mdev->pdev->dev, format, ## arg)
+
+struct mlx4_bitmap {
+       u32                     last;
+       u32                     top;
+       u32                     max;
+       u32                     mask;
+       spinlock_t              lock;
+       unsigned long          *table;
+};
+
+struct mlx4_buddy {
+       unsigned long         **bits;
+       int                     max_order;
+       spinlock_t              lock;
+};
+
+struct mlx4_icm;
+
+struct mlx4_icm_table {
+       u64                     virt;
+       int                     num_icm;
+       int                     num_obj;
+       int                     obj_size;
+       int                     lowmem;
+       struct mutex            mutex;
+       struct mlx4_icm       **icm;
+};
+
+struct mlx4_eq {
+       struct mlx4_dev        *dev;
+       void __iomem           *doorbell;
+       int                     eqn;
+       u32                     cons_index;
+       u16                     irq;
+       u16                     have_irq;
+       int                     nent;
+       struct mlx4_buf_list   *page_list;
+       struct mlx4_mtt         mtt;
+};
+
+struct mlx4_profile {
+       int                     num_qp;
+       int                     rdmarc_per_qp;
+       int                     num_srq;
+       int                     num_cq;
+       int                     num_mcg;
+       int                     num_mpt;
+       int                     num_mtt;
+};
+
+struct mlx4_fw {
+       u64                     clr_int_base;
+       u64                     catas_offset;
+       struct mlx4_icm        *fw_icm;
+       struct mlx4_icm        *aux_icm;
+       u32                     catas_size;
+       u16                     fw_pages;
+       u8                      clr_int_bar;
+       u8                      catas_bar;
+};
+
+struct mlx4_cmd {
+       struct pci_pool        *pool;
+       void __iomem           *hcr;
+       struct mutex            hcr_mutex;
+       struct semaphore        poll_sem;
+       struct semaphore        event_sem;
+       int                     max_cmds;
+       spinlock_t              context_lock;
+       int                     free_head;
+       struct mlx4_cmd_context *context;
+       u16                     token_mask;
+       u8                      use_events;
+       u8                      toggle;
+};
+
+struct mlx4_uar_table {
+       struct mlx4_bitmap      bitmap;
+};
+
+struct mlx4_mr_table {
+       struct mlx4_bitmap      mpt_bitmap;
+       struct mlx4_buddy       mtt_buddy;
+       u64                     mtt_base;
+       u64                     mpt_base;
+       struct mlx4_icm_table   mtt_table;
+       struct mlx4_icm_table   dmpt_table;
+};
+
+struct mlx4_cq_table {
+       struct mlx4_bitmap      bitmap;
+       spinlock_t              lock;
+       struct radix_tree_root  tree;
+       struct mlx4_icm_table   table;
+       struct mlx4_icm_table   cmpt_table;
+};
+
+struct mlx4_eq_table {
+       struct mlx4_bitmap      bitmap;
+       void __iomem           *clr_int;
+       void __iomem           *uar_map[(MLX4_NUM_EQ + 6) / 4];
+       u32                     clr_mask;
+       struct mlx4_eq          eq[MLX4_NUM_EQ];
+       u64                     icm_virt;
+       struct page            *icm_page;
+       dma_addr_t              icm_dma;
+       struct mlx4_icm_table   cmpt_table;
+       int                     have_irq;
+       u8                      inta_pin;
+};
+
+struct mlx4_srq_table {
+       struct mlx4_bitmap      bitmap;
+       spinlock_t              lock;
+       struct radix_tree_root  tree;
+       struct mlx4_icm_table   table;
+       struct mlx4_icm_table   cmpt_table;
+};
+
+struct mlx4_qp_table {
+       struct mlx4_bitmap      bitmap;
+       u32                     rdmarc_base;
+       int                     rdmarc_shift;
+       spinlock_t              lock;
+       struct mlx4_icm_table   qp_table;
+       struct mlx4_icm_table   auxc_table;
+       struct mlx4_icm_table   altc_table;
+       struct mlx4_icm_table   rdmarc_table;
+       struct mlx4_icm_table   cmpt_table;
+};
+
+struct mlx4_mcg_table {
+       struct mutex            mutex;
+       struct mlx4_bitmap      bitmap;
+       struct mlx4_icm_table   table;
+};
+
+struct mlx4_catas_err {
+       u32 __iomem            *map;
+       int                     size;
+};
+
+struct mlx4_priv {
+       struct mlx4_dev         dev;
+
+       struct list_head        dev_list;
+       struct list_head        ctx_list;
+       spinlock_t              ctx_lock;
+
+       struct mlx4_fw          fw;
+       struct mlx4_cmd         cmd;
+
+       struct mlx4_bitmap      pd_bitmap;
+       struct mlx4_uar_table   uar_table;
+       struct mlx4_mr_table    mr_table;
+       struct mlx4_cq_table    cq_table;
+       struct mlx4_eq_table    eq_table;
+       struct mlx4_srq_table   srq_table;
+       struct mlx4_qp_table    qp_table;
+       struct mlx4_mcg_table   mcg_table;
+
+       struct mlx4_catas_err   catas_err;
+
+       void __iomem           *clr_base;
+
+       struct mlx4_uar         driver_uar;
+       void __iomem           *kar;
+       MLX4_DECLARE_DOORBELL_LOCK(doorbell_lock)
+
+       u32                     rev_id;
+       char                    board_id[MLX4_BOARD_ID_LEN];
+};
+
+static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
+{
+       return container_of(dev, struct mlx4_priv, dev);
+}
+
+u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
+void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
+int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved);
+void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);
+
+int mlx4_reset(struct mlx4_dev *dev);
+
+int mlx4_init_pd_table(struct mlx4_dev *dev);
+int mlx4_init_uar_table(struct mlx4_dev *dev);
+int mlx4_init_mr_table(struct mlx4_dev *dev);
+int mlx4_init_eq_table(struct mlx4_dev *dev);
+int mlx4_init_cq_table(struct mlx4_dev *dev);
+int mlx4_init_qp_table(struct mlx4_dev *dev);
+int mlx4_init_srq_table(struct mlx4_dev *dev);
+int mlx4_init_mcg_table(struct mlx4_dev *dev);
+
+void mlx4_cleanup_pd_table(struct mlx4_dev *dev);
+void mlx4_cleanup_uar_table(struct mlx4_dev *dev);
+void mlx4_cleanup_mr_table(struct mlx4_dev *dev);
+void mlx4_cleanup_eq_table(struct mlx4_dev *dev);
+void mlx4_cleanup_cq_table(struct mlx4_dev *dev);
+void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
+void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
+void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
+
+void mlx4_map_catas_buf(struct mlx4_dev *dev);
+void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
+
+int mlx4_register_device(struct mlx4_dev *dev);
+void mlx4_unregister_device(struct mlx4_dev *dev);
+void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
+                        int subtype, int port);
+
+struct mlx4_dev_cap;
+struct mlx4_init_hca_param;
+
+u64 mlx4_make_profile(struct mlx4_dev *dev,
+                     struct mlx4_profile *request,
+                     struct mlx4_dev_cap *dev_cap,
+                     struct mlx4_init_hca_param *init_hca);
+
+int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt);
+void mlx4_unmap_eq_icm(struct mlx4_dev *dev);
+
+int mlx4_cmd_init(struct mlx4_dev *dev);
+void mlx4_cmd_cleanup(struct mlx4_dev *dev);
+void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);
+int mlx4_cmd_use_events(struct mlx4_dev *dev);
+void mlx4_cmd_use_polling(struct mlx4_dev *dev);
+
+void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
+void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type);
+
+void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type);
+
+void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
+
+void mlx4_handle_catas_err(struct mlx4_dev *dev);
+
+#endif /* MLX4_H */
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
new file mode 100644 (file)
index 0000000..b33864d
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+#include "icm.h"
+
+/*
+ * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
+ */
+struct mlx4_mpt_entry {
+       __be32 flags;
+       __be32 qpn;
+       __be32 key;
+       __be32 pd;
+       __be64 start;
+       __be64 length;
+       __be32 lkey;
+       __be32 win_cnt;
+       u8      reserved1[3];
+       u8      mtt_rep;
+       __be64 mtt_seg;
+       __be32 mtt_sz;
+       __be32 entity_size;
+       __be32 first_byte_offset;
+} __attribute__((packed));
+
+#define MLX4_MPT_FLAG_SW_OWNS      (0xfUL << 28)
+#define MLX4_MPT_FLAG_MIO          (1 << 17)
+#define MLX4_MPT_FLAG_BIND_ENABLE   (1 << 15)
+#define MLX4_MPT_FLAG_PHYSICAL     (1 <<  9)
+#define MLX4_MPT_FLAG_REGION       (1 <<  8)
+
+#define MLX4_MTT_FLAG_PRESENT          1
+
+static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order)
+{
+       int o;
+       int m;
+       u32 seg;
+
+       spin_lock(&buddy->lock);
+
+       for (o = order; o <= buddy->max_order; ++o) {
+               m = 1 << (buddy->max_order - o);
+               seg = find_first_bit(buddy->bits[o], m);
+               if (seg < m)
+                       goto found;
+       }
+
+       spin_unlock(&buddy->lock);
+       return -1;
+
+ found:
+       clear_bit(seg, buddy->bits[o]);
+
+       while (o > order) {
+               --o;
+               seg <<= 1;
+               set_bit(seg ^ 1, buddy->bits[o]);
+       }
+
+       spin_unlock(&buddy->lock);
+
+       seg <<= order;
+
+       return seg;
+}
+
+static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order)
+{
+       seg >>= order;
+
+       spin_lock(&buddy->lock);
+
+       while (test_bit(seg ^ 1, buddy->bits[order])) {
+               clear_bit(seg ^ 1, buddy->bits[order]);
+               seg >>= 1;
+               ++order;
+       }
+
+       set_bit(seg, buddy->bits[order]);
+
+       spin_unlock(&buddy->lock);
+}
+
+static int __devinit mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
+{
+       int i, s;
+
+       buddy->max_order = max_order;
+       spin_lock_init(&buddy->lock);
+
+       buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),
+                             GFP_KERNEL);
+       if (!buddy->bits)
+               goto err_out;
+
+       for (i = 0; i <= buddy->max_order; ++i) {
+               s = BITS_TO_LONGS(1 << (buddy->max_order - i));
+               buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
+               if (!buddy->bits[i])
+                       goto err_out_free;
+               bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
+       }
+
+       set_bit(0, buddy->bits[buddy->max_order]);
+
+       return 0;
+
+err_out_free:
+       for (i = 0; i <= buddy->max_order; ++i)
+               kfree(buddy->bits[i]);
+
+       kfree(buddy->bits);
+
+err_out:
+       return -ENOMEM;
+}
+
+static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
+{
+       int i;
+
+       for (i = 0; i <= buddy->max_order; ++i)
+               kfree(buddy->bits[i]);
+
+       kfree(buddy->bits);
+}
+
+static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)
+{
+       struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+       u32 seg;
+
+       seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order);
+       if (seg == -1)
+               return -1;
+
+       if (mlx4_table_get_range(dev, &mr_table->mtt_table, seg,
+                                seg + (1 << order) - 1)) {
+               mlx4_buddy_free(&mr_table->mtt_buddy, seg, order);
+               return -1;
+       }
+
+       return seg;
+}
+
+int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
+                 struct mlx4_mtt *mtt)
+{
+       int i;
+
+       if (!npages) {
+               mtt->order      = -1;
+               mtt->page_shift = MLX4_ICM_PAGE_SHIFT;
+               return 0;
+       } else
+               mtt->page_shift = page_shift;
+
+       for (mtt->order = 0, i = MLX4_MTT_ENTRY_PER_SEG; i < npages; i <<= 1)
+               ++mtt->order;
+
+       mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order);
+       if (mtt->first_seg == -1)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_mtt_init);
+
+void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
+{
+       struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+
+       if (mtt->order < 0)
+               return;
+
+       mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order);
+       mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg,
+                            mtt->first_seg + (1 << mtt->order) - 1);
+}
+EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup);
+
+u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
+{
+       return (u64) mtt->first_seg * dev->caps.mtt_entry_sz;
+}
+EXPORT_SYMBOL_GPL(mlx4_mtt_addr);
+
+static u32 hw_index_to_key(u32 ind)
+{
+       return (ind >> 24) | (ind << 8);
+}
+
+static u32 key_to_hw_index(u32 key)
+{
+       return (key << 24) | (key >> 8);
+}
+
+static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         int mpt_index)
+{
+       return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT,
+                       MLX4_CMD_TIME_CLASS_B);
+}
+
+static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         int mpt_index)
+{
+       return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
+                           !mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
+                 int npages, int page_shift, struct mlx4_mr *mr)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       u32 index;
+       int err;
+
+       index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
+       if (index == -1) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       mr->iova       = iova;
+       mr->size       = size;
+       mr->pd         = pd;
+       mr->access     = access;
+       mr->enabled    = 0;
+       mr->key        = hw_index_to_key(index);
+
+       err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
+       if (err)
+               goto err_index;
+
+       return 0;
+
+err_index:
+       mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
+
+err:
+       kfree(mr);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
+
+void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int err;
+
+       if (mr->enabled) {
+               err = mlx4_HW2SW_MPT(dev, NULL,
+                                    key_to_hw_index(mr->key) &
+                                    (dev->caps.num_mpts - 1));
+               if (err)
+                       mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err);
+       }
+
+       mlx4_mtt_cleanup(dev, &mr->mtt);
+       mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key));
+}
+EXPORT_SYMBOL_GPL(mlx4_mr_free);
+
+int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
+{
+       struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_mpt_entry *mpt_entry;
+       int err;
+
+       err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
+       if (err)
+               return err;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
+               goto err_table;
+       }
+       mpt_entry = mailbox->buf;
+
+       memset(mpt_entry, 0, sizeof *mpt_entry);
+
+       mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS     |
+                                      MLX4_MPT_FLAG_MIO         |
+                                      MLX4_MPT_FLAG_REGION      |
+                                      mr->access);
+       if (mr->mtt.order < 0)
+               mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL);
+
+       mpt_entry->key         = cpu_to_be32(key_to_hw_index(mr->key));
+       mpt_entry->pd          = cpu_to_be32(mr->pd);
+       mpt_entry->start       = cpu_to_be64(mr->iova);
+       mpt_entry->length      = cpu_to_be64(mr->size);
+       mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift);
+       mpt_entry->mtt_seg     = cpu_to_be64(mlx4_mtt_addr(dev, &mr->mtt));
+
+       err = mlx4_SW2HW_MPT(dev, mailbox,
+                            key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1));
+       if (err) {
+               mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err);
+               goto err_cmd;
+       }
+
+       mr->enabled = 1;
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+       return 0;
+
+err_cmd:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+err_table:
+       mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_mr_enable);
+
+static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         int num_mtt)
+{
+       return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT,
+                       MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                  int start_index, int npages, u64 *page_list)
+{
+       struct mlx4_cmd_mailbox *mailbox;
+       __be64 *mtt_entry;
+       int i;
+       int err = 0;
+
+       if (mtt->order < 0)
+               return -EINVAL;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       mtt_entry = mailbox->buf;
+
+       while (npages > 0) {
+               mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8);
+               mtt_entry[1] = 0;
+
+               for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i)
+                       mtt_entry[i + 2] = cpu_to_be64(page_list[i] |
+                                                      MLX4_MTT_FLAG_PRESENT);
+
+               /*
+                * If we have an odd number of entries to write, add
+                * one more dummy entry for firmware efficiency.
+                */
+               if (i & 1)
+                       mtt_entry[i + 2] = 0;
+
+               err = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1);
+               if (err)
+                       goto out;
+
+               npages      -= i;
+               start_index += i;
+               page_list   += i;
+       }
+
+out:
+       mlx4_free_cmd_mailbox(dev, mailbox);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_write_mtt);
+
+int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                      struct mlx4_buf *buf)
+{
+       u64 *page_list;
+       int err;
+       int i;
+
+       page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL);
+       if (!page_list)
+               return -ENOMEM;
+
+       for (i = 0; i < buf->npages; ++i)
+               if (buf->nbufs == 1)
+                       page_list[i] = buf->u.direct.map + (i << buf->page_shift);
+               else
+                       page_list[i] = buf->u.page_list[i].map;
+
+       err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list);
+
+       kfree(page_list);
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt);
+
+int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
+{
+       struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+       int err;
+
+       err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts,
+                              ~0, dev->caps.reserved_mrws);
+       if (err)
+               return err;
+
+       err = mlx4_buddy_init(&mr_table->mtt_buddy,
+                             ilog2(dev->caps.num_mtt_segs));
+       if (err)
+               goto err_buddy;
+
+       if (dev->caps.reserved_mtts) {
+               if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) {
+                       mlx4_warn(dev, "MTT table of order %d is too small.\n",
+                                 mr_table->mtt_buddy.max_order);
+                       err = -ENOMEM;
+                       goto err_reserve_mtts;
+               }
+       }
+
+       return 0;
+
+err_reserve_mtts:
+       mlx4_buddy_cleanup(&mr_table->mtt_buddy);
+
+err_buddy:
+       mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
+
+       return err;
+}
+
+void mlx4_cleanup_mr_table(struct mlx4_dev *dev)
+{
+       struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+
+       mlx4_buddy_cleanup(&mr_table->mtt_buddy);
+       mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
+}
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
new file mode 100644 (file)
index 0000000..23dea1e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <asm/page.h>
+
+#include "mlx4.h"
+#include "icm.h"
+
+int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap);
+       if (*pdn == -1)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_pd_alloc);
+
+void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn)
+{
+       mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn);
+}
+EXPORT_SYMBOL_GPL(mlx4_pd_free);
+
+int __devinit mlx4_init_pd_table(struct mlx4_dev *dev)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds,
+                               (1 << 24) - 1, dev->caps.reserved_pds);
+}
+
+void mlx4_cleanup_pd_table(struct mlx4_dev *dev)
+{
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap);
+}
+
+
+int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar)
+{
+       uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap);
+       if (uar->index == -1)
+               return -ENOMEM;
+
+       uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_uar_alloc);
+
+void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar)
+{
+       mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index);
+}
+EXPORT_SYMBOL_GPL(mlx4_uar_free);
+
+int mlx4_init_uar_table(struct mlx4_dev *dev)
+{
+       return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap,
+                               dev->caps.num_uars, dev->caps.num_uars - 1,
+                               max(128, dev->caps.reserved_uars));
+}
+
+void mlx4_cleanup_uar_table(struct mlx4_dev *dev)
+{
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap);
+}
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
new file mode 100644 (file)
index 0000000..9ca42b2
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+
+#include "mlx4.h"
+#include "fw.h"
+
+enum {
+       MLX4_RES_QP,
+       MLX4_RES_RDMARC,
+       MLX4_RES_ALTC,
+       MLX4_RES_AUXC,
+       MLX4_RES_SRQ,
+       MLX4_RES_CQ,
+       MLX4_RES_EQ,
+       MLX4_RES_DMPT,
+       MLX4_RES_CMPT,
+       MLX4_RES_MTT,
+       MLX4_RES_MCG,
+       MLX4_RES_NUM
+};
+
+static const char *res_name[] = {
+       [MLX4_RES_QP]           = "QP",
+       [MLX4_RES_RDMARC]       = "RDMARC",
+       [MLX4_RES_ALTC]         = "ALTC",
+       [MLX4_RES_AUXC]         = "AUXC",
+       [MLX4_RES_SRQ]          = "SRQ",
+       [MLX4_RES_CQ]           = "CQ",
+       [MLX4_RES_EQ]           = "EQ",
+       [MLX4_RES_DMPT]         = "DMPT",
+       [MLX4_RES_CMPT]         = "CMPT",
+       [MLX4_RES_MTT]          = "MTT",
+       [MLX4_RES_MCG]          = "MCG",
+};
+
+u64 mlx4_make_profile(struct mlx4_dev *dev,
+                     struct mlx4_profile *request,
+                     struct mlx4_dev_cap *dev_cap,
+                     struct mlx4_init_hca_param *init_hca)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource {
+               u64 size;
+               u64 start;
+               int type;
+               int num;
+               int log_num;
+       };
+
+       u64 total_size = 0;
+       struct mlx4_resource *profile;
+       struct mlx4_resource tmp;
+       int i, j;
+
+       profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL);
+       if (!profile)
+               return -ENOMEM;
+
+       profile[MLX4_RES_QP].size     = dev_cap->qpc_entry_sz;
+       profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz;
+       profile[MLX4_RES_ALTC].size   = dev_cap->altc_entry_sz;
+       profile[MLX4_RES_AUXC].size   = dev_cap->aux_entry_sz;
+       profile[MLX4_RES_SRQ].size    = dev_cap->srq_entry_sz;
+       profile[MLX4_RES_CQ].size     = dev_cap->cqc_entry_sz;
+       profile[MLX4_RES_EQ].size     = dev_cap->eqc_entry_sz;
+       profile[MLX4_RES_DMPT].size   = dev_cap->dmpt_entry_sz;
+       profile[MLX4_RES_CMPT].size   = dev_cap->cmpt_entry_sz;
+       profile[MLX4_RES_MTT].size    = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz;
+       profile[MLX4_RES_MCG].size    = MLX4_MGM_ENTRY_SIZE;
+
+       profile[MLX4_RES_QP].num      = request->num_qp;
+       profile[MLX4_RES_RDMARC].num  = request->num_qp * request->rdmarc_per_qp;
+       profile[MLX4_RES_ALTC].num    = request->num_qp;
+       profile[MLX4_RES_AUXC].num    = request->num_qp;
+       profile[MLX4_RES_SRQ].num     = request->num_srq;
+       profile[MLX4_RES_CQ].num      = request->num_cq;
+       profile[MLX4_RES_EQ].num      = MLX4_NUM_EQ + dev_cap->reserved_eqs;
+       profile[MLX4_RES_DMPT].num    = request->num_mpt;
+       profile[MLX4_RES_CMPT].num    = MLX4_NUM_CMPTS;
+       profile[MLX4_RES_MTT].num     = request->num_mtt;
+       profile[MLX4_RES_MCG].num     = request->num_mcg;
+
+       for (i = 0; i < MLX4_RES_NUM; ++i) {
+               profile[i].type     = i;
+               profile[i].num      = roundup_pow_of_two(profile[i].num);
+               profile[i].log_num  = ilog2(profile[i].num);
+               profile[i].size    *= profile[i].num;
+               profile[i].size     = max(profile[i].size, (u64) PAGE_SIZE);
+       }
+
+       /*
+        * Sort the resources in decreasing order of size.  Since they
+        * all have sizes that are powers of 2, we'll be able to keep
+        * resources aligned to their size and pack them without gaps
+        * using the sorted order.
+        */
+       for (i = MLX4_RES_NUM; i > 0; --i)
+               for (j = 1; j < i; ++j) {
+                       if (profile[j].size > profile[j - 1].size) {
+                               tmp            = profile[j];
+                               profile[j]     = profile[j - 1];
+                               profile[j - 1] = tmp;
+                       }
+               }
+
+       for (i = 0; i < MLX4_RES_NUM; ++i) {
+               if (profile[i].size) {
+                       profile[i].start = total_size;
+                       total_size      += profile[i].size;
+               }
+
+               if (total_size > dev_cap->max_icm_sz) {
+                       mlx4_err(dev, "Profile requires 0x%llx bytes; "
+                                 "won't fit in 0x%llx bytes of context memory.\n",
+                                 (unsigned long long) total_size,
+                                 (unsigned long long) dev_cap->max_icm_sz);
+                       kfree(profile);
+                       return -ENOMEM;
+               }
+
+               if (profile[i].size)
+                       mlx4_dbg(dev, "  profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, "
+                                 "size 0x%10llx\n",
+                                i, res_name[profile[i].type], profile[i].log_num,
+                                (unsigned long long) profile[i].start,
+                                (unsigned long long) profile[i].size);
+       }
+
+       mlx4_dbg(dev, "HCA context memory: reserving %d KB\n",
+                (int) (total_size >> 10));
+
+       for (i = 0; i < MLX4_RES_NUM; ++i) {
+               switch (profile[i].type) {
+               case MLX4_RES_QP:
+                       dev->caps.num_qps     = profile[i].num;
+                       init_hca->qpc_base    = profile[i].start;
+                       init_hca->log_num_qps = profile[i].log_num;
+                       break;
+               case MLX4_RES_RDMARC:
+                       for (priv->qp_table.rdmarc_shift = 0;
+                            request->num_qp << priv->qp_table.rdmarc_shift < profile[i].num;
+                            ++priv->qp_table.rdmarc_shift)
+                               ; /* nothing */
+                       dev->caps.max_qp_dest_rdma = 1 << priv->qp_table.rdmarc_shift;
+                       priv->qp_table.rdmarc_base   = (u32) profile[i].start;
+                       init_hca->rdmarc_base        = profile[i].start;
+                       init_hca->log_rd_per_qp      = priv->qp_table.rdmarc_shift;
+                       break;
+               case MLX4_RES_ALTC:
+                       init_hca->altc_base = profile[i].start;
+                       break;
+               case MLX4_RES_AUXC:
+                       init_hca->auxc_base = profile[i].start;
+                       break;
+               case MLX4_RES_SRQ:
+                       dev->caps.num_srqs     = profile[i].num;
+                       init_hca->srqc_base    = profile[i].start;
+                       init_hca->log_num_srqs = profile[i].log_num;
+                       break;
+               case MLX4_RES_CQ:
+                       dev->caps.num_cqs     = profile[i].num;
+                       init_hca->cqc_base    = profile[i].start;
+                       init_hca->log_num_cqs = profile[i].log_num;
+                       break;
+               case MLX4_RES_EQ:
+                       dev->caps.num_eqs     = profile[i].num;
+                       init_hca->eqc_base    = profile[i].start;
+                       init_hca->log_num_eqs = profile[i].log_num;
+                       break;
+               case MLX4_RES_DMPT:
+                       dev->caps.num_mpts      = profile[i].num;
+                       priv->mr_table.mpt_base = profile[i].start;
+                       init_hca->dmpt_base     = profile[i].start;
+                       init_hca->log_mpt_sz    = profile[i].log_num;
+                       break;
+               case MLX4_RES_CMPT:
+                       init_hca->cmpt_base      = profile[i].start;
+                       break;
+               case MLX4_RES_MTT:
+                       dev->caps.num_mtt_segs   = profile[i].num;
+                       priv->mr_table.mtt_base  = profile[i].start;
+                       init_hca->mtt_base       = profile[i].start;
+                       break;
+               case MLX4_RES_MCG:
+                       dev->caps.num_mgms        = profile[i].num >> 1;
+                       dev->caps.num_amgms       = profile[i].num >> 1;
+                       init_hca->mc_base         = profile[i].start;
+                       init_hca->log_mc_entry_sz = ilog2(MLX4_MGM_ENTRY_SIZE);
+                       init_hca->log_mc_table_sz = profile[i].log_num;
+                       init_hca->log_mc_hash_sz  = profile[i].log_num - 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /*
+        * PDs don't take any HCA memory, but we assign them as part
+        * of the HCA profile anyway.
+        */
+       dev->caps.num_pds = MLX4_NUM_PDS;
+
+       kfree(profile);
+       return total_size;
+}
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
new file mode 100644 (file)
index 0000000..7f8b7d5
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+
+#include <linux/mlx4/cmd.h>
+#include <linux/mlx4/qp.h>
+
+#include "mlx4.h"
+#include "icm.h"
+
+void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type)
+{
+       struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+       struct mlx4_qp *qp;
+
+       spin_lock(&qp_table->lock);
+
+       qp = __mlx4_qp_lookup(dev, qpn);
+       if (qp)
+               atomic_inc(&qp->refcount);
+
+       spin_unlock(&qp_table->lock);
+
+       if (!qp) {
+               mlx4_warn(dev, "Async event for bogus QP %08x\n", qpn);
+               return;
+       }
+
+       qp->event(qp, event_type);
+
+       if (atomic_dec_and_test(&qp->refcount))
+               complete(&qp->free);
+}
+
+int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                  enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state,
+                  struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar,
+                  int sqd_event, struct mlx4_qp *qp)
+{
+       static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = {
+               [MLX4_QP_STATE_RST] = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_INIT]    = MLX4_CMD_RST2INIT_QP,
+               },
+               [MLX4_QP_STATE_INIT]  = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_INIT]    = MLX4_CMD_INIT2INIT_QP,
+                       [MLX4_QP_STATE_RTR]     = MLX4_CMD_INIT2RTR_QP,
+               },
+               [MLX4_QP_STATE_RTR]   = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_RTS]     = MLX4_CMD_RTR2RTS_QP,
+               },
+               [MLX4_QP_STATE_RTS]   = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_RTS]     = MLX4_CMD_RTS2RTS_QP,
+                       [MLX4_QP_STATE_SQD]     = MLX4_CMD_RTS2SQD_QP,
+               },
+               [MLX4_QP_STATE_SQD] = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_RTS]     = MLX4_CMD_SQD2RTS_QP,
+                       [MLX4_QP_STATE_SQD]     = MLX4_CMD_SQD2SQD_QP,
+               },
+               [MLX4_QP_STATE_SQER] = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+                       [MLX4_QP_STATE_RTS]     = MLX4_CMD_SQERR2RTS_QP,
+               },
+               [MLX4_QP_STATE_ERR] = {
+                       [MLX4_QP_STATE_RST]     = MLX4_CMD_2RST_QP,
+                       [MLX4_QP_STATE_ERR]     = MLX4_CMD_2ERR_QP,
+               }
+       };
+
+       struct mlx4_cmd_mailbox *mailbox;
+       int ret = 0;
+
+       if (cur_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
+           new_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
+           !op[cur_state][new_state])
+               return -EINVAL;
+
+       if (op[cur_state][new_state] == MLX4_CMD_2RST_QP)
+               return mlx4_cmd(dev, 0, qp->qpn, 2,
+                               MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A);
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) {
+               u64 mtt_addr = mlx4_mtt_addr(dev, mtt);
+               context->mtt_base_addr_h = mtt_addr >> 32;
+               context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
+               context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
+       }
+
+       *(__be32 *) mailbox->buf = cpu_to_be32(optpar);
+       memcpy(mailbox->buf + 8, context, sizeof *context);
+
+       ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn =
+               cpu_to_be32(qp->qpn);
+
+       ret = mlx4_cmd(dev, mailbox->dma, qp->qpn | (!!sqd_event << 31),
+                      new_state == MLX4_QP_STATE_RST ? 2 : 0,
+                      op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_modify);
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_qp_table *qp_table = &priv->qp_table;
+       int err;
+
+       if (sqpn)
+               qp->qpn = sqpn;
+       else {
+               qp->qpn = mlx4_bitmap_alloc(&qp_table->bitmap);
+               if (qp->qpn == -1)
+                       return -ENOMEM;
+       }
+
+       err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn);
+       if (err)
+               goto err_out;
+
+       err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn);
+       if (err)
+               goto err_put_qp;
+
+       err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn);
+       if (err)
+               goto err_put_auxc;
+
+       err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn);
+       if (err)
+               goto err_put_altc;
+
+       err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn);
+       if (err)
+               goto err_put_rdmarc;
+
+       spin_lock_irq(&qp_table->lock);
+       err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp);
+       spin_unlock_irq(&qp_table->lock);
+       if (err)
+               goto err_put_cmpt;
+
+       atomic_set(&qp->refcount, 1);
+       init_completion(&qp->free);
+
+       return 0;
+
+err_put_cmpt:
+       mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
+
+err_put_rdmarc:
+       mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
+
+err_put_altc:
+       mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
+
+err_put_auxc:
+       mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
+
+err_put_qp:
+       mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
+
+err_out:
+       if (!sqpn)
+               mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
+
+void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp)
+{
+       struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp_table->lock, flags);
+       radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1));
+       spin_unlock_irqrestore(&qp_table->lock, flags);
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_remove);
+
+void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
+{
+       struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+
+       if (atomic_dec_and_test(&qp->refcount))
+               complete(&qp->free);
+       wait_for_completion(&qp->free);
+
+       mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
+       mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
+       mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
+       mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
+       mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
+
+       mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_free);
+
+static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn)
+{
+       return mlx4_cmd(dev, 0, base_qpn, 0, MLX4_CMD_CONF_SPECIAL_QP,
+                       MLX4_CMD_TIME_CLASS_B);
+}
+
+int __devinit mlx4_init_qp_table(struct mlx4_dev *dev)
+{
+       struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+       int err;
+
+       spin_lock_init(&qp_table->lock);
+       INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
+
+       /*
+        * We reserve 2 extra QPs per port for the special QPs.  The
+        * block of special QPs must be aligned to a multiple of 8, so
+        * round up.
+        */
+       dev->caps.sqp_start = ALIGN(dev->caps.reserved_qps, 8);
+       err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
+                              (1 << 24) - 1, dev->caps.sqp_start + 8);
+       if (err)
+               return err;
+
+       return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start);
+}
+
+void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
+{
+       mlx4_CONF_SPECIAL_QP(dev, 0);
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap);
+}
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c
new file mode 100644 (file)
index 0000000..51eef84
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "mlx4.h"
+
+int mlx4_reset(struct mlx4_dev *dev)
+{
+       void __iomem *reset;
+       u32 *hca_header = NULL;
+       int pcie_cap;
+       u16 devctl;
+       u16 linkctl;
+       u16 vendor;
+       unsigned long end;
+       u32 sem;
+       int i;
+       int err = 0;
+
+#define MLX4_RESET_BASE                0xf0000
+#define MLX4_RESET_SIZE                  0x400
+#define MLX4_SEM_OFFSET                  0x3fc
+#define MLX4_RESET_OFFSET         0x10
+#define MLX4_RESET_VALUE       swab32(1)
+
+#define MLX4_SEM_TIMEOUT_JIFFIES       (10 * HZ)
+#define MLX4_RESET_TIMEOUT_JIFFIES     (2 * HZ)
+
+       /*
+        * Reset the chip.  This is somewhat ugly because we have to
+        * save off the PCI header before reset and then restore it
+        * after the chip reboots.  We skip config space offsets 22
+        * and 23 since those have a special meaning.
+        */
+
+       /* Do we need to save off the full 4K PCI Express header?? */
+       hca_header = kmalloc(256, GFP_KERNEL);
+       if (!hca_header) {
+               err = -ENOMEM;
+               mlx4_err(dev, "Couldn't allocate memory to save HCA "
+                         "PCI header, aborting.\n");
+               goto out;
+       }
+
+       pcie_cap = pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
+
+       for (i = 0; i < 64; ++i) {
+               if (i == 22 || i == 23)
+                       continue;
+               if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) {
+                       err = -ENODEV;
+                       mlx4_err(dev, "Couldn't save HCA "
+                                 "PCI header, aborting.\n");
+                       goto out;
+               }
+       }
+
+       reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE,
+                       MLX4_RESET_SIZE);
+       if (!reset) {
+               err = -ENOMEM;
+               mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n");
+               goto out;
+       }
+
+       /* grab HW semaphore to lock out flash updates */
+       end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES;
+       do {
+               sem = readl(reset + MLX4_SEM_OFFSET);
+               if (!sem)
+                       break;
+
+               msleep(1);
+       } while (time_before(jiffies, end));
+
+       if (sem) {
+               mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n");
+               err = -EAGAIN;
+               iounmap(reset);
+               goto out;
+       }
+
+       /* actually hit reset */
+       writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);
+       iounmap(reset);
+
+       end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
+       do {
+               if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
+                   vendor != 0xffff)
+                       break;
+
+               msleep(1);
+       } while (time_before(jiffies, end));
+
+       if (vendor == 0xffff) {
+               err = -ENODEV;
+               mlx4_err(dev, "PCI device did not come back after reset, "
+                         "aborting.\n");
+               goto out;
+       }
+
+       /* Now restore the PCI headers */
+       if (pcie_cap) {
+               devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];
+               if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL,
+                                          devctl)) {
+                       err = -ENODEV;
+                       mlx4_err(dev, "Couldn't restore HCA PCI Express "
+                                "Device Control register, aborting.\n");
+                       goto out;
+               }
+               linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];
+               if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL,
+                                          linkctl)) {
+                       err = -ENODEV;
+                       mlx4_err(dev, "Couldn't restore HCA PCI Express "
+                                "Link control register, aborting.\n");
+                       goto out;
+               }
+       }
+
+       for (i = 0; i < 16; ++i) {
+               if (i * 4 == PCI_COMMAND)
+                       continue;
+
+               if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) {
+                       err = -ENODEV;
+                       mlx4_err(dev, "Couldn't restore HCA reg %x, "
+                                 "aborting.\n", i);
+                       goto out;
+               }
+       }
+
+       if (pci_write_config_dword(dev->pdev, PCI_COMMAND,
+                                  hca_header[PCI_COMMAND / 4])) {
+               err = -ENODEV;
+               mlx4_err(dev, "Couldn't restore HCA COMMAND, "
+                         "aborting.\n");
+               goto out;
+       }
+
+out:
+       kfree(hca_header);
+
+       return err;
+}
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
new file mode 100644 (file)
index 0000000..2134f83
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+
+#include <linux/mlx4/cmd.h>
+
+#include "mlx4.h"
+#include "icm.h"
+
+struct mlx4_srq_context {
+       __be32                  state_logsize_srqn;
+       u8                      logstride;
+       u8                      reserved1[3];
+       u8                      pg_offset;
+       u8                      reserved2[3];
+       u32                     reserved3;
+       u8                      log_page_size;
+       u8                      reserved4[2];
+       u8                      mtt_base_addr_h;
+       __be32                  mtt_base_addr_l;
+       __be32                  pd;
+       __be16                  limit_watermark;
+       __be16                  wqe_cnt;
+       u16                     reserved5;
+       __be16                  wqe_counter;
+       u32                     reserved6;
+       __be64                  db_rec_addr;
+};
+
+void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
+{
+       struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+       struct mlx4_srq *srq;
+
+       spin_lock(&srq_table->lock);
+
+       srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
+       if (srq)
+               atomic_inc(&srq->refcount);
+
+       spin_unlock(&srq_table->lock);
+
+       if (!srq) {
+               mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
+               return;
+       }
+
+       srq->event(srq, event_type);
+
+       if (atomic_dec_and_test(&srq->refcount))
+               complete(&srq->free);
+}
+
+static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         int srq_num)
+{
+       return mlx4_cmd(dev, mailbox->dma, srq_num, 0, MLX4_CMD_SW2HW_SRQ,
+                       MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+                         int srq_num)
+{
+       return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
+                           mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ,
+                           MLX4_CMD_TIME_CLASS_A);
+}
+
+static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark)
+{
+       return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ,
+                       MLX4_CMD_TIME_CLASS_B);
+}
+
+int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
+                  u64 db_rec, struct mlx4_srq *srq)
+{
+       struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+       struct mlx4_cmd_mailbox *mailbox;
+       struct mlx4_srq_context *srq_context;
+       u64 mtt_addr;
+       int err;
+
+       srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
+       if (srq->srqn == -1)
+               return -ENOMEM;
+
+       err = mlx4_table_get(dev, &srq_table->table, srq->srqn);
+       if (err)
+               goto err_out;
+
+       err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn);
+       if (err)
+               goto err_put;
+
+       spin_lock_irq(&srq_table->lock);
+       err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
+       spin_unlock_irq(&srq_table->lock);
+       if (err)
+               goto err_cmpt_put;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox)) {
+               err = PTR_ERR(mailbox);
+               goto err_radix;
+       }
+
+       srq_context = mailbox->buf;
+       memset(srq_context, 0, sizeof *srq_context);
+
+       srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) |
+                                                     srq->srqn);
+       srq_context->logstride          = srq->wqe_shift - 4;
+       srq_context->log_page_size      = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
+
+       mtt_addr = mlx4_mtt_addr(dev, mtt);
+       srq_context->mtt_base_addr_h    = mtt_addr >> 32;
+       srq_context->mtt_base_addr_l    = cpu_to_be32(mtt_addr & 0xffffffff);
+       srq_context->pd                 = cpu_to_be32(pdn);
+       srq_context->db_rec_addr        = cpu_to_be64(db_rec);
+
+       err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn);
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       if (err)
+               goto err_radix;
+
+       atomic_set(&srq->refcount, 1);
+       init_completion(&srq->free);
+
+       return 0;
+
+err_radix:
+       spin_lock_irq(&srq_table->lock);
+       radix_tree_delete(&srq_table->tree, srq->srqn);
+       spin_unlock_irq(&srq_table->lock);
+
+err_cmpt_put:
+       mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn);
+
+err_put:
+       mlx4_table_put(dev, &srq_table->table, srq->srqn);
+
+err_out:
+       mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_srq_alloc);
+
+void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
+{
+       struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+       int err;
+
+       err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn);
+       if (err)
+               mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn);
+
+       spin_lock_irq(&srq_table->lock);
+       radix_tree_delete(&srq_table->tree, srq->srqn);
+       spin_unlock_irq(&srq_table->lock);
+
+       if (atomic_dec_and_test(&srq->refcount))
+               complete(&srq->free);
+       wait_for_completion(&srq->free);
+
+       mlx4_table_put(dev, &srq_table->table, srq->srqn);
+       mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
+}
+EXPORT_SYMBOL_GPL(mlx4_srq_free);
+
+int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark)
+{
+       return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark);
+}
+EXPORT_SYMBOL_GPL(mlx4_srq_arm);
+
+int __devinit mlx4_init_srq_table(struct mlx4_dev *dev)
+{
+       struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+       int err;
+
+       spin_lock_init(&srq_table->lock);
+       INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
+
+       err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
+                              dev->caps.num_srqs - 1, dev->caps.reserved_srqs);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
+{
+       mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap);
+}
index 223e0e6264ba75c536fb72f6c6d3f454832a6975..4cf0d3fcb519d741559d9e016178f455a75884c3 100644 (file)
@@ -131,7 +131,6 @@ static const char version[] __devinitdata =
   KERN_INFO DRV_NAME " dp8381x driver, version "
       DRV_VERSION ", " DRV_RELDATE "\n"
   KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
-  KERN_INFO "  http://www.scyld.com/network/natsemi.html\n"
   KERN_INFO "  2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
index 589785d1e762d1b280f9c267435b9535f93c3318..995c0a5d40662ec1c7c1238faeb9bc74384c29be 100644 (file)
@@ -63,8 +63,7 @@ static int options[MAX_UNITS];
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n"
-KERN_INFO "  http://www.scyld.com/network/ne2k-pci.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
 
 #if defined(__powerpc__)
 #define inl_le(addr)  le32_to_cpu(inl(addr))
index 1060154ae750279138d8bd9414a3049beba5a369..4ecb8ca5a992ec318cfd9c58cbc21f116d56287c 100644 (file)
@@ -189,16 +189,20 @@ static void ibmtr_detach(struct pcmcia_device *link)
 {
     struct ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
+     struct tok_info *ti = netdev_priv(dev);
 
     DEBUG(0, "ibmtr_detach(0x%p)\n", link);
+    
+    /* 
+     * When the card removal interrupt hits tok_interrupt(), 
+     * bail out early, so we don't crash the machine 
+     */
+    ti->sram_phys |= 1;
 
     if (link->dev_node)
        unregister_netdev(dev);
-
-    {
-       struct tok_info *ti = netdev_priv(dev);
-       del_timer_sync(&(ti->tr_timer));
-    }
+    
+    del_timer_sync(&(ti->tr_timer));
 
     ibmtr_release(link);
 
index f994f129f3d8c17477edc0aded181253f57603de..c0d3101eb6a0a5891876fe32262191ccd98244be 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "PHY device support"
+       depends on !S390
 
 config PHYLIB
        tristate "PHY Device support and infrastructure"
index eed433d6056a2ddae3bad391e09ebec087892475..f71dab347667cd3fc33b408aaa55c0fdf7e4e570 100644 (file)
@@ -662,10 +662,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
                phy_error(phydev);
 
        /*
-        * Finish any pending work; we might have been scheduled
-        * to be called from keventd ourselves, though.
+        * Finish any pending work; we might have been scheduled to be called
+        * from keventd ourselves, but cancel_work_sync() handles that.
         */
-       run_scheduled_work(&phydev->phy_queue);
+       cancel_work_sync(&phydev->phy_queue);
 
        free_irq(phydev->irq, phydev);
 
index b07da1054add14a8d26af46ce418b6a2c7f24866..e0489578945dccda63d486d83e1d55b5228a2753 100644 (file)
@@ -3594,7 +3594,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        skge->duplex = -1;
        skge->speed = -1;
        skge->advertising = skge_supported_modes(hw);
-       skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
+
+       if (pci_wake_enabled(hw->pdev))
+               skge->wol = wol_supported(hw) & WAKE_MAGIC;
 
        hw->dev[port] = dev;
 
index f51ba31970aa34766482f629b147831cc4542efa..e1f912d04043e82c3de70201ed87d0ceb7b097f2 100644 (file)
@@ -110,8 +110,7 @@ static char *media[MAX_UNITS];
 
 /* These identify the driver base version and may not be removed. */
 static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
-KERN_INFO "  http://www.scyld.com/network/sundance.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
index e5e901ecd80815e16bc8212b80ec047f85421a54..923b9c725cc3f4e5cd75434914dbb4ce466c151f 100644 (file)
@@ -3716,10 +3716,8 @@ static void tg3_reset_task(struct work_struct *work)
        unsigned int restart_timer;
 
        tg3_full_lock(tp, 0);
-       tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
 
        if (!netif_running(tp->dev)) {
-               tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
                tg3_full_unlock(tp);
                return;
        }
@@ -3750,8 +3748,6 @@ static void tg3_reset_task(struct work_struct *work)
                mod_timer(&tp->timer, jiffies + 1);
 
 out:
-       tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
-
        tg3_full_unlock(tp);
 }
 
@@ -7390,12 +7386,7 @@ static int tg3_close(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       /* Calling flush_scheduled_work() may deadlock because
-        * linkwatch_event() may be on the workqueue and it will try to get
-        * the rtnl_lock which we are holding.
-        */
-       while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
-               msleep(1);
+       cancel_work_sync(&tp->reset_task);
 
        netif_stop_queue(dev);
 
index 4d334cf5a243b905a4e65a9a3f3cf9fc66be42bf..bd9f4f428e5b8895d5cc8c281302e00e0c6bdfba 100644 (file)
@@ -2228,7 +2228,7 @@ struct tg3 {
 #define TG3_FLAG_JUMBO_RING_ENABLE     0x00800000
 #define TG3_FLAG_10_100_ONLY           0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG         0x02000000
-#define TG3_FLAG_IN_RESET_TASK         0x04000000
+
 #define TG3_FLAG_40BIT_DMA_BUG         0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS      0x10000000
 #define TG3_FLAG_SUPPORT_MSI           0x20000000
index 9b08afbd1f65e245648c4e7f3fc84531e9b7069e..ea896777bcafecc84fce5896b8256892541ea8f1 100644 (file)
@@ -269,7 +269,7 @@ done:
             This would turn on IM for devices that is not contributing
             to backlog congestion with unnecessary latency.
 
-             We monitor the the device RX-ring and have:
+             We monitor the device RX-ring and have:
 
              HW Interrupt Mitigation either ON or OFF.
 
index fa440706fb4aa28f2d7b285439aa2f10a0853f36..38f3b99716b8bb8c4357d9291d00fe181f29aeec 100644 (file)
@@ -1021,7 +1021,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
                np->tx_ring[entry].length |= DescEndRing;
 
        /* Now acquire the irq spinlock.
-        * The difficult race is the the ordering between
+        * The difficult race is the ordering between
         * increasing np->cur_tx and setting DescOwned:
         * - if np->cur_tx is increased first the interrupt
         *   handler could consider the packet as transmitted
index 985a1810ca5945a282cae4a384db1245a21a2705..2470b1ee33c03b2243f9ed40aa4b0071a321d949 100644 (file)
@@ -1043,7 +1043,7 @@ static int enable_promisc(struct xircom_private *card)
 
 
 /*
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
 
 Must be called in locked state with interrupts disabled
 */
index f2dd7763cd0b6661b23dfae1aaa74562f0a29153..f72573594121340f217336024e9a1aff192c30db 100644 (file)
@@ -639,7 +639,7 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
 
        typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
 
-       /* "I feel a presence... another warrior is on the the mesa."
+       /* "I feel a presence... another warrior is on the mesa."
         */
        wmb();
        iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
index d7aff8189377dacb7d0ee68d15e933fe266eee6c..0f667652fda9304ce04d479dfdbea05ba08270a8 100644 (file)
@@ -293,7 +293,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
                else {
                        init_enet_offset =
                            qe_muram_alloc(thread_size, thread_alignment);
-                       if (IS_MURAM_ERR(init_enet_offset)) {
+                       if (IS_ERR_VALUE(init_enet_offset)) {
                                ugeth_err
                ("fill_init_enet_entries: Can not allocate DPRAM memory.");
                                qe_put_snum((u8) snum);
@@ -2594,7 +2594,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                        ugeth->tx_bd_ring_offset[j] =
                            qe_muram_alloc(length,
                                           UCC_GETH_TX_BD_RING_ALIGNMENT);
-                       if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j]))
+                       if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j]))
                                ugeth->p_tx_bd_ring[j] =
                                    (u8 *) qe_muram_addr(ugeth->
                                                         tx_bd_ring_offset[j]);
@@ -2629,7 +2629,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                        ugeth->rx_bd_ring_offset[j] =
                            qe_muram_alloc(length,
                                           UCC_GETH_RX_BD_RING_ALIGNMENT);
-                       if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j]))
+                       if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j]))
                                ugeth->p_rx_bd_ring[j] =
                                    (u8 *) qe_muram_addr(ugeth->
                                                         rx_bd_ring_offset[j]);
@@ -2713,7 +2713,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        ugeth->tx_glbl_pram_offset =
            qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
                           UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) {
+       if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
                     __FUNCTION__);
@@ -2735,7 +2735,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                           sizeof(struct ucc_geth_thread_data_tx) +
                           32 * (numThreadsTxNumerical == 1),
                           UCC_GETH_THREAD_DATA_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) {
+       if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
                     __FUNCTION__);
@@ -2763,7 +2763,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
            qe_muram_alloc(ug_info->numQueuesTx *
                           sizeof(struct ucc_geth_send_queue_qd),
                           UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) {
+       if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
                     __FUNCTION__);
@@ -2806,7 +2806,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                ugeth->scheduler_offset =
                    qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
                                   UCC_GETH_SCHEDULER_ALIGNMENT);
-               if (IS_MURAM_ERR(ugeth->scheduler_offset)) {
+               if (IS_ERR_VALUE(ugeth->scheduler_offset)) {
                        ugeth_err
                         ("%s: Can not allocate DPRAM memory for p_scheduler.",
                             __FUNCTION__);
@@ -2854,7 +2854,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                    qe_muram_alloc(sizeof
                                   (struct ucc_geth_tx_firmware_statistics_pram),
                                   UCC_GETH_TX_STATISTICS_ALIGNMENT);
-               if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) {
+               if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) {
                        ugeth_err
                            ("%s: Can not allocate DPRAM memory for"
                                " p_tx_fw_statistics_pram.", __FUNCTION__);
@@ -2893,7 +2893,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        ugeth->rx_glbl_pram_offset =
            qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
                           UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) {
+       if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
                     __FUNCTION__);
@@ -2914,7 +2914,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
            qe_muram_alloc(numThreadsRxNumerical *
                           sizeof(struct ucc_geth_thread_data_rx),
                           UCC_GETH_THREAD_DATA_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) {
+       if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
                     __FUNCTION__);
@@ -2937,7 +2937,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                    qe_muram_alloc(sizeof
                                   (struct ucc_geth_rx_firmware_statistics_pram),
                                   UCC_GETH_RX_STATISTICS_ALIGNMENT);
-               if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) {
+               if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) {
                        ugeth_err
                                ("%s: Can not allocate DPRAM memory for"
                                " p_rx_fw_statistics_pram.", __FUNCTION__);
@@ -2959,7 +2959,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
            qe_muram_alloc(ug_info->numQueuesRx *
                           sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
                           + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
+       if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for"
                        " p_rx_irq_coalescing_tbl.", __FUNCTION__);
@@ -3027,7 +3027,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                           (sizeof(struct ucc_geth_rx_bd_queues_entry) +
                            sizeof(struct ucc_geth_rx_prefetched_bds)),
                           UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
-       if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) {
+       if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
                     __FUNCTION__);
@@ -3116,7 +3116,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                ugeth->exf_glbl_param_offset =
                    qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
                UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
-               if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) {
+               if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) {
                        ugeth_err
                                ("%s: Can not allocate DPRAM memory for"
                                " p_exf_glbl_param.", __FUNCTION__);
@@ -3258,7 +3258,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
 
        /* Allocate InitEnet command parameter structure */
        init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
-       if (IS_MURAM_ERR(init_enet_pram_offset)) {
+       if (IS_ERR_VALUE(init_enet_pram_offset)) {
                ugeth_err
                    ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
                     __FUNCTION__);
similarity index 99%
rename from drivers/usb/net/usbnet.h
rename to drivers/net/usb/usbnet.h
index cbb53e065d6c198626151f3a9f4235263bd79aa8..82db5a8e528e57b95ad40c369afb31b7298c2aa6 100644 (file)
@@ -129,7 +129,7 @@ extern void usbnet_disconnect(struct usb_interface *);
 
 
 /* Drivers that reuse some of the standard USB CDC infrastructure
- * (notably, using multiple interfaces according to the the CDC
+ * (notably, using multiple interfaces according to the CDC
  * union descriptor) get some helper code.
  */
 struct cdc_state {
index e273347dc6068b5dcad2653a46f02b07f17f3aef..e3f5bb0fe603cf66eab0dc6118bbd1d6a4e34e21 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Wireless LAN"
+       depends on !S390
 
 config WLAN_PRE80211
        bool "Wireless LAN (pre-802.11)"
index 38fac3bbcd823b0e568fef8729961dac95fd2c3d..7d5b8c2cc614ef3970ce34c9279cad6700758bfc 100644 (file)
@@ -149,7 +149,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
        /* Vitally important.  If we don't do this it seems we get an
         * interrupt somewhere during the power cycle, since
         * hw_unavailable is already set it doesn't get ACKed, we get
-        * into an interrupt loop and the the PMU decides to turn us
+        * into an interrupt loop and the PMU decides to turn us
         * off. */
        disable_irq(dev->irq);
 
index f8483c179e4c9d4a1c6dcaf23bab05da0423e9ac..10e07e8654260fa8bf4bf61436e51d8d47b391c3 100644 (file)
@@ -658,12 +658,6 @@ struct bcm43xx_pio {
 
 #define BCM43xx_MAX_80211_CORES                2
 
-#ifdef CONFIG_BCM947XX
-#define core_offset(bcm) (bcm)->current_core_offset
-#else
-#define core_offset(bcm) 0
-#endif
-
 /* Generic information about a core. */
 struct bcm43xx_coreinfo {
        u8 available:1,
@@ -789,10 +783,6 @@ struct bcm43xx_private {
 
        /* The currently active core. */
        struct bcm43xx_coreinfo *current_core;
-#ifdef CONFIG_BCM947XX
-       /** current core memory offset */
-       u32 current_core_offset;
-#endif
        struct bcm43xx_coreinfo *active_80211_core;
        /* coreinfo structs for all possible cores follow.
         * Note that a core might not exist.
@@ -943,25 +933,25 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
 static inline
 u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
 {
-       return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+       return ioread16(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
 {
-       iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+       iowrite16(value, bcm->mmio_addr + offset);
 }
 
 static inline
 u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
 {
-       return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+       return ioread32(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
 {
-       iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+       iowrite32(value, bcm->mmio_addr + offset);
 }
 
 static inline
index e3d2e61a31eef7fb3b7593beb5f28d337b8ebd1a..1f7731fcfbd57a22dffcb3cab6809921baf0b361 100644 (file)
@@ -660,10 +660,6 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
        ring->routing = BCM43xx_DMA32_CLIENTTRANS;
        if (dma64)
                ring->routing = BCM43xx_DMA64_CLIENTTRANS;
-#ifdef CONFIG_BCM947XX
-       if (bcm->pci_dev->bus->number == 0)
-               ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
-#endif
 
        ring->bcm = bcm;
        ring->nr_slots = nr_slots;
index 5e96bca6730a470df027e7f10a62899f1c331cf5..ef6b253a92cec27d09039af365888cf18d3783d3 100644 (file)
@@ -61,10 +61,6 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_BCM947XX
-extern char *nvram_get(char *name);
-#endif
-
 #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
@@ -142,10 +138,6 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple fi
        { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 43XG 802.11b/g */
        { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#ifdef CONFIG_BCM947XX
-       /* SB bus on BCM947xx */
-       { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#endif
        { 0 },
 };
 MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
@@ -786,9 +778,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 {
        u16 value;
        u16 *sprom;
-#ifdef CONFIG_BCM947XX
-       char *c;
-#endif
 
        sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
                        GFP_KERNEL);
@@ -796,28 +785,7 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
                printk(KERN_ERR PFX "sprom_extract OOM\n");
                return -ENOMEM;
        }
-#ifdef CONFIG_BCM947XX
-       sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
-       sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
-
-       if ((c = nvram_get("il0macaddr")) != NULL)
-               e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
-
-       if ((c = nvram_get("et1macaddr")) != NULL)
-               e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
-
-       sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
-       sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
-       sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
-
-       sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
-       sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
-       sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
-
-       sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
-#else
        bcm43xx_sprom_read(bcm, sprom);
-#endif
 
        /* boardflags2 */
        value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
@@ -1225,12 +1193,6 @@ static int _switch_core(struct bcm43xx_private *bcm, int core)
                        goto error;
                udelay(10);
        }
-#ifdef CONFIG_BCM947XX
-       if (bcm->pci_dev->bus->number == 0)
-               bcm->current_core_offset = 0x1000 * core;
-       else
-               bcm->current_core_offset = 0;
-#endif
 
        return 0;
 error:
@@ -1387,19 +1349,6 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
 
        if ((bcm43xx_core_enabled(bcm)) &&
            !bcm43xx_using_pio(bcm)) {
-//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
-#if 0
-#ifndef CONFIG_BCM947XX
-               /* reset all used DMA controllers. */
-               bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-               bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
-               bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
-               bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-               bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-               if (bcm->current_core->rev < 5)
-                       bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-#endif
-#endif
        }
        if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
                bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -2140,32 +2089,11 @@ out:
        return err;
 }
 
-#ifdef CONFIG_BCM947XX
-static struct pci_device_id bcm43xx_47xx_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-       { 0 }
-};
-#endif
-
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
        int err;
 
        bcm->irq = bcm->pci_dev->irq;
-#ifdef CONFIG_BCM947XX
-       if (bcm->pci_dev->bus->number == 0) {
-               struct pci_dev *d;
-               struct pci_device_id *id;
-               for (id = bcm43xx_47xx_ids; id->vendor; id++) {
-                       d = pci_get_device(id->vendor, id->device, NULL);
-                       if (d != NULL) {
-                               bcm->irq = d->irq;
-                               pci_dev_put(d);
-                               break;
-                       }
-               }
-       }
-#endif
        err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
                          IRQF_SHARED, KBUILD_MODNAME, bcm);
        if (err)
@@ -2645,10 +2573,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
                        chip_id_16 = 0x4610;
                else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
                        chip_id_16 = 0x4710;
-#ifdef CONFIG_BCM947XX
-               else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
-                       chip_id_16 = 0x4309;
-#endif
                else {
                        printk(KERN_ERR PFX "Could not determine Chip ID\n");
                        return -ENODEV;
@@ -4144,11 +4068,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
        struct bcm43xx_private *bcm;
        int err;
 
-#ifdef CONFIG_BCM947XX
-       if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
-               return -ENODEV;
-#endif
-
 #ifdef DEBUG_SINGLE_DEVICE_ONLY
        if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
                return -ENODEV;
index f76357178e4d3535f982b070e6422de212c39426..c8f3c532bab5d8b28bc482de6cd59328cec95ba6 100644 (file)
 
 #include "bcm43xx.h"
 
-#ifdef CONFIG_BCM947XX
-#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-
-static inline void e_aton(char *str, char *dest)
-{
-       int i = 0;
-       u16 *d = (u16 *) dest;
-
-       for (;;) {
-               dest[i++] = (char) simple_strtoul(str, NULL, 16);
-               str += 2;
-               if (!*str++ || i == 6)
-                       break;
-       }
-       for (i = 0; i < 3; i++)
-               d[i] = cpu_to_be16(d[i]);
-}
-#endif
-
 #define P4D_BYT3S(magic, nr_bytes)     u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)      P4D_BYT3S(line, nr_bytes)
 /* Magic helper macro to pad structures. Ignore those above. It's magic. */
index 841b3c136ad951d47ed6ca0aeb53b8d605550061..283be4a70524b650920b02e86506d5ffab1940d7 100644 (file)
@@ -3054,7 +3054,7 @@ static const iw_handler prism54_handler[] = {
        (iw_handler) prism54_set_wap,   /* SIOCSIWAP */
        (iw_handler) prism54_get_wap,   /* SIOCGIWAP */
        (iw_handler) NULL,      /* -- hole -- */
-       (iw_handler) NULL,      /* SIOCGIWAPLIST depreciated */
+       (iw_handler) NULL,      /* SIOCGIWAPLIST deprecated */
        (iw_handler) prism54_set_scan,  /* SIOCSIWSCAN */
        (iw_handler) prism54_get_scan,  /* SIOCGIWSCAN */
        (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
index a037b11dac9da840645624cb5e28d165ecc76bcb..084795355b74a312cac2bdf29c10b6a01088e528 100644 (file)
@@ -115,7 +115,7 @@ isl_upload_firmware(islpci_private *priv)
                            ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
                        u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
 
-                       /* set the cards base address for writting the data */
+                       /* set the card's base address for writing the data */
                        isl38xx_w32_flush(device_base, reg,
                                          ISL38XX_DIR_MEM_BASE_REG);
                        wmb();  /* be paranoid */
index 67b867f837ca49e0aaca4b96aadeeacdb996b8ba..5740d4d4267c657b762d90db692c9a2ff45f19ab 100644 (file)
@@ -176,7 +176,7 @@ psa_write(struct net_device *       dev,
   volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
     (psaoff(0, psa_comp_number) << 1);
 
-  /* Authorize writting to PSA */
+  /* Authorize writing to PSA */
   hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
 
   while(n-- > 0)
@@ -1676,7 +1676,7 @@ wv_set_frequency(u_long           base,   /* i/o port of the card */
       fee_write(base, 0x60,
                dac, 2);
 
-      /* We now should verify here that the EEprom writting was ok */
+      /* We now should verify here that the EEprom writing was ok */
 
       /* ReRead the first area */
       fee_read(base, 0x00,
index 4d1c4905c7494d04b33a4239234dcc19395a166e..4b9de0093a7b2314bf6439512b21f47fe8d6668a 100644 (file)
  * the Wavelan itself (NCR -> AT&T -> Lucent).
  *
  * All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * writing a Wavelan ISA driver for the MACH microkernel. Girish
  * Welling <welling@paul.rutgers.edu> had also worked on it.
  * Keith Moore modify this for the Pcmcia hardware.
  * 
index e04cffc8adf305240d6f7f5923af55550f91262d..8459549d0cee6e8c3e1375b7e3deedd9371430e4 100644 (file)
@@ -40,6 +40,7 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
        { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
@@ -67,8 +68,11 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+       { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
        {}
 };
 
index 3f4a7cf9efeaaa785e802c50347b055bca61b4b1..f2a90a7fa2d6ff9fb826224342ecec58ad3b6ced 100644 (file)
@@ -109,7 +109,6 @@ static int gx_fix;
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  http://www.scyld.com/network/yellowfin.html\n"
 KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
index 36c6a1bfe558374dc76a9124375f0c06c92bfded..f46c69e4ed829772c190cf2fbfa6910c300613c6 100644 (file)
@@ -6,6 +6,7 @@
 #
 
 menu "Parallel port support"
+       depends on HAS_IOMEM
 
 config PARPORT
        tristate "Parallel port support"
index 3bb7739d26a50af35f6c7344a1cda7daa1fbefdc..8e58ea3d95c09fab4c72656a616a33cd5c73f84a 100644 (file)
@@ -119,7 +119,7 @@ static inline int pci_create_newid_file(struct pci_driver *drv)
  * system is in its list of supported devices.  Returns the matching
  * pci_device_id structure or %NULL if there is no match.
  *
- * Depreciated, don't use this as it will not catch any dynamic ids
+ * Deprecated, don't use this as it will not catch any dynamic ids
  * that a driver might want to check for.
  */
 const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
index c5143201419aebdeff65e7a2ad3e121e6bbd503f..1959cef8e9debc6e613882ebfd06427ecab929d2 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Plug and Play support"
+       depends on HAS_IOMEM
 
 config PNP
        bool "Plug and Play support"
index 5e439836db2d534da615ff0114d9358ad9c7b5fd..ad445d5e58c7198a1ab0b6d27bad19cf580f5a39 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Real Time Clock"
+       depends on !S390
 
 config RTC_LIB
        tristate
@@ -98,7 +99,7 @@ config RTC_INTF_DEV_UIE_EMUL
        bool "RTC UIE emulation on dev interface"
        depends on RTC_INTF_DEV
        help
-         Provides an emulation for RTC_UIE if the underlaying rtc chip
+         Provides an emulation for RTC_UIE if the underlying rtc chip
          driver does not expose RTC_UIE ioctls.  Those requests generate
          once-per-second update interrupts, used for synchronization.
 
@@ -396,7 +397,7 @@ config RTC_DRV_BFIN
 
 config RTC_DRV_RS5C313
        tristate "Ricoh RS5C313"
-       depends on RTC_CLASS && BROKEN
+       depends on RTC_CLASS && SH_LANDISK
        help
          If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
index 9d6de371495b9848e518ebb82d425a51c07167a9..66eb133bf5fddf98c6df9382b249bf3596e49989 100644 (file)
@@ -126,7 +126,7 @@ static void rs5c313_write_data(unsigned char data)
 static unsigned char rs5c313_read_data(void)
 {
        int i;
-       unsigned char data;
+       unsigned char data = 0;
 
        for (i = 0; i < 8; i++) {
                ndelay(700);
@@ -194,7 +194,7 @@ static void rs5c313_write_reg(unsigned char addr, unsigned char data)
        return;
 }
 
-static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+static inline unsigned char rs5c313_read_cntreg(void)
 {
        return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
 }
@@ -212,7 +212,9 @@ static inline void rs5c313_write_intintvreg(unsigned char data)
 static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        int data;
+       int cnt;
 
+       cnt = 0;
        while (1) {
                RS5C313_CEENABLE;       /* CE:H */
 
@@ -225,6 +227,10 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
                RS5C313_CEDISABLE;
                ndelay(700);    /* CE:L */
 
+               if (cnt++ > 100) {
+                       dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+                       return -EIO;
+               }
        }
 
        data = rs5c313_read_reg(RS5C313_ADDR_SEC);
@@ -266,7 +272,9 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        int data;
+       int cnt;
 
+       cnt = 0;
        /* busy check. */
        while (1) {
                RS5C313_CEENABLE;       /* CE:H */
@@ -279,6 +287,11 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
                RS5C313_MISCOP;
                RS5C313_CEDISABLE;
                ndelay(700);    /* CE:L */
+
+               if (cnt++ > 100) {
+                       dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+                       return -EIO;
+               }
        }
 
        data = BIN2BCD(tm->tm_sec);
@@ -317,6 +330,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 static void rs5c313_check_xstp_bit(void)
 {
        struct rtc_time tm;
+       int cnt;
 
        RS5C313_CEENABLE;       /* CE:H */
        if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
@@ -326,12 +340,16 @@ static void rs5c313_check_xstp_bit(void)
                rs5c313_write_cntreg(0x07);
 
                /* busy check. */
-               while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+               for (cnt = 0; cnt < 100; cnt++) {
+                       if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+                               break;
                        RS5C313_MISCOP;
+               }
 
                memset(&tm, 0, sizeof(struct rtc_time));
                tm.tm_mday      = 1;
-               tm.tm_mon       = 1;
+               tm.tm_mon       = 1 - 1;
+               tm.tm_year      = 2000 - 1900;
 
                rs5c313_rtc_set_time(NULL, &tm);
                printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
@@ -356,7 +374,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
-       return err;
+       return 0;
 }
 
 static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
index 6abf4811958c3969270fb09e3f8fffd23b656013..e0f91dfce0f56bcb8f340058d208557e613a44dd 100644 (file)
@@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
 
        writeb(tmp, rtc->regbase + RCR1);
 
-       rtc_update_irq(&rtc->rtc_dev, 1, events);
+       rtc_update_irq(rtc->rtc_dev, 1, events);
 
        spin_unlock(&rtc->lock);
 
@@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
 
                rtc->rearm_aie = 1;
 
-               rtc_update_irq(&rtc->rtc_dev, 1, events);
+               rtc_update_irq(rtc->rtc_dev, 1, events);
        }
 
        spin_unlock(&rtc->lock);
@@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
 
        spin_lock(&rtc->lock);
 
-       rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
+       rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
 
        spin_unlock(&rtc->lock);
 
@@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_sec--;
 #endif
 
-       dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
                "mday=%d, mon=%d, year=%d, wday=%d\n",
                __FUNCTION__,
                tm->tm_sec, tm->tm_min, tm->tm_hour,
index b250c53545033cba2a019ee4e5973bf1bac04551..e879b212cf4367441e853c5e7681850ae0e57a9b 100644 (file)
@@ -1,11 +1,9 @@
-if S390 && BLOCK
-
 comment "S/390 block device drivers"
-       depends on S390
+       depends on S390 && BLOCK
 
 config BLK_DEV_XPRAM
        tristate "XPRAM disk support"
-       depends on S390
+       depends on S390 && BLOCK
        help
          Select this option if you want to use your expanded storage on S/390
          or zSeries as a disk.  This is useful as a _fast_ swap device if you
@@ -15,12 +13,13 @@ config BLK_DEV_XPRAM
 
 config DCSSBLK
        tristate "DCSSBLK support"
+       depends on S390 && BLOCK
        help
          Support for dcss block device
 
 config DASD
        tristate "Support for DASD devices"
-       depends on CCW
+       depends on CCW && BLOCK
        help
          Enable this option if you want to access DASDs directly utilizing
          S/390s channel subsystem commands. This is necessary for running
@@ -62,5 +61,3 @@ config DASD_EER
          This driver provides a character device interface to the
          DASD extended error reporting. This is only needed if you want to
          use applications written for the EER facility.
-
-endif
index 977521013fe8065c6be213c7aaecda48792e6a91..bfeca57098fa6725edd53546e1466f78e6aceed9 100644 (file)
@@ -2174,9 +2174,10 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
-struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device,
-                                            void *rdc_buffer,
-                                            int rdc_buffer_size, char *magic)
+static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
+                                                  void *rdc_buffer,
+                                                  int rdc_buffer_size,
+                                                  char *magic)
 {
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
@@ -2219,6 +2220,7 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
        dasd_sfree_request(cqr, cqr->device);
        return ret;
 }
+EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
 
 static int __init
 dasd_init(void)
index e810e4a44ed4ea2105b9c6169487e21d78d20e43..eccac1c3b71bb86ef535300a21c4311ebce343a9 100644 (file)
@@ -50,6 +50,7 @@ struct dasd_diag_private {
        struct dasd_diag_rw_io iob;
        struct dasd_diag_init_io iib;
        blocknum_t pt_block;
+       struct ccw_dev_id dev_id;
 };
 
 struct dasd_diag_req {
@@ -102,7 +103,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
        iib = &private->iib;
        memset(iib, 0, sizeof (struct dasd_diag_init_io));
 
-       iib->dev_nr = _ccw_device_get_device_number(device->cdev);
+       iib->dev_nr = private->dev_id.devno;
        iib->block_size = blocksize;
        iib->offset = offset;
        iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
@@ -127,7 +128,7 @@ mdsk_term_io(struct dasd_device * device)
        private = (struct dasd_diag_private *) device->private;
        iib = &private->iib;
        memset(iib, 0, sizeof (struct dasd_diag_init_io));
-       iib->dev_nr = _ccw_device_get_device_number(device->cdev);
+       iib->dev_nr = private->dev_id.devno;
        rc = dia250(iib, TERM_BIO);
        return rc;
 }
@@ -166,7 +167,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
        private = (struct dasd_diag_private *) device->private;
        dreq = (struct dasd_diag_req *) cqr->data;
 
-       private->iob.dev_nr = _ccw_device_get_device_number(device->cdev);
+       private->iob.dev_nr = private->dev_id.devno;
        private->iob.key = 0;
        private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
        private->iob.block_count = dreq->block_count;
@@ -323,11 +324,12 @@ dasd_diag_check_device(struct dasd_device *device)
                                "memory allocation failed for private data");
                        return -ENOMEM;
                }
+               ccw_device_get_id(device->cdev, &private->dev_id);
                device->private = (void *) private;
        }
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
-       rdc_data->dev_nr = _ccw_device_get_device_number(device->cdev);
+       rdc_data->dev_nr = private->dev_id.devno;
        rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
 
        rc = diag210((struct diag210 *) rdc_data);
index c9583fbc2a7dd8893e924f6be665efdcf672a2c6..418b4e63a4fab42473f9d650073171a81543a8b4 100644 (file)
@@ -450,9 +450,9 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
        return 0;
 }
 
-struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device,
-                                             void *rcd_buffer,
-                                             struct ciw *ciw, __u8 lpm)
+static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+                                                   void *rcd_buffer,
+                                                   struct ciw *ciw, __u8 lpm)
 {
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
index 758cfb54286570b2333998adcf2180bf20ee32c5..672eb0a3dd0bd4e5e48a71ce33456ee0ce668dc6 100644 (file)
@@ -255,6 +255,7 @@ dasd_ioctl_information(struct dasd_device *device,
        unsigned long flags;
        int rc;
        struct ccw_device *cdev;
+       struct ccw_dev_id dev_id;
 
        if (!device->discipline->fill_info)
                return -EINVAL;
@@ -270,8 +271,9 @@ dasd_ioctl_information(struct dasd_device *device,
        }
 
        cdev = device->cdev;
+       ccw_device_get_id(cdev, &dev_id);
 
-       dasd_info->devno = _ccw_device_get_device_number(device->cdev);
+       dasd_info->devno = dev_id.devno;
        dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
        dasd_info->cu_type = cdev->id.cu_type;
        dasd_info->cu_model = cdev->id.cu_model;
similarity index 59%
rename from drivers/s390/Kconfig
rename to drivers/s390/char/Kconfig
index 165af398fdead8b181edc120ae91ed6a364f1cb3..66102a1843220ab4c8e0e77483e8f7aba3030bce 100644 (file)
@@ -1,69 +1,9 @@
-config CCW
-       bool
-       default y
-
-source "drivers/block/Kconfig"
-
-source "drivers/md/Kconfig"
-
-
-menu "Character device drivers"
-
-config UNIX98_PTYS
-       bool "Unix98 PTY support"
-       ---help---
-         A pseudo terminal (PTY) is a software device consisting of two
-         halves: a master and a slave. The slave device behaves identical to
-         a physical terminal; the master device is used by a process to
-         read data from and write data to the slave, thereby emulating a
-         terminal. Typical programs for the master side are telnet servers
-         and xterms.
-
-         Linux has traditionally used the BSD-like names /dev/ptyxx for
-         masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-         has a number of problems. The GNU C library glibc 2.1 and later,
-         however, supports the Unix98 naming standard: in order to acquire a
-         pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-         terminal is then made available to the process and the pseudo
-         terminal slave can be accessed as /dev/pts/<number>. What was
-         traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-         The entries in /dev/pts/ are created on the fly by a virtual
-         file system; therefore, if you say Y here you should say Y to
-         "/dev/pts file system for Unix98 PTYs" as well.
-
-         If you want to say Y here, you need to have the C library glibc 2.1
-         or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-         Read the instructions in <file:Documentation/Changes> pertaining to
-         pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
-       int "Maximum number of Unix98 PTYs in use (0-2048)"
-       depends on UNIX98_PTYS
-       default "256"
-       help
-         The maximum number of Unix98 PTYs that can be used at any one time.
-         The default is 256, and should be enough for desktop systems. Server
-         machines which support incoming telnet/rlogin/ssh connections and/or
-         serve several X terminals may want to increase this: every incoming
-         connection and every xterm uses up one PTY.
-
-         When not in use, each additional set of 256 PTYs occupy
-         approximately 8 KB of kernel memory on 32-bit architectures.
-
-config HANGCHECK_TIMER
-       tristate "Hangcheck timer"
-       help
-         The hangcheck-timer module detects when the system has gone
-         out to lunch past a certain margin.  It can reboot the system
-         or merely print a warning.
-
-source "drivers/char/watchdog/Kconfig"
-
 comment "S/390 character device drivers"
+       depends on S390
 
 config TN3270
        tristate "Support for locally attached 3270 terminals"
+       depends on CCW
        help
          Include support for IBM 3270 terminals.
 
@@ -88,6 +28,7 @@ config TN3270_CONSOLE
 
 config TN3215
        bool "Support for 3215 line mode terminal"
+       depends on CCW
        help
          Include support for IBM 3215 line-mode terminals.
 
@@ -99,12 +40,19 @@ config TN3215_CONSOLE
          Linux system console.
 
 config CCW_CONSOLE
-       bool
-       depends on TN3215_CONSOLE || TN3270_CONSOLE
-       default y
+       bool
+       depends on TN3215_CONSOLE || TN3270_CONSOLE
+       default y
+
+config SCLP
+       bool "Support for SCLP"
+       depends on S390
+       help
+         Include support for the SCLP interface to the service element.
+
 config SCLP_TTY
        bool "Support for SCLP line mode terminal"
+       depends on SCLP
        help
          Include support for IBM SCLP line-mode terminals.
 
@@ -117,6 +65,7 @@ config SCLP_CONSOLE
 
 config SCLP_VT220_TTY
        bool "Support for SCLP VT220-compatible terminal"
+       depends on SCLP
        help
          Include support for an IBM SCLP VT220-compatible terminal.
 
@@ -129,6 +78,7 @@ config SCLP_VT220_CONSOLE
 
 config SCLP_CPI
        tristate "Control-Program Identification"
+       depends on SCLP
        help
          This option enables the hardware console interface for system
          identification. This is commonly used for workload management and
@@ -140,6 +90,7 @@ config SCLP_CPI
 
 config S390_TAPE
        tristate "S/390 tape device support"
+       depends on CCW
        help
          Select this option if you want to access channel-attached tape
          devices on IBM S/390 or zSeries.
@@ -194,6 +145,7 @@ config VMLOGRDR
 
 config VMCP
        tristate "Support for the z/VM CP interface (VM only)"
+       depends on S390
        help
          Select this option if you want to be able to interact with the control
          program on z/VM
@@ -207,33 +159,8 @@ config MONREADER
 
 config MONWRITER
        tristate "API for writing z/VM monitor service records"
+       depends on S390
        default "m"
        help
          Character device driver for writing z/VM monitor service records
 
-endmenu
-
-menu "Cryptographic devices"
-
-config ZCRYPT
-       tristate "Support for PCI-attached cryptographic adapters"
-       select ZCRYPT_MONOLITHIC if ZCRYPT="y"
-       default "m"
-       help
-         Select this option if you want to use a PCI-attached cryptographic
-         adapter like:
-         + PCI Cryptographic Accelerator (PCICA)
-         + PCI Cryptographic Coprocessor (PCICC)
-         + PCI-X Cryptographic Coprocessor (PCIXCC)
-         + Crypto Express2 Coprocessor (CEX2C)
-         + Crypto Express2 Accelerator (CEX2A)
-
-config ZCRYPT_MONOLITHIC
-       bool "Monolithic zcrypt module"
-       depends on ZCRYPT="m"
-       help
-         Select this option if you want to have a single module z90crypt.ko
-         that contains all parts of the crypto device driver (ap bus,
-         request router and all the card drivers).
-
-endmenu
index 8df7b1323c053177f078c9e06798cd5a75909a7f..67009bfa093e12c8c0a828e9528f49021d84df20 100644 (file)
@@ -97,7 +97,7 @@ static u8 user_data_sever[16] = {
  * Create the 8 bytes EBCDIC DCSS segment name from
  * an ASCII name, incl. padding
  */
-static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
+static void dcss_mkname(char *ascii_name, char *ebcdic_name)
 {
        int i;
 
@@ -191,7 +191,7 @@ static inline u32 mon_rec_end(struct mon_msg *monmsg)
        return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
 }
 
-static inline int mon_check_mca(struct mon_msg *monmsg)
+static int mon_check_mca(struct mon_msg *monmsg)
 {
        if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
            (mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -209,8 +209,8 @@ static inline int mon_check_mca(struct mon_msg *monmsg)
        return 0;
 }
 
-static inline int mon_send_reply(struct mon_msg *monmsg,
-                                struct mon_private *monpriv)
+static int mon_send_reply(struct mon_msg *monmsg,
+                         struct mon_private *monpriv)
 {
        int rc;
 
@@ -236,7 +236,7 @@ static inline int mon_send_reply(struct mon_msg *monmsg,
        return 0;
 }
 
-static inline void mon_free_mem(struct mon_private *monpriv)
+static void mon_free_mem(struct mon_private *monpriv)
 {
        int i;
 
@@ -246,7 +246,7 @@ static inline void mon_free_mem(struct mon_private *monpriv)
        kfree(monpriv);
 }
 
-static inline struct mon_private *mon_alloc_mem(void)
+static struct mon_private *mon_alloc_mem(void)
 {
        int i;
        struct mon_private *monpriv;
@@ -307,7 +307,7 @@ static inline void mon_next_mca(struct mon_msg *monmsg)
        monmsg->pos = 0;
 }
 
-static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
+static struct mon_msg *mon_next_message(struct mon_private *monpriv)
 {
        struct mon_msg *monmsg;
 
index 8facd14adb7c168ab2d5c6137fd6eee63ffebbec..f6ef90ee3e7d83d06090ff594818d2f40fdd6c85 100644 (file)
@@ -589,9 +589,10 @@ static int
 __raw3270_size_device_vm(struct raw3270 *rp)
 {
        int rc, model;
+       struct ccw_dev_id dev_id;
 
-       raw3270_init_diag210.vrdcdvno = 
-               _ccw_device_get_device_number(rp->cdev);
+       ccw_device_get_id(rp->cdev, &dev_id);
+       raw3270_init_diag210.vrdcdvno = dev_id.devno;
        raw3270_init_diag210.vrdclen = sizeof(struct diag210);
        rc = diag210(&raw3270_init_diag210);
        if (rc)
index 87ac4a3ad49dccf9b4113e093f1ec015e0801273..dbb99d1b6f57ffa814f3f8b37c48abc5413e50c6 100644 (file)
@@ -132,6 +132,9 @@ int sclp_deactivate(void);
 int sclp_reactivate(void);
 int sclp_service_call(sclp_cmdw_t command, void *sccb);
 
+int sclp_sdias_init(void);
+void sclp_sdias_exit(void);
+
 /* useful inlines */
 
 /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */
index bbd5b8b66f420b9288a84a21ba89f622457afee3..d6b06ab81188884a1a63729653366a7ab4ee7b8d 100644 (file)
@@ -23,7 +23,7 @@
 
 /*
  * The room for the SCCB (only for writing) is not equal to a pages size
- * (as it is specified as the maximum size in the the SCLP documentation)
+ * (as it is specified as the maximum size in the SCLP documentation)
  * because of the additional data structure described above.
  */
 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
index 52283daddaef224db42cf70bd3ba421ab11b5059..1c064976b32bd322a4e4554e9d335bf1cef71328 100644 (file)
@@ -66,9 +66,9 @@ static DEFINE_MUTEX(sdias_mutex);
 
 static void sdias_callback(struct sclp_req *request, void *data)
 {
-       struct sdias_sccb *sccb;
+       struct sdias_sccb *cbsccb;
 
-       sccb = (struct sdias_sccb *) request->sccb;
+       cbsccb = (struct sdias_sccb *) request->sccb;
        sclp_req_done = 1;
        wake_up(&sdias_wq); /* Inform caller, that request is complete */
        TRACE("callback done\n");
@@ -229,7 +229,7 @@ out:
        return rc;
 }
 
-int __init sdias_init(void)
+int __init sclp_sdias_init(void)
 {
        int rc;
 
@@ -248,7 +248,7 @@ int __init sdias_init(void)
        return 0;
 }
 
-void __exit sdias_exit(void)
+void __exit sclp_sdias_exit(void)
 {
        debug_unregister(sdias_dbf);
        sclp_unregister(&sclp_sdias_register);
index 89d439316a531cb3373a16b780de0fecc8cf7c78..66eb0688d523491b0749651f8f02ea7d4ef926ce 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/debug.h>
 #include <asm/processor.h>
 #include <asm/irqflags.h>
+#include "sclp.h"
 
 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
 #define MSG(x...) printk( KERN_ALERT x )
@@ -564,8 +565,6 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr)
        get_cpu_id(&hdr->cpu_id);
 }
 
-extern int sdias_init(void);
-
 static int __init zcore_init(void)
 {
        unsigned char arch;
@@ -582,7 +581,7 @@ static int __init zcore_init(void)
        TRACE("wwpn:   %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
        TRACE("lun:    %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
 
-       rc = sdias_init();
+       rc = sclp_sdias_init();
        if (rc)
                goto fail;
 
@@ -634,12 +633,10 @@ fail:
        return rc;
 }
 
-extern void sdias_exit(void);
-
 static void __exit zcore_exit(void)
 {
        debug_unregister(zcore_dbf);
-       sdias_exit();
+       sclp_sdias_exit();
        diag308(DIAG308_REL_HSA, NULL);
 }
 
index 27c6d9e55b23e41142309750fbd3afb799a2a8c3..dfca0ef139fdc374cddc8bb0ef452b24a10ccd78 100644 (file)
@@ -191,8 +191,7 @@ static int css_register_subchannel(struct subchannel *sch)
        return ret;
 }
 
-int
-css_probe_device(struct subchannel_id schid)
+static int css_probe_device(struct subchannel_id schid)
 {
        int ret;
        struct subchannel *sch;
index 71fcfdc42800d39d0433d51cbf1e6f30be521f37..ed7977531c3f8a14d9e345f86130107e1e582442 100644 (file)
@@ -138,9 +138,7 @@ struct css_driver {
  * all css_drivers have the css_bus_type
  */
 extern struct bus_type css_bus_type;
-extern struct css_driver io_subchannel_driver;
 
-extern int css_probe_device(struct subchannel_id);
 extern int css_sch_device_register(struct subchannel *);
 extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
index a23ff582db9ddf03b303aa6647d2d353f7e96294..a8b373f69cf0ef2d61ab1315b3b191f4276e39e9 100644 (file)
@@ -129,7 +129,7 @@ static void io_subchannel_verify(struct device *);
 static void io_subchannel_ioterm(struct device *);
 static void io_subchannel_shutdown(struct subchannel *);
 
-struct css_driver io_subchannel_driver = {
+static struct css_driver io_subchannel_driver = {
        .subchannel_type = SUBCHANNEL_TYPE_IO,
        .drv = {
                .name = "io_subchannel",
@@ -546,7 +546,7 @@ static struct attribute_group ccwdev_attr_group = {
        .attrs = ccwdev_attrs,
 };
 
-struct attribute_group *ccwdev_attr_groups[] = {
+static struct attribute_group *ccwdev_attr_groups[] = {
        &ccwdev_attr_group,
        NULL,
 };
index 16f59fcb66b13938480a497f4d2deeda2d9fa669..a5d263fb55ae1722ff0aced679d55df0978e7546 100644 (file)
@@ -616,6 +616,17 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
        return chp_get_chp_desc(chpid);
 }
 
+/**
+ * ccw_device_get_id - obtain a ccw device id
+ * @cdev: device to obtain the id for
+ * @dev_id: where to fill in the values
+ */
+void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id)
+{
+       *dev_id = cdev->private->dev_id;
+}
+EXPORT_SYMBOL(ccw_device_get_id);
+
 // FIXME: these have to go:
 
 int
index f770018fe1d5c02c691686b32115b59bf1d6472e..e70aeb7a378109ef1fa1f6a31d72ae6fe7009828 100644 (file)
@@ -1983,6 +1983,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
                if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
                        qdio_mark_q(q);
                else {
+                       qdio_perf_stat_dec(&perf_stats.tl_runs);
                        __qdio_inbound_processing(q);
                }
        }
index f98fa465df0a79b4ed45c68ea43a89e83cc4e072..eada69dec4fe7ea7c299e701f31b6c66ee6211c8 100644 (file)
@@ -3,7 +3,7 @@ menu "S/390 network device drivers"
 
 config LCS
        tristate "Lan Channel Station Interface"
-       depends on NETDEVICES && (NET_ETHERNET || TR || FDDI)
+       depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI)
        help
           Select this option if you want to use LCS networking  on IBM S/390
           or zSeries. This device driver supports Token Ring (IEEE 802.5),
@@ -13,7 +13,7 @@ config LCS
 
 config CTC
        tristate "CTC device support"
-       depends on NETDEVICES
+       depends on CCW && NETDEVICES
        help
          Select this option if you want to use channel-to-channel networking
          on IBM S/390 or zSeries. This device driver supports real CTC
@@ -42,7 +42,7 @@ config SMSGIUCV
 
 config CLAW
        tristate "CLAW device support"
-       depends on NETDEVICES
+       depends on CCW && NETDEVICES
        help
          This driver supports channel attached CLAW devices.
          CLAW is Common Link Access for Workstation.  Common devices
@@ -52,7 +52,7 @@ config CLAW
 
 config QETH
        tristate "Gigabit Ethernet device support"
-       depends on NETDEVICES && IP_MULTICAST && QDIO
+       depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
        help
          This driver supports the IBM S/390 and zSeries OSA Express adapters
          in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
index 29d176036e5c5fd0d2cbe5e9d59072e6942f92df..0b96d49dd636bc55f6f8f8f360472ab9c18fede1 100644 (file)
@@ -2860,7 +2860,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
                        if (!atomic_read(&queue->set_pci_flags_count)){
                                /*
                                 * there's no outstanding PCI any more, so we
-                                * have to request a PCI to be sure the the PCI
+                                * have to request a PCI to be sure that the PCI
                                 * will wake at some time in the future then we
                                 * can flush packed buffers that might still be
                                 * hanging around, which can happen if no
index f54fdfdbf06fcf300f8e812b67451fcdf09055f0..f29a4bc4f6f2ebe855d99c6f65a1ab8282f7c7b7 100644 (file)
@@ -162,7 +162,7 @@ struct ipa_rc_msg {
        char *msg;
 };
 
-struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
        {IPA_RC_SUCCESS,                "success"},
        {IPA_RC_NOTSUPP,                "Command not supported"},
        {IPA_RC_IP_TABLE_FULL,          "Add Addr IP Table Full - ipv6"},
@@ -226,7 +226,7 @@ struct ipa_cmd_names {
        char *name;
 };
 
-struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
        {IPA_CMD_STARTLAN,      "startlan"},
        {IPA_CMD_STOPLAN,       "stoplan"},
        {IPA_CMD_SETVMAC,       "setvmac"},
index 1f9554e0801392e043ff2ac1e120ed44c8da7644..ddff40c4212c28068dcb3b58e501ba1398d4e336 100644 (file)
@@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count)
 
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_FSF
 
-static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
 {
-       int i;
+       int idx;
 
        adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
                                    GFP_KERNEL);
-
        if (!adapter->req_list)
                return -ENOMEM;
 
-       for (i=0; i<REQUEST_LIST_SIZE; i++)
-               INIT_LIST_HEAD(&adapter->req_list[i]);
-
+       for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+               INIT_LIST_HEAD(&adapter->req_list[idx]);
        return 0;
 }
 
 static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
 {
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i;
-
-       for (i=0; i<REQUEST_LIST_SIZE; i++) {
-               if (list_empty(&adapter->req_list[i]))
-                       continue;
-
-               list_for_each_entry_safe(request, tmp,
-                                        &adapter->req_list[i], list)
-                       list_del(&request->list);
-       }
-
        kfree(adapter->req_list);
 }
 
-void zfcp_reqlist_add(struct zfcp_adapter *adapter,
-                     struct zfcp_fsf_req *fsf_req)
-{
-       unsigned int i;
-
-       i = fsf_req->req_id % REQUEST_LIST_SIZE;
-       list_add_tail(&fsf_req->list, &adapter->req_list[i]);
-}
-
-void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
-{
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i, counter;
-       u64 dbg_tmp[2];
-
-       i = req_id % REQUEST_LIST_SIZE;
-       BUG_ON(list_empty(&adapter->req_list[i]));
-
-       counter = 0;
-       list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
-               if (request->req_id == req_id) {
-                       dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
-                       dbg_tmp[1] = (u64) counter;
-                       debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
-                       list_del(&request->list);
-                       break;
-               }
-               counter++;
-       }
-}
-
-struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
-                                          unsigned long req_id)
-{
-       struct zfcp_fsf_req *request, *tmp;
-       unsigned int i;
-
-       /* 0 is reserved as an invalid req_id */
-       if (req_id == 0)
-               return NULL;
-
-       i = req_id % REQUEST_LIST_SIZE;
-
-       list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
-               if (request->req_id == req_id)
-                       return request;
-
-       return NULL;
-}
-
 int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
 {
-       unsigned int i;
+       unsigned int idx;
 
-       for (i=0; i<REQUEST_LIST_SIZE; i++)
-               if (!list_empty(&adapter->req_list[i]))
+       for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+               if (!list_empty(&adapter->req_list[idx]))
                        return 0;
-
        return 1;
 }
 
@@ -672,8 +607,7 @@ zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
  * @sg_count: elements in array
  * Return: size of entire scatter-gather list
  */
-size_t
-zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
+static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
 {
        unsigned int i;
        struct scatterlist *p;
@@ -913,6 +847,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
        unit->sysfs_device.release = zfcp_sysfs_unit_release;
        dev_set_drvdata(&unit->sysfs_device, unit);
 
+       init_waitqueue_head(&unit->scsi_scan_wq);
+
        /* mark unit unusable as long as sysfs registration is not complete */
        atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
 
@@ -1038,8 +974,7 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
                mempool_destroy(adapter->pool.data_gid_pn);
 }
 
-void
-zfcp_dummy_release(struct device *dev)
+static void zfcp_dummy_release(struct device *dev)
 {
        return;
 }
@@ -1104,7 +1039,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 
        /* initialize list of fsf requests */
        spin_lock_init(&adapter->req_list_lock);
-       retval = zfcp_reqlist_init(adapter);
+       retval = zfcp_reqlist_alloc(adapter);
        if (retval) {
                ZFCP_LOG_INFO("request list initialization failed\n");
                goto failed_low_mem_buffers;
@@ -1165,6 +1100,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
  sysfs_failed:
        dev_set_drvdata(&ccw_device->dev, NULL);
+       zfcp_reqlist_free(adapter);
  failed_low_mem_buffers:
        zfcp_free_low_mem_buffers(adapter);
        if (qdio_free(ccw_device) != 0)
@@ -1398,7 +1334,7 @@ zfcp_nameserver_enqueue(struct zfcp_adapter *adapter)
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_FC
 
-void
+static void
 zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
                           struct fsf_status_read_buffer *status_buffer)
 {
@@ -1497,7 +1433,7 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
 
        if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) {
                ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port "
-                              "with d_id 0x%08x on adapter %s\n",
+                              "with d_id 0x%06x on adapter %s\n",
                               status_buffer->d_id,
                               zfcp_get_busid_by_adapter(adapter));
        } else {
@@ -1522,7 +1458,7 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
 
        if (!port || (port->wwpn != els_logo->nport_wwpn)) {
                ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port "
-                              "with d_id 0x%08x on adapter %s\n",
+                              "with d_id 0x%06x on adapter %s\n",
                               status_buffer->d_id,
                               zfcp_get_busid_by_adapter(adapter));
        } else {
@@ -1704,7 +1640,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
        /* looks like a valid d_id */
         port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
        atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
-       ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%08x\n",
+       ZFCP_LOG_DEBUG("adapter %s:  wwpn=0x%016Lx ---> d_id=0x%06x\n",
                       zfcp_get_busid_by_port(port), port->wwpn, port->d_id);
        goto out;
 
index d8191d115c14a3c8a8db329f5613e53bc2805224..5f3212440f68594b304e9c0b48074b1c3c0618bd 100644 (file)
@@ -478,7 +478,7 @@ static struct debug_view zfcp_hba_dbf_view = {
        NULL
 };
 
-void
+static void
 _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
                              u32 s_id, u32 d_id, void *buffer, int buflen)
 {
index 32933ed54b8a05dbe3534ac90395bbbf3d1ee283..22649639230b25fc8a326ab0eb3938070a9fdb26 100644 (file)
@@ -637,6 +637,7 @@ do { \
 #define ZFCP_STATUS_UNIT_SHARED                        0x00000004
 #define ZFCP_STATUS_UNIT_READONLY              0x00000008
 #define ZFCP_STATUS_UNIT_REGISTERED            0x00000010
+#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING     0x00000020
 
 /* FSF request status (this does not have a common part) */
 #define ZFCP_STATUS_FSFREQ_NOT_INIT            0x00000000
@@ -980,6 +981,10 @@ struct zfcp_unit {
         struct scsi_device     *device;        /* scsi device struct pointer */
        struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
+       wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
+                                                 all scsi_scan_target
+                                                 requests have been
+                                                 completed. */
 };
 
 /* FSF request */
@@ -1084,6 +1089,42 @@ extern void _zfcp_hex_dump(char *, int);
 #define zfcp_get_busid_by_port(port) (zfcp_get_busid_by_adapter(port->adapter))
 #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
 
+/*
+ * Helper functions for request ID management.
+ */
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+       return req_id % REQUEST_LIST_SIZE;
+}
+
+static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+                                   struct zfcp_fsf_req *fsf_req)
+{
+       unsigned int idx;
+
+       idx = zfcp_reqlist_hash(fsf_req->req_id);
+       list_add_tail(&fsf_req->list, &adapter->req_list[idx]);
+}
+
+static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
+                                      struct zfcp_fsf_req *fsf_req)
+{
+       list_del(&fsf_req->list);
+}
+
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+       struct zfcp_fsf_req *request;
+       unsigned int idx;
+
+       idx = zfcp_reqlist_hash(req_id);
+       list_for_each_entry(request, &adapter->req_list[idx], list)
+               if (request->req_id == req_id)
+                       return request;
+       return NULL;
+}
+
 /*
  *  functions needed for reference/usage counting
  */
index c1f2d4b14c2b4517071d5e8fc6a8d5358a9b7347..aef66bc2b6cac79dff1219b44a287f666a8a4087 100644 (file)
@@ -179,7 +179,7 @@ static void zfcp_close_fsf(struct zfcp_adapter *adapter)
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
        struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-       zfcp_erp_adapter_reopen(adapter, 0);
+       zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
 }
 
 void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
@@ -342,9 +342,9 @@ zfcp_erp_adisc(struct zfcp_port *port)
        adisc->wwpn = fc_host_port_name(adapter->scsi_host);
        adisc->wwnn = fc_host_node_name(adapter->scsi_host);
        adisc->nport_id = fc_host_port_id(adapter->scsi_host);
-       ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
+       ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x "
                      "(wwpn=0x%016Lx, wwnn=0x%016Lx, "
-                     "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+                     "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
                      adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
                      (wwn_t) adisc->wwnn, adisc->hard_nport_id,
                      adisc->nport_id);
@@ -352,7 +352,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
        retval = zfcp_fsf_send_els(send_els);
        if (retval != 0) {
                ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
-                               "0x%08x on adapter %s\n", send_els->d_id,
+                               "0x%06x on adapter %s\n", send_els->d_id,
                                zfcp_get_busid_by_adapter(adapter));
                goto freemem;
        }
@@ -398,7 +398,7 @@ zfcp_erp_adisc_handler(unsigned long data)
        if (send_els->status != 0) {
                ZFCP_LOG_NORMAL("ELS request rejected/timed out, "
                                "force physical port reopen "
-                               "(adapter %s, port d_id=0x%08x)\n",
+                               "(adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_adapter(adapter), d_id);
                debug_text_event(adapter->erp_dbf, 3, "forcreop");
                if (zfcp_erp_port_forced_reopen(port, 0))
@@ -411,9 +411,9 @@ zfcp_erp_adisc_handler(unsigned long data)
 
        adisc = zfcp_sg_to_address(send_els->resp);
 
-       ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
-                     "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
-                     "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+       ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id "
+                     "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+                     "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
                      d_id, fc_host_port_id(adapter->scsi_host),
                      (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
                      adisc->hard_nport_id, adisc->nport_id);
@@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
        if (erp_action->fsf_req) {
                /* take lock to ensure that request is not deleted meanwhile */
                spin_lock(&adapter->req_list_lock);
-               if (zfcp_reqlist_ismember(adapter,
-                                           erp_action->fsf_req->req_id)) {
+               if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
                        /* fsf_req still exists */
                        debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
                        debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1377,7 +1376,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
 
        if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
                ZFCP_LOG_NORMAL("port erp failed (adapter %s, "
-                               "port d_id=0x%08x)\n",
+                               "port d_id=0x%06x)\n",
                                zfcp_get_busid_by_port(port), port->d_id);
        else
                ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n",
@@ -1591,6 +1590,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
        return result;
 }
 
+struct zfcp_erp_add_work {
+       struct zfcp_unit  *unit;
+       struct work_struct work;
+};
+
+/**
+ * zfcp_erp_scsi_scan
+ * @data: pointer to a struct zfcp_erp_add_work
+ *
+ * Registers a logical unit with the SCSI stack.
+ */
+static void zfcp_erp_scsi_scan(struct work_struct *work)
+{
+       struct zfcp_erp_add_work *p =
+               container_of(work, struct zfcp_erp_add_work, work);
+       struct zfcp_unit *unit = p->unit;
+       struct fc_rport *rport = unit->port->rport;
+       scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
+                        unit->scsi_lun, 0);
+       atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+       wake_up(&unit->scsi_scan_wq);
+       zfcp_unit_put(unit);
+       kfree(p);
+}
+
+/**
+ * zfcp_erp_schedule_work
+ * @unit: pointer to unit which should be registered with SCSI stack
+ *
+ * Schedules work which registers a unit with the SCSI stack
+ */
+static void
+zfcp_erp_schedule_work(struct zfcp_unit *unit)
+{
+       struct zfcp_erp_add_work *p;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
+                               "the FCP-LUN 0x%Lx connected to "
+                               "the port with WWPN 0x%Lx connected to "
+                               "the adapter %s with the SCSI stack.\n",
+                               unit->fcp_lun,
+                               unit->port->wwpn,
+                               zfcp_get_busid_by_unit(unit));
+               return;
+       }
+
+       zfcp_unit_get(unit);
+       memset(p, 0, sizeof(*p));
+       atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+       INIT_WORK(&p->work, zfcp_erp_scsi_scan);
+       p->unit = unit;
+       schedule_work(&p->work);
+}
+
 /*
  * function:   
  *
@@ -2401,7 +2456,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
                                retval = ZFCP_ERP_FAILED;
                        }
                } else {
-                       ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> "
+                       ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> "
                                       "trying open\n", port->wwpn, port->d_id);
                        retval = zfcp_erp_port_strategy_open_port(erp_action);
                }
@@ -2441,7 +2496,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
        case ZFCP_ERP_STEP_UNINITIALIZED:
        case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
        case ZFCP_ERP_STEP_PORT_CLOSING:
-               ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n",
+               ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n",
                               port->wwpn, port->d_id);
                retval = zfcp_erp_port_strategy_open_port(erp_action);
                break;
@@ -3092,9 +3147,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                    && port->rport) {
                        atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
                                        &unit->status);
-                       scsi_scan_target(&port->rport->dev, 0,
-                                        port->rport->scsi_target_id,
-                                        unit->scsi_lun, 0);
+                       if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+                                            &unit->status) == 0)
+                               zfcp_erp_schedule_work(unit);
                }
                zfcp_unit_put(unit);
                break;
@@ -3121,7 +3176,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                                                zfcp_get_busid_by_port(port),
                                                port->wwpn);
                        else {
-                               scsi_flush_work(adapter->scsi_host);
+                               scsi_target_unblock(&port->rport->dev);
                                port->rport->maxframe_size = port->maxframe_size;
                                port->rport->supported_classes =
                                        port->supported_classes;
index 01386ac688a27887e32cd75dfa336a2c4611f5d9..991d45667a44d0453f06d0134d1345a8a5509d2a 100644 (file)
@@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
                                      unsigned long);
 extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
                                         struct scsi_cmnd *);
-extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
-extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
-extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
-                                                 unsigned long);
 extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
 
 #endif /* ZFCP_EXT_H */
index 4c0a59afd5c85bda51083b6cab01588c11268363..a8b02542ac2da30aaaf9a953153d41e419c18da0 100644 (file)
@@ -828,7 +828,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
 
        if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
                ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
-                               "nonexisting port with d_id 0x%08x on "
+                               "nonexisting port with d_id 0x%06x on "
                                "adapter %s. Ignored.\n",
                                status_buffer->d_id & ZFCP_DID_MASK,
                                zfcp_get_busid_by_adapter(adapter));
@@ -853,7 +853,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
                                &status_buffer->status_subtype, sizeof (u32));
                ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
                                "for a reopen indication on port with "
-                               "d_id 0x%08x on the adapter %s. "
+                               "d_id 0x%06x on the adapter %s. "
                                "Ignored. (debug info 0x%x)\n",
                                status_buffer->d_id,
                                zfcp_get_busid_by_adapter(adapter),
@@ -1156,7 +1156,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
        }
 
        ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
-                      "(adapter%s, port d_id=0x%08x, "
+                      "(adapter%s, port d_id=0x%06x, "
                       "unit x%016Lx, old_req_id=0x%lx)\n",
                       zfcp_get_busid_by_adapter(adapter),
                       unit->port->d_id,
@@ -1554,7 +1554,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_ACCESS_DENIED:
                ZFCP_LOG_NORMAL("access denied, cannot send generic service "
-                               "command (adapter %s, port d_id=0x%08x)\n",
+                               "command (adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_port(port), port->d_id);
                for (counter = 0; counter < 2; counter++) {
                        subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -1576,7 +1576,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
         case FSF_GENERIC_COMMAND_REJECTED:
                ZFCP_LOG_INFO("generic service command rejected "
-                             "(adapter %s, port d_id=0x%08x)\n",
+                             "(adapter %s, port d_id=0x%06x)\n",
                              zfcp_get_busid_by_port(port), port->d_id);
                ZFCP_LOG_INFO("status qualifier:\n");
                ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
@@ -1602,7 +1602,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
 
         case FSF_PORT_BOXED:
                ZFCP_LOG_INFO("port needs to be reopened "
-                             "(adapter %s, port d_id=0x%08x)\n",
+                             "(adapter %s, port d_id=0x%06x)\n",
                              zfcp_get_busid_by_port(port), port->d_id);
                debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
                zfcp_erp_port_boxed(port);
@@ -1683,7 +1683,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                  NULL, &lock_flags, &fsf_req);
        if (ret < 0) {
                 ZFCP_LOG_INFO("error: creation of ELS request failed "
-                             "(adapter %s, port d_id: 0x%08x)\n",
+                             "(adapter %s, port d_id: 0x%06x)\n",
                               zfcp_get_busid_by_adapter(adapter), d_id);
                 goto failed_req;
        }
@@ -1708,7 +1708,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-                                     "(adapter %s, port d_id: 0x%08x)\n",
+                                     "(adapter %s, port d_id: 0x%06x)\n",
                                      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1725,7 +1725,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                                                 ZFCP_MAX_SBALS_PER_ELS_REQ);
                 if (bytes <= 0) {
                         ZFCP_LOG_INFO("error: creation of ELS request failed "
-                                     "(adapter %s, port d_id: 0x%08x)\n",
+                                     "(adapter %s, port d_id: 0x%06x)\n",
                                      zfcp_get_busid_by_adapter(adapter), d_id);
                         if (bytes == 0) {
                                 ret = -ENOMEM;
@@ -1739,7 +1739,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                 /* reject request */
                ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
                               ", ELS request too big (adapter %s, "
-                             "port d_id: 0x%08x)\n",
+                             "port d_id: 0x%06x)\n",
                              zfcp_get_busid_by_adapter(adapter), d_id);
                 ret = -EOPNOTSUPP;
                 goto failed_send;
@@ -1760,13 +1760,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
        ret = zfcp_fsf_req_send(fsf_req);
        if (ret) {
                ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
-                              "(adapter %s, port d_id: 0x%08x)\n",
+                              "(adapter %s, port d_id: 0x%06x)\n",
                               zfcp_get_busid_by_adapter(adapter), d_id);
                goto failed_send;
        }
 
        ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
-                      "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
+                      "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
        goto out;
 
  failed_send:
@@ -1859,7 +1859,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
        case FSF_ELS_COMMAND_REJECTED:
                ZFCP_LOG_INFO("ELS has been rejected because command filter "
                              "prohibited sending "
-                             "(adapter: %s, port d_id: 0x%08x)\n",
+                             "(adapter: %s, port d_id: 0x%06x)\n",
                              zfcp_get_busid_by_adapter(adapter), d_id);
 
                break;
@@ -1907,7 +1907,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_ACCESS_DENIED:
                ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
-                               "(adapter %s, port d_id=0x%08x)\n",
+                               "(adapter %s, port d_id=0x%06x)\n",
                                zfcp_get_busid_by_adapter(adapter), d_id);
                for (counter = 0; counter < 2; counter++) {
                        subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -2070,7 +2070,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
        ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
                        "WWNN 0x%016Lx, "
                        "WWPN 0x%016Lx, "
-                       "S_ID 0x%08x,\n"
+                       "S_ID 0x%06x,\n"
                        "adapter version 0x%x, "
                        "LIC version 0x%x, "
                        "FC link speed %d Gb/s\n",
@@ -3043,6 +3043,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
        queue_designator = &header->fsf_status_qual.fsf_queue_designator;
 
        atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
+                         ZFCP_STATUS_COMMON_ACCESS_BOXED |
                          ZFCP_STATUS_UNIT_SHARED |
                          ZFCP_STATUS_UNIT_READONLY,
                          &unit->status);
@@ -4645,23 +4646,22 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
        fsf_req->adapter = adapter;
        fsf_req->fsf_command = fsf_cmd;
        INIT_LIST_HEAD(&fsf_req->list);
-       
-       /* this is serialized (we are holding req_queue-lock of adapter */
-       if (adapter->req_no == 0)
-               adapter->req_no++;
-       fsf_req->req_id = adapter->req_no++;
-
        init_timer(&fsf_req->timer);
-       zfcp_fsf_req_qtcb_init(fsf_req);
 
        /* initialize waitqueue which may be used to wait on 
           this request completion */
        init_waitqueue_head(&fsf_req->completion_wq);
 
         ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
-        if(ret < 0) {
+        if (ret < 0)
                 goto failed_sbals;
-       }
+
+       /* this is serialized (we are holding req_queue-lock of adapter) */
+       if (adapter->req_no == 0)
+               adapter->req_no++;
+       fsf_req->req_id = adapter->req_no++;
+
+       zfcp_fsf_req_qtcb_init(fsf_req);
 
        /*
         * We hold queue_lock here. Check if QDIOUP is set and let request fail
@@ -4788,7 +4788,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
                retval = -EIO;
                del_timer(&fsf_req->timer);
                spin_lock(&adapter->req_list_lock);
-               zfcp_reqlist_remove(adapter, fsf_req->req_id);
+               zfcp_reqlist_remove(adapter, fsf_req);
                spin_unlock(&adapter->req_list_lock);
                /* undo changes in request queue made for this request */
                zfcp_qdio_zero_sbals(req_queue->buffer,
index 1e12a78e8edd1c17886a66f5e7bf2b530adf6018..bdf5782b8a7acd175dac262d45514d7035a21bbb 100644 (file)
@@ -222,7 +222,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
                 * Since we have been using this adapter, it is save to assume
                 * that it is not failed but recoverable. The card seems to
                 * report link-up events by self-initiated queue shutdown.
-                * That is why we need to clear the the link-down flag
+                * That is why we need to clear the link-down flag
                 * which is set again in case we have missed by a mile.
                 */
                zfcp_erp_adapter_reopen(
@@ -283,10 +283,10 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
 }
 
 /**
- * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ * zfcp_qdio_reqid_check - checks for valid reqids.
  */
-static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, 
-                                unsigned long req_id)
+static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+                                 unsigned long req_id)
 {
        struct zfcp_fsf_req *fsf_req;
        unsigned long flags;
@@ -294,23 +294,22 @@ static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
        debug_long_event(adapter->erp_dbf, 4, req_id);
 
        spin_lock_irqsave(&adapter->req_list_lock, flags);
-       fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+       fsf_req = zfcp_reqlist_find(adapter, req_id);
 
-       if (!fsf_req) {
-               spin_unlock_irqrestore(&adapter->req_list_lock, flags);
-               ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id);
-               zfcp_erp_adapter_reopen(adapter, 0);
-               return -EINVAL;
-       }
+       if (!fsf_req)
+               /*
+                * Unknown request means that we have potentially memory
+                * corruption and must stop the machine immediatly.
+                */
+               panic("error: unknown request id (%ld) on adapter %s.\n",
+                     req_id, zfcp_get_busid_by_adapter(adapter));
 
-       zfcp_reqlist_remove(adapter, req_id);
+       zfcp_reqlist_remove(adapter, fsf_req);
        atomic_dec(&adapter->reqs_active);
        spin_unlock_irqrestore(&adapter->req_list_lock, flags);
 
        /* finish the FSF request */
        zfcp_fsf_req_complete(fsf_req);
-
-       return 0;
 }
 
 /*
@@ -374,27 +373,9 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
 
                        /* look for QDIO request identifiers in SB */
                        buffere = &buffer->element[buffere_index];
-                       retval = zfcp_qdio_reqid_check(adapter,
-                                       (unsigned long) buffere->addr);
-
-                       if (retval) {
-                               ZFCP_LOG_NORMAL("bug: unexpected inbound "
-                                               "packet on adapter %s "
-                                               "(reqid=0x%lx, "
-                                               "first_element=%d, "
-                                               "elements_processed=%d)\n",
-                                               zfcp_get_busid_by_adapter(adapter),
-                                               (unsigned long) buffere->addr,
-                                               first_element,
-                                               elements_processed);
-                               ZFCP_LOG_NORMAL("hex dump of inbound buffer "
-                                               "at address %p "
-                                               "(buffer_index=%d, "
-                                               "buffere_index=%d)\n", buffer,
-                                               buffer_index, buffere_index);
-                               ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
-                                             (char *) buffer, SBAL_SIZE);
-                       }
+                       zfcp_qdio_reqid_check(adapter,
+                                             (unsigned long) buffere->addr);
+
                        /*
                         * A single used SBALE per inbound SBALE has been
                         * implemented by QDIO so far. Hope they will
index 99db02062c3b4af325e8cbfa3b9208d333a867d5..16e2d64658afea075143230bdcc08d9a492a58a8 100644 (file)
@@ -22,6 +22,7 @@
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_SCSI
 
 #include "zfcp_ext.h"
+#include <asm/atomic.h>
 
 static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
 static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
@@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
        struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
 
        if (unit) {
+               zfcp_erp_wait(unit->port->adapter);
+               wait_event(unit->scsi_scan_wq,
+                          atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+                                           &unit->status) == 0);
                atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
                sdpnt->hostdata = NULL;
                unit->device = NULL;
@@ -402,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 
        /* Check whether corresponding fsf_req is still pending */
        spin_lock(&adapter->req_list_lock);
-       fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
-                                       scpnt->host_scribble);
+       fsf_req = zfcp_reqlist_find(adapter,
+                                   (unsigned long) scpnt->host_scribble);
        spin_unlock(&adapter->req_list_lock);
        if (!fsf_req) {
                write_unlock_irqrestore(&adapter->abort_lock, flags);
index 74b999d77bbff251022afed3fbe4bd315df46fe2..4fab0c23814c90dda8bf55b85e6242c6dbc07d96 100644 (file)
@@ -156,7 +156,7 @@ static unsigned short get_pins(unsigned minor)
 #define BPP_ICR      0x18
 #define BPP_SIZE     0x1A
 
-/* BPP_CSR.  Bits of type RW1 are cleared with writting '1'. */
+/* BPP_CSR.  Bits of type RW1 are cleared with writing '1'. */
 #define P_DEV_ID_MASK   0xf0000000      /* R   */
 #define P_DEV_ID_ZEBRA  0x40000000
 #define P_DEV_ID_L64854 0xa0000000      /*      == NCR 89C100+89C105. Pity. */
index 33682ce96a5d683cdc9d6e2687b2e95eaee43f20..3009ad8c407343d209e9b4d0a79639f0dbbfd4fe 100644 (file)
@@ -387,12 +387,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
         *      Ok now init the communication subsystem
         */
 
-       dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+       dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
        if (dev->queues == NULL) {
                printk(KERN_ERR "Error could not allocate comm region.\n");
                return NULL;
        }
-       memset(dev->queues, 0, sizeof(struct aac_queue_block));
 
        if (aac_comm_init(dev)<0){
                kfree(dev->queues);
index 5824a757a7531aa9d71801486754cee84027a3f1..9aca57eda943664011d06863c309fd4178a58622 100644 (file)
@@ -1223,13 +1223,11 @@ int aac_check_health(struct aac_dev * aac)
                 * Warning: no sleep allowed while
                 * holding spinlock
                 */
-               hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-               fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+               hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+               fib = kzalloc(sizeof(struct fib), GFP_ATOMIC);
                if (fib && hw_fib) {
                        struct aac_aifcmd * aif;
 
-                       memset(hw_fib, 0, sizeof(struct hw_fib));
-                       memset(fib, 0, sizeof(struct fib));
                        fib->hw_fib_va = hw_fib;
                        fib->dev = aac;
                        aac_fib_init(fib);
index 42c7dcda6d9bd1c9679cddcc8dd01bb0be00ae4c..fcd25f7d0bc636252074d535338d3c9f9e2e81f0 100644 (file)
@@ -248,16 +248,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
                 * manage the linked lists.
                 */
                if ((!dev->aif_thread)
-                || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+                || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
                        return 1;
-               if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+               if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
                        kfree (fib);
                        return 1;
                }
-               memset(hw_fib, 0, sizeof(struct hw_fib));
                memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
                  (index & ~0x00000002L)), sizeof(struct hw_fib));
-               memset(fib, 0, sizeof(struct fib));
                INIT_LIST_HEAD(&fib->fiblink);
                fib->type = FSAFS_NTC_FIB_CONTEXT;
                fib->size = sizeof(struct fib);
index 0c71315cbf1aec8ed3df4f72bf8bb87d6a7f2cbc..291cd14f4e989737b0f54c289250a6cb006a67e0 100644 (file)
@@ -539,8 +539,10 @@ int _aac_rx_init(struct aac_dev *dev)
        }
 
        /* Failure to reset here is an option ... */
+       dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+       dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
        dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
-       if ((((status & 0xff) != 0xff) || reset_devices) &&
+       if ((((status & 0x0c) != 0x0c) || reset_devices) &&
          !aac_rx_restart_adapter(dev, 0))
                ++restart;
        /*
index 8d72bbae96ad1a59a3777b662d8e47b640abc0c1..0bada0028aa0ba0c2081f79c4bdc99477754f6bc 100644 (file)
@@ -966,7 +966,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
                              |  AHD_BUSFREEREV_BUG;
                ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
 
-               /* If the user requested the the SLOWCRC bit to be set. */
+               /* If the user requested that the SLOWCRC bit to be set. */
                if (aic79xx_slowcrc)
                        ahd->features |= AHD_AIC79XXB_SLOWCRC;
 
index e6b70123940ce4dd7826feb4bd74bc25aa96a9bf..e78ce0fa44d2dd8c9d0eb8fe87ffd3141b9c2915 100644 (file)
@@ -6,7 +6,7 @@
 #
 # This file is licensed under GPLv2.
 #
-# This file is part of the the aic94xx driver.
+# This file is part of the aic94xx driver.
 #
 # The aic94xx driver is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License as
index 2a2cc6cf1182a9cdaa2ebf0df1c2b9e15b4b37e3..2311019304c00ef22ec4a8b63167a7c65c7dc488 100644 (file)
@@ -319,10 +319,9 @@ ch_readconfig(scsi_changer *ch)
        int     result,id,lun,i;
        u_int   elem;
 
-       buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+       buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
        if (!buffer)
                return -ENOMEM;
-       memset(buffer,0,512);
        
        memset(cmd,0,sizeof(cmd));
        cmd[0] = MODE_SENSE;
@@ -530,10 +529,9 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
        u_char  *buffer;
        int result;
 
-       buffer = kmalloc(512, GFP_KERNEL);
+       buffer = kzalloc(512, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
-       memset(buffer,0,512);
 
        dprintk("%s %s voltag: 0x%x => \"%s\"\n",
                clear     ? "clear"     : "set",
@@ -922,11 +920,10 @@ static int ch_probe(struct device *dev)
        if (sd->type != TYPE_MEDIUM_CHANGER)
                return -ENODEV;
     
-       ch = kmalloc(sizeof(*ch), GFP_KERNEL);
+       ch = kzalloc(sizeof(*ch), GFP_KERNEL);
        if (NULL == ch)
                return -ENOMEM;
 
-       memset(ch,0,sizeof(*ch));
        ch->minor = ch_devcount;
        sprintf(ch->name,"ch%d",ch->minor);
        mutex_init(&ch->lock);
index a965ed3548d5583fd2ac56d343b0e8d5a0f64d08..564ea90ed3a00a18cccb80b63799a236297dc579 100644 (file)
@@ -541,7 +541,7 @@ static struct ParameterData __devinitdata cfg_data[] = {
 
 
 /*
- * Safe settings. If set to zero the the BIOS/default values with
+ * Safe settings. If set to zero the BIOS/default values with
  * command line overrides will be used. If set to 1 then safe and
  * slow settings will be used.
  */
@@ -617,7 +617,7 @@ static void __devinit fix_settings(void)
 
 /*
  * Mapping from the eeprom delay index value (index into this array)
- * to the the number of actual seconds that the delay should be for.
+ * to the number of actual seconds that the delay should be for.
  */
 static char __devinitdata eeprom_index_to_delay_map[] = 
        { 1, 3, 5, 10, 16, 30, 60, 120 };
@@ -4136,7 +4136,7 @@ static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long
  * @io_port:   base I/O address
  * @addr:      offset into SEEPROM
  *
- * Returns the the byte read.
+ * Returns the byte read.
  **/
 static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
 {
index fb6433a56989f5b98d5fccfc9978d9ba51d23ec3..8c7d2bbf9b1a848b90b19a2edd1663e0164c0a2b 100644 (file)
@@ -1308,13 +1308,12 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
                schedule_timeout_uninterruptible(1);
        } while (m == EMPTY_QUEUE);
 
-       status = kmalloc(4, GFP_KERNEL|ADDR32);
+       status = kzalloc(4, GFP_KERNEL|ADDR32);
        if(status == NULL) {
                adpt_send_nop(pHba, m);
                printk(KERN_ERR"IOP reset failed - no free memory.\n");
                return -ENOMEM;
        }
-       memset(status,0,4);
 
        msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
        msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1504,21 +1503,19 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba)
                                        continue;
                                }
                                if( pHba->channel[bus_no].device[scsi_id] == NULL){
-                                       pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
                                        pHba->channel[bus_no].device[scsi_id] = pDev;
-                                       memset(pDev,0,sizeof(struct adpt_device));
                                } else {
                                        for( pDev = pHba->channel[bus_no].device[scsi_id];      
                                                        pDev->next_lun; pDev = pDev->next_lun){
                                        }
-                                       pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev->next_lun == NULL) {
                                                return -ENOMEM;
                                        }
-                                       memset(pDev->next_lun,0,sizeof(struct adpt_device));
                                        pDev = pDev->next_lun;
                                }
                                pDev->tid = tid;
@@ -1667,12 +1664,11 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
                reply_size = REPLY_FRAME_SIZE;
        }
        reply_size *= 4;
-       reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
+       reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
        if(reply == NULL) {
                printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name);
                return -ENOMEM;
        }
-       memset(reply,0,REPLY_FRAME_SIZE*4);
        sg_offset = (msg[0]>>4)&0xf;
        msg[2] = 0x40000000; // IOCTL context
        msg[3] = (u32)reply;
@@ -2444,7 +2440,7 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
                                }
                                pDev = pHba->channel[bus_no].device[scsi_id];   
                                if( pDev == NULL){
-                                       pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev =  kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
@@ -2453,12 +2449,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
                                        while (pDev->next_lun) {
                                                pDev = pDev->next_lun;
                                        }
-                                       pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+                                       pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
                                        if(pDev == NULL) {
                                                return -ENOMEM;
                                        }
                                }
-                               memset(pDev,0,sizeof(struct adpt_device));
                                pDev->tid = d->lct_data.tid;
                                pDev->scsi_channel = bus_no;
                                pDev->scsi_id = scsi_id;
index 2b5b8a93bc10756ed801eb7ea06f31265cb0ecbb..8263f752809d2ff64b00bb97f685ae7bbc9657d8 100644 (file)
@@ -721,19 +721,23 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r
        return ide_stopped;
 }
 
+#ifdef CONFIG_IDE_PROC_FS
 static void idescsi_add_settings(ide_drive_t *drive)
 {
        idescsi_scsi_t *scsi = drive_to_idescsi(drive);
 
 /*
- *                     drive   setting name    read/write      ioctl   ioctl           data type       min     max     mul_factor      div_factor      data pointer            set function
+ *                     drive   setting name    read/write      data type       min     max     mul_factor      div_factor      data pointer            set function
  */
-       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     -1,     -1,             TYPE_INT,       0,      1023,   1,              1,              &drive->bios_cyl,       NULL);
-       ide_add_setting(drive,  "bios_head",    SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,      255,    1,              1,              &drive->bios_head,      NULL);
-       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     -1,     -1,             TYPE_BYTE,      0,      63,     1,              1,              &drive->bios_sect,      NULL);
-       ide_add_setting(drive,  "transform",    SETTING_RW,     -1,     -1,             TYPE_INT,       0,      3,      1,              1,              &scsi->transform,       NULL);
-       ide_add_setting(drive,  "log",          SETTING_RW,     -1,     -1,             TYPE_INT,       0,      1,      1,              1,              &scsi->log,             NULL);
+       ide_add_setting(drive,  "bios_cyl",     SETTING_RW,     TYPE_INT,       0,      1023,   1,              1,              &drive->bios_cyl,       NULL);
+       ide_add_setting(drive,  "bios_head",    SETTING_RW,     TYPE_BYTE,      0,      255,    1,              1,              &drive->bios_head,      NULL);
+       ide_add_setting(drive,  "bios_sect",    SETTING_RW,     TYPE_BYTE,      0,      63,     1,              1,              &drive->bios_sect,      NULL);
+       ide_add_setting(drive,  "transform",    SETTING_RW,     TYPE_INT,       0,      3,      1,              1,              &scsi->transform,       NULL);
+       ide_add_setting(drive,  "log",          SETTING_RW,     TYPE_INT,       0,      1,      1,              1,              &scsi->log,             NULL);
 }
+#else
+static inline void idescsi_add_settings(ide_drive_t *drive) { ; }
+#endif
 
 /*
  *     Driver initialization.
@@ -756,7 +760,7 @@ static void ide_scsi_remove(ide_drive_t *drive)
        struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
        struct gendisk *g = scsi->disk;
 
-       ide_unregister_subdriver(drive, scsi->driver);
+       ide_proc_unregister_driver(drive, scsi->driver);
 
        ide_unregister_region(g);
 
@@ -770,13 +774,11 @@ static void ide_scsi_remove(ide_drive_t *drive)
 
 static int ide_scsi_probe(ide_drive_t *);
 
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_IDE_PROC_FS
 static ide_proc_entry_t idescsi_proc[] = {
        { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
        { NULL, 0, NULL, NULL }
 };
-#else
-# define idescsi_proc  NULL
 #endif
 
 static ide_driver_t idescsi_driver = {
@@ -790,11 +792,13 @@ static ide_driver_t idescsi_driver = {
        .version                = IDESCSI_VERSION,
        .media                  = ide_scsi,
        .supports_dsc_overlap   = 0,
-       .proc                   = idescsi_proc,
        .do_request             = idescsi_do_request,
        .end_request            = idescsi_end_request,
        .error                  = idescsi_atapi_error,
        .abort                  = idescsi_atapi_abort,
+#ifdef CONFIG_IDE_PROC_FS
+       .proc                   = idescsi_proc,
+#endif
 };
 
 static int idescsi_ide_open(struct inode *inode, struct file *filp)
@@ -1153,7 +1157,7 @@ static int ide_scsi_probe(ide_drive_t *drive)
        idescsi->host = host;
        idescsi->disk = g;
        g->private_data = &idescsi->driver;
-       ide_register_subdriver(drive, &idescsi_driver);
+       ide_proc_register_driver(drive, &idescsi_driver);
        err = 0;
        idescsi_setup(drive, idescsi);
        g->fops = &idescsi_ops;
@@ -1165,7 +1169,7 @@ static int ide_scsi_probe(ide_drive_t *drive)
        }
        /* fall through on error */
        ide_unregister_region(g);
-       ide_unregister_subdriver(drive, &idescsi_driver);
+       ide_proc_unregister_driver(drive, &idescsi_driver);
 
        put_disk(g);
 out_host_put:
index 2c7b77e833f993ff6d14d65820452d87dbaa8351..4baa79e686794ba5915717c2998860b6031fd91b 100644 (file)
@@ -92,6 +92,7 @@ static unsigned int ipr_fastfail = 0;
 static unsigned int ipr_transop_timeout = 0;
 static unsigned int ipr_enable_cache = 1;
 static unsigned int ipr_debug = 0;
+static unsigned int ipr_dual_ioa_raid = 1;
 static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
@@ -158,6 +159,8 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0);
 MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
 module_param_named(debug, ipr_debug, int, 0);
 MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
+module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
+MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(IPR_DRIVER_VERSION);
 
@@ -206,6 +209,8 @@ struct ipr_error_table_t ipr_error_table[] = {
        "8009: Impending cache battery pack failure"},
        {0x02040400, 0, 0,
        "34FF: Disk device format in progress"},
+       {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL,
+       "9070: IOA requested reset"},
        {0x023F0000, 0, 0,
        "Synchronization required"},
        {0x024E0000, 0, 0,
@@ -950,6 +955,53 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
        }
 }
 
+/**
+ * strip_and_pad_whitespace - Strip and pad trailing whitespace.
+ * @i:         index into buffer
+ * @buf:               string to modify
+ *
+ * This function will strip all trailing whitespace, pad the end
+ * of the string with a single space, and NULL terminate the string.
+ *
+ * Return value:
+ *     new length of string
+ **/
+static int strip_and_pad_whitespace(int i, char *buf)
+{
+       while (i && buf[i] == ' ')
+               i--;
+       buf[i+1] = ' ';
+       buf[i+2] = '\0';
+       return i + 2;
+}
+
+/**
+ * ipr_log_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:            string to print at start of printk
+ * @hostrcb:   hostrcb pointer
+ * @vpd:               vendor/product id/sn struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+                               struct ipr_vpd *vpd)
+{
+       char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3];
+       int i = 0;
+
+       memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
+       i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer);
+
+       memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN);
+       i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer);
+
+       memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN);
+       buffer[IPR_SERIAL_NUM_LEN + i] = '\0';
+
+       ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer);
+}
+
 /**
  * ipr_log_vpd - Log the passed VPD to the error log.
  * @vpd:               vendor/product id/sn struct
@@ -973,6 +1025,23 @@ static void ipr_log_vpd(struct ipr_vpd *vpd)
        ipr_err("    Serial Number: %s\n", buffer);
 }
 
+/**
+ * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix:            string to print at start of printk
+ * @hostrcb:   hostrcb pointer
+ * @vpd:               vendor/product id/sn/wwn struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+                                   struct ipr_ext_vpd *vpd)
+{
+       ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd);
+       ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix,
+                    be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1]));
+}
+
 /**
  * ipr_log_ext_vpd - Log the passed extended VPD to the error log.
  * @vpd:               vendor/product id/sn/wwn struct
@@ -1287,10 +1356,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 
        error = &hostrcb->hcam.u.error.u.type_17_error;
        error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       strstrip(error->failure_reason);
 
-       ipr_err("%s\n", error->failure_reason);
-       ipr_err("Remote Adapter VPD:\n");
-       ipr_log_ext_vpd(&error->vpd);
+       ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+                    be32_to_cpu(hostrcb->hcam.u.error.prc));
+       ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd);
        ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
@@ -1312,10 +1382,11 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 
        error = &hostrcb->hcam.u.error.u.type_07_error;
        error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       strstrip(error->failure_reason);
 
-       ipr_err("%s\n", error->failure_reason);
-       ipr_err("Remote Adapter VPD:\n");
-       ipr_log_vpd(&error->vpd);
+       ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+                    be32_to_cpu(hostrcb->hcam.u.error.prc));
+       ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd);
        ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
@@ -1672,12 +1743,15 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
 
        list_del(&hostrcb->queue);
        list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 
        if (!ioasc) {
                ipr_handle_log_data(ioa_cfg, hostrcb);
+               if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED)
+                       ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
        } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
                dev_err(&ioa_cfg->pdev->dev,
                        "Host RCB failed with IOASC: 0x%08X\n", ioasc);
@@ -2635,8 +2709,13 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev,
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
+
        ioa_cfg->errors_logged = 0;
        ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
@@ -2958,6 +3037,11 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
        unsigned long lock_flags;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
 
        if (ioa_cfg->ucode_sglist) {
                spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -4656,18 +4740,19 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
        u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+       u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
 
        if (!res) {
                ipr_scsi_eh_done(ipr_cmd);
                return;
        }
 
-       if (!ipr_is_gscsi(res))
+       if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS)
                ipr_gen_sense(ipr_cmd);
 
        ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
-       switch (ioasc & IPR_IOASC_IOASC_MASK) {
+       switch (masked_ioasc) {
        case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
                if (ipr_is_naca_model(res))
                        scsi_cmd->result |= (DID_ABORT << 16);
@@ -5363,6 +5448,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
                        ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
        }
 
+       scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS);
        dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n");
 
        ioa_cfg->reset_retries = 0;
@@ -5798,6 +5884,94 @@ static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd)
        return IPR_RC_JOB_RETURN;
 }
 
+/**
+ * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function enables dual IOA RAID support if possible.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages;
+       struct ipr_mode_page24 *mode_page;
+       int length;
+
+       ENTER;
+       mode_page = ipr_get_mode_page(mode_pages, 0x24,
+                                     sizeof(struct ipr_mode_page24));
+
+       if (mode_page)
+               mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF;
+
+       length = mode_pages->hdr.length + 1;
+       mode_pages->hdr.length = 0;
+
+       ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11,
+                             ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
+                             length);
+
+       ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+       ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function handles the failure of a Mode Sense to the IOAFP.
+ * Some adapters do not handle all mode pages.
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd)
+{
+       u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+       if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+               return IPR_RC_JOB_CONTINUE;
+       }
+
+       return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+/**
+ * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function send a mode sense to the IOA to retrieve
+ * the IOA Advanced Function Control mode page.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+       ENTER;
+       ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE),
+                            0x24, ioa_cfg->vpd_cbs_dma +
+                            offsetof(struct ipr_misc_cbs, mode_pages),
+                            sizeof(struct ipr_mode_pages));
+
+       ipr_cmd->job_step = ipr_ioafp_mode_select_page24;
+       ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed;
+
+       ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
 /**
  * ipr_init_res_table - Initialize the resource table
  * @ipr_cmd:   ipr command struct
@@ -5866,7 +6040,10 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
                }
        }
 
-       ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+       if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page24;
+       else
+               ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
 
        LEAVE;
        return IPR_RC_JOB_CONTINUE;
@@ -5888,8 +6065,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
        struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
        struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+       struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
 
        ENTER;
+       if (cap->cap & IPR_CAP_DUAL_IOA_RAID)
+               ioa_cfg->dual_raid = 1;
        dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n",
                 ucode_vpd->major_release, ucode_vpd->card_type,
                 ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]);
@@ -5972,6 +6152,37 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
        return 0;
 }
 
+/**
+ * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
+ * @ipr_cmd:   ipr command struct
+ *
+ * This function sends a Page 0xD0 inquiry to the adapter
+ * to retrieve adapter capabilities.
+ *
+ * Return value:
+ *     IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+       struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
+
+       ENTER;
+       ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+       memset(cap, 0, sizeof(*cap));
+
+       if (ipr_inquiry_page_supported(page0, 0xD0)) {
+               ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0,
+                                 ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap),
+                                 sizeof(struct ipr_inquiry_cap));
+               return IPR_RC_JOB_RETURN;
+       }
+
+       LEAVE;
+       return IPR_RC_JOB_CONTINUE;
+}
+
 /**
  * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
  * @ipr_cmd:   ipr command struct
@@ -5992,7 +6203,7 @@ static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
        if (!ipr_inquiry_page_supported(page0, 1))
                ioa_cfg->cache_state = CACHE_NONE;
 
-       ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+       ipr_cmd->job_step = ipr_ioafp_cap_inquiry;
 
        ipr_ioafp_inquiry(ipr_cmd, 1, 3,
                          ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
@@ -6278,6 +6489,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
        struct ipr_hostrcb *hostrcb;
        struct ipr_uc_sdt sdt;
        int rc, length;
+       u32 ioasc;
 
        mailbox = readl(ioa_cfg->ioa_mailbox);
 
@@ -6310,9 +6522,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
                                        (__be32 *)&hostrcb->hcam,
                                        min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
 
-       if (!rc)
+       if (!rc) {
                ipr_handle_log_data(ioa_cfg, hostrcb);
-       else
+               ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+               if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
+                   ioa_cfg->sdt_state == GET_DUMP)
+                       ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+       } else
                ipr_unit_check_no_data(ioa_cfg);
 
        list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
@@ -6424,6 +6640,48 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
        return rc;
 }
 
+/**
+ * ipr_reset_slot_reset_done - Clear PCI reset to the adapter
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This clears PCI reset to the adapter and delays two seconds.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+       ENTER;
+       pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
+       ipr_cmd->job_step = ipr_reset_bist_done;
+       ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_slot_reset - Reset the PCI slot of the adapter.
+ * @ipr_cmd:   ipr command struct
+ *
+ * Description: This asserts PCI reset to the adapter.
+ *
+ * Return value:
+ *     IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
+{
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+       struct pci_dev *pdev = ioa_cfg->pdev;
+
+       ENTER;
+       pci_block_user_cfg_access(pdev);
+       pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+       ipr_cmd->job_step = ipr_reset_slot_reset_done;
+       ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
+       LEAVE;
+       return IPR_RC_JOB_RETURN;
+}
+
 /**
  * ipr_reset_allowed - Query whether or not IOA can be reset
  * @ioa_cfg:   ioa config struct
@@ -6463,7 +6721,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
                ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
                ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
        } else {
-               ipr_cmd->job_step = ipr_reset_start_bist;
+               ipr_cmd->job_step = ioa_cfg->reset;
                rc = IPR_RC_JOB_CONTINUE;
        }
 
@@ -6496,7 +6754,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
                writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
                ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
        } else {
-               ipr_cmd->job_step = ipr_reset_start_bist;
+               ipr_cmd->job_step = ioa_cfg->reset;
        }
 
        ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
@@ -6591,12 +6849,14 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
                ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
                ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type;
 
-               if (shutdown_type == IPR_SHUTDOWN_ABBREV)
-                       timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
+               if (shutdown_type == IPR_SHUTDOWN_NORMAL)
+                       timeout = IPR_SHUTDOWN_TIMEOUT;
                else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL)
                        timeout = IPR_INTERNAL_TIMEOUT;
+               else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+                       timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO;
                else
-                       timeout = IPR_SHUTDOWN_TIMEOUT;
+                       timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
 
                ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout);
 
@@ -6776,8 +7036,11 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-       _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
-                                        IPR_SHUTDOWN_NONE);
+       if (ioa_cfg->needs_warm_reset)
+               ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+       else
+               _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+                                       IPR_SHUTDOWN_NONE);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
        return PCI_ERS_RESULT_RECOVERED;
 }
@@ -7226,7 +7489,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        unsigned long ipr_regs_pci;
        void __iomem *ipr_regs;
        int rc = PCIBIOS_SUCCESSFUL;
-       volatile u32 mask, uproc;
+       volatile u32 mask, uproc, interrupts;
 
        ENTER;
 
@@ -7265,6 +7528,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        else
                ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
 
+       rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid);
+
+       if (rc != PCIBIOS_SUCCESSFUL) {
+               dev_err(&pdev->dev, "Failed to read PCI revision ID\n");
+               rc = -EIO;
+               goto out_scsi_host_put;
+       }
+
        ipr_regs_pci = pci_resource_start(pdev, 0);
 
        rc = pci_request_regions(pdev, IPR_NAME);
@@ -7333,9 +7604,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
         * the card is in an unknown state and needs a hard reset
         */
        mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+       interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
        uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
        if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
                ioa_cfg->needs_hard_reset = 1;
+       if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
+               ioa_cfg->needs_hard_reset = 1;
+       if (interrupts & IPR_PCII_IOA_UNIT_CHECKED)
+               ioa_cfg->ioa_unit_checked = 1;
 
        ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
        rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
@@ -7346,6 +7622,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
                goto cleanup_nolog;
        }
 
+       if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) ||
+           (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) {
+               ioa_cfg->needs_warm_reset = 1;
+               ioa_cfg->reset = ipr_reset_slot_reset;
+       } else
+               ioa_cfg->reset = ipr_reset_start_bist;
+
        spin_lock(&ipr_driver_lock);
        list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
        spin_unlock(&ipr_driver_lock);
@@ -7428,6 +7711,12 @@ static void __ipr_remove(struct pci_dev *pdev)
        ENTER;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+       }
+
        ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
 
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
@@ -7551,6 +7840,12 @@ static void ipr_shutdown(struct pci_dev *pdev)
        unsigned long lock_flags = 0;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
+
        ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
        wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
@@ -7577,19 +7872,22 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT},
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 },
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0,
+             IPR_USE_LONG_TRANSOP_TIMEOUT },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
              IPR_USE_LONG_TRANSOP_TIMEOUT },
@@ -7597,7 +7895,7 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
-             IPR_USE_LONG_TRANSOP_TIMEOUT },
+             IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
@@ -7627,6 +7925,7 @@ static struct pci_driver ipr_driver = {
        .remove = ipr_remove,
        .shutdown = ipr_shutdown,
        .err_handler = &ipr_err_handler,
+       .dynids.use_driver_data = 1
 };
 
 /**
index bc53d7cebe0ac645e654b34889e9fb0c4cfbd9f5..d93156671e93d7155505098242f821a46c1ed973 100644 (file)
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.3.2"
-#define IPR_DRIVER_DATE "(March 23, 2007)"
+#define IPR_DRIVER_VERSION "2.4.1"
+#define IPR_DRIVER_DATE "(April 24, 2007)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -91,6 +91,7 @@
  * IOASCs
  */
 #define IPR_IOASC_NR_INIT_CMD_REQUIRED         0x02040200
+#define IPR_IOASC_NR_IOA_RESET_REQUIRED                0x02048000
 #define IPR_IOASC_SYNC_REQUIRED                        0x023f0000
 #define IPR_IOASC_MED_DO_NOT_REALLOC           0x03110C00
 #define IPR_IOASC_HW_SEL_TIMEOUT                       0x04050000
 
 /* Driver data flags */
 #define IPR_USE_LONG_TRANSOP_TIMEOUT           0x00000001
+#define IPR_USE_PCI_WARM_RESET                 0x00000002
 
 #define IPR_DEFAULT_MAX_ERROR_DUMP                     984
 #define IPR_NUM_LOG_HCAMS                              2
 #define IPR_SHUTDOWN_TIMEOUT                   (ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
 #define IPR_VSET_RW_TIMEOUT                    (ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
 #define IPR_ABBREV_SHUTDOWN_TIMEOUT            (10 * HZ)
+#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO  (2 * 60 * HZ)
 #define IPR_DEVICE_RESET_TIMEOUT               (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_CANCEL_ALL_TIMEOUT         (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_ABORT_TASK_TIMEOUT         (ipr_fastfail ? 10 * HZ : 30 * HZ)
 #define IPR_WAIT_FOR_RESET_TIMEOUT             (2 * HZ)
 #define IPR_CHECK_FOR_RESET_TIMEOUT            (HZ / 10)
 #define IPR_WAIT_FOR_BIST_TIMEOUT              (2 * HZ)
+#define IPR_PCI_RESET_TIMEOUT                  (HZ / 2)
 #define IPR_DUMP_TIMEOUT                       (15 * HZ)
 
 /*
@@ -602,6 +606,12 @@ struct ipr_mode_page28 {
        struct ipr_dev_bus_entry bus[0];
 }__attribute__((packed));
 
+struct ipr_mode_page24 {
+       struct ipr_mode_page_hdr hdr;
+       u8 flags;
+#define IPR_ENABLE_DUAL_IOA_AF 0x80
+}__attribute__((packed));
+
 struct ipr_ioa_vpd {
        struct ipr_std_inq_data std_inq_data;
        u8 ascii_part_num[12];
@@ -624,6 +634,19 @@ struct ipr_inquiry_page3 {
        u8 patch_number[4];
 }__attribute__((packed));
 
+struct ipr_inquiry_cap {
+       u8 peri_qual_dev_type;
+       u8 page_code;
+       u8 reserved1;
+       u8 page_length;
+       u8 ascii_len;
+       u8 reserved2;
+       u8 sis_version[2];
+       u8 cap;
+#define IPR_CAP_DUAL_IOA_RAID          0x80
+       u8 reserved3[15];
+}__attribute__((packed));
+
 #define IPR_INQUIRY_PAGE0_ENTRIES 20
 struct ipr_inquiry_page0 {
        u8 peri_qual_dev_type;
@@ -962,6 +985,7 @@ struct ipr_misc_cbs {
        struct ipr_ioa_vpd ioa_vpd;
        struct ipr_inquiry_page0 page0_data;
        struct ipr_inquiry_page3 page3_data;
+       struct ipr_inquiry_cap cap;
        struct ipr_mode_pages mode_pages;
        struct ipr_supported_device supp_dev;
 };
@@ -1068,6 +1092,10 @@ struct ipr_ioa_cfg {
        u8 allow_cmds:1;
        u8 allow_ml_add_del:1;
        u8 needs_hard_reset:1;
+       u8 dual_raid:1;
+       u8 needs_warm_reset:1;
+
+       u8 revid;
 
        enum ipr_cache_state cache_state;
        u16 type; /* CCIN of the card */
@@ -1161,6 +1189,7 @@ struct ipr_ioa_cfg {
        struct pci_pool *ipr_cmd_pool;
 
        struct ipr_cmnd *reset_cmd;
+       int (*reset) (struct ipr_cmnd *);
 
        struct ata_host ata_host;
        char ipr_cmd_label[8];
index 897a5e2c55e438a806c6e93072547a7386922832..b4b52694497c16312d87ed2d2203e55ad630ff07 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#include <linux/kthread.h>
+
 #include "sas_internal.h"
 
 #include <scsi/scsi_host.h>
@@ -184,7 +186,7 @@ static int sas_queue_up(struct sas_task *task)
        list_add_tail(&task->list, &core->task_queue);
        core->task_queue_size += 1;
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
-       up(&core->queue_thread_sema);
+       wake_up_process(core->queue_thread);
 
        return 0;
 }
@@ -819,7 +821,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        struct sas_internal *i = to_sas_internal(core->shost->transportt);
 
        spin_lock_irqsave(&core->task_queue_lock, flags);
-       while (!core->queue_thread_kill &&
+       while (!kthread_should_stop() &&
               !list_empty(&core->task_queue)) {
 
                can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
@@ -858,8 +860,6 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
 }
 
-static DECLARE_COMPLETION(queue_th_comp);
-
 /**
  * sas_queue_thread -- The Task Collector thread
  * @_sas_ha: pointer to struct sas_ha
@@ -867,40 +867,33 @@ static DECLARE_COMPLETION(queue_th_comp);
 static int sas_queue_thread(void *_sas_ha)
 {
        struct sas_ha_struct *sas_ha = _sas_ha;
-       struct scsi_core *core = &sas_ha->core;
 
-       daemonize("sas_queue_%d", core->shost->host_no);
        current->flags |= PF_NOFREEZE;
 
-       complete(&queue_th_comp);
-
        while (1) {
-               down_interruptible(&core->queue_thread_sema);
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
                sas_queue(sas_ha);
-               if (core->queue_thread_kill)
+               if (kthread_should_stop())
                        break;
        }
 
-       complete(&queue_th_comp);
-
        return 0;
 }
 
 int sas_init_queue(struct sas_ha_struct *sas_ha)
 {
-       int res;
        struct scsi_core *core = &sas_ha->core;
 
        spin_lock_init(&core->task_queue_lock);
        core->task_queue_size = 0;
        INIT_LIST_HEAD(&core->task_queue);
-       init_MUTEX_LOCKED(&core->queue_thread_sema);
 
-       res = kernel_thread(sas_queue_thread, sas_ha, 0);
-       if (res >= 0)
-               wait_for_completion(&queue_th_comp);
-
-       return res < 0 ? res : 0;
+       core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
+                                        "sas_queue_%d", core->shost->host_no);
+       if (IS_ERR(core->queue_thread))
+               return PTR_ERR(core->queue_thread);
+       return 0;
 }
 
 void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
@@ -909,10 +902,7 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
        struct scsi_core *core = &sas_ha->core;
        struct sas_task *task, *n;
 
-       init_completion(&queue_th_comp);
-       core->queue_thread_kill = 1;
-       up(&core->queue_thread_sema);
-       wait_for_completion(&queue_th_comp);
+       kthread_stop(core->queue_thread);
 
        if (!list_empty(&core->task_queue))
                SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
index a7de0bca5bdd31efd19b2683e95feaa39e7aadcd..82e8f90c46178472c3cb24243250dea996cdcd46 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -27,10 +27,6 @@ struct lpfc_sli2_slim;
                                           requests */
 #define LPFC_MAX_NS_RETRY      3       /* Number of retry attempts to contact
                                           the NameServer  before giving up. */
-#define LPFC_DFT_HBA_Q_DEPTH   2048    /* max cmds per hba */
-#define LPFC_LC_HBA_Q_DEPTH    1024    /* max cmds per low cost hba */
-#define LPFC_LP101_HBA_Q_DEPTH 128     /* max cmds per low cost hba */
-
 #define LPFC_CMD_PER_LUN       3       /* max outstanding cmds per lun */
 #define LPFC_SG_SEG_CNT                64      /* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT     2250    /* list of IOCBs for fast-path usage. */
@@ -244,28 +240,23 @@ struct lpfc_hba {
 #define FC_FABRIC               0x100  /* We are fabric attached */
 #define FC_ESTABLISH_LINK       0x200  /* Reestablish Link */
 #define FC_RSCN_DISCOVERY       0x400  /* Authenticate all devices after RSCN*/
+#define FC_BLOCK_MGMT_IO        0x800   /* Don't allow mgmt mbx or iocb cmds */
 #define FC_LOADING             0x1000  /* HBA in process of loading drvr */
 #define FC_UNLOADING           0x2000  /* HBA in process of unloading drvr */
 #define FC_SCSI_SCAN_TMO        0x4000 /* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000 /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000        /* NPort discovery active */
 #define FC_BYPASSED_MODE        0x20000        /* NPort is in bypassed mode */
+#define FC_LOOPBACK_MODE        0x40000        /* NPort is in Loopback mode */
+                                       /* This flag is set while issuing */
+                                       /* INIT_LINK mailbox command */
+#define FC_IGNORE_ERATT         0x80000        /* intr handler should ignore ERATT */
 
        uint32_t fc_topology;   /* link topology, from LINK INIT */
 
        struct lpfc_stats fc_stat;
 
-       /* These are the head/tail pointers for the bind, plogi, adisc, unmap,
-        *  and map lists.  Their counters are immediately following.
-        */
-       struct list_head fc_plogi_list;
-       struct list_head fc_adisc_list;
-       struct list_head fc_reglogin_list;
-       struct list_head fc_prli_list;
-       struct list_head fc_nlpunmap_list;
-       struct list_head fc_nlpmap_list;
-       struct list_head fc_npr_list;
-       struct list_head fc_unused_list;
+       struct list_head fc_nodes;
 
        /* Keep counters for the number of entries in each list. */
        uint16_t fc_plogi_cnt;
@@ -387,13 +378,17 @@ struct lpfc_hba {
 
        mempool_t *mbox_mem_pool;
        mempool_t *nlp_mem_pool;
-       struct list_head freebufList;
-       struct list_head ctrspbuflist;
-       struct list_head rnidrspbuflist;
 
        struct fc_host_statistics link_stats;
 };
 
+static inline void
+lpfc_set_loopback_flag(struct lpfc_hba *phba) {
+       if (phba->cfg_topology == FLAGS_LOCAL_LB)
+               phba->fc_flag |= FC_LOOPBACK_MODE;
+       else
+               phba->fc_flag &= ~FC_LOOPBACK_MODE;
+}
 
 struct rnidrsp {
        void *buf;
index f247e786af99487cda664cae44193adec19af7b3..95fe77e816f80a756b937f6012b8ab989e14ac74 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -20,6 +20,7 @@
  *******************************************************************/
 
 #include <linux/ctype.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -213,6 +214,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
        int mbxstatus = MBXERR_ERROR;
 
        if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+           (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
            (phba->hba_state != LPFC_HBA_READY))
                return -EPERM;
 
@@ -235,6 +237,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
                                                     phba->fc_ratov * 2);
        }
 
+       lpfc_set_loopback_flag(phba);
        if (mbxstatus == MBX_TIMEOUT)
                pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        else
@@ -247,19 +250,62 @@ lpfc_issue_lip(struct Scsi_Host *host)
 }
 
 static int
-lpfc_selective_reset(struct lpfc_hba *phba)
+lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 {
        struct completion online_compl;
+       struct lpfc_sli_ring *pring;
+       struct lpfc_sli *psli;
        int status = 0;
+       int cnt = 0;
+       int i;
 
        init_completion(&online_compl);
        lpfc_workq_post_event(phba, &status, &online_compl,
-                             LPFC_EVT_OFFLINE);
+                             LPFC_EVT_OFFLINE_PREP);
+       wait_for_completion(&online_compl);
+
+       if (status != 0)
+               return -EIO;
+
+       psli = &phba->sli;
+
+       for (i = 0; i < psli->num_rings; i++) {
+               pring = &psli->ring[i];
+               /* The linkdown event takes 30 seconds to timeout. */
+               while (pring->txcmplq_cnt) {
+                       msleep(10);
+                       if (cnt++ > 3000) {
+                               lpfc_printf_log(phba,
+                                       KERN_WARNING, LOG_INIT,
+                                       "%d:0466 Outstanding IO when "
+                                       "bringing Adapter offline\n",
+                                       phba->brd_no);
+                               break;
+                       }
+               }
+       }
+
+       init_completion(&online_compl);
+       lpfc_workq_post_event(phba, &status, &online_compl, type);
        wait_for_completion(&online_compl);
 
        if (status != 0)
                return -EIO;
 
+       return 0;
+}
+
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
+{
+       struct completion online_compl;
+       int status = 0;
+
+       status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+
+       if (status != 0)
+               return status;
+
        init_completion(&online_compl);
        lpfc_workq_post_event(phba, &status, &online_compl,
                              LPFC_EVT_ONLINE);
@@ -324,23 +370,19 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
 
        init_completion(&online_compl);
 
-       if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+       if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
                lpfc_workq_post_event(phba, &status, &online_compl,
                                      LPFC_EVT_ONLINE);
-       else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_OFFLINE);
+               wait_for_completion(&online_compl);
+       } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+               status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
        else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_WARM_START);
-       else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
-               lpfc_workq_post_event(phba, &status, &online_compl,
-                                     LPFC_EVT_KILL);
+               status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+       else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+               status = lpfc_do_offline(phba, LPFC_EVT_KILL);
        else
                return -EINVAL;
 
-       wait_for_completion(&online_compl);
-
        if (!status)
                return strlen(buf);
        else
@@ -645,9 +687,7 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
        dev_printk(KERN_NOTICE, &phba->pcidev->dev,
                   "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
 
-       init_completion(&online_compl);
-       lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
-       wait_for_completion(&online_compl);
+       stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
        if (stat1)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
@@ -789,6 +829,18 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
        return -EINVAL;
 }
 
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+       struct lpfc_nodelist  *ndlp;
+
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
+               if (ndlp->rport)
+                       ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+       spin_unlock_irq(phba->host->host_lock);
+}
+
 static int
 lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
 {
@@ -804,6 +856,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
        if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
                phba->cfg_nodev_tmo = val;
                phba->cfg_devloss_tmo = val;
+               lpfc_update_rport_devloss_tmo(phba);
                return 0;
        }
 
@@ -839,6 +892,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
                phba->cfg_nodev_tmo = val;
                phba->cfg_devloss_tmo = val;
                phba->dev_loss_tmo_changed = 1;
+               lpfc_update_rport_devloss_tmo(phba);
                return 0;
        }
 
@@ -931,9 +985,10 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
 #       1  = 1 Gigabaud
 #       2  = 2 Gigabaud
 #       4  = 4 Gigabaud
-# Value range is [0,4]. Default value is 0.
+#       8  = 8 Gigabaud
+# Value range is [0,8]. Default value is 0.
 */
-LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed");
+LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -958,7 +1013,7 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
 /*
 # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing
 # cr_delay (msec) or cr_count outstanding commands. cr_delay can take
-# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay
+# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay
 # is 0. Default value of cr_count is 1. The cr_count feature is disabled if
 # cr_delay is set to 0.
 */
@@ -1227,11 +1282,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
        struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
        int rc;
 
-       if (off > sizeof(MAILBOX_t))
+       if (off > MAILBOX_CMD_SIZE)
                return -ERANGE;
 
-       if ((count + off) > sizeof(MAILBOX_t))
-               count = sizeof(MAILBOX_t) - off;
+       if ((count + off) > MAILBOX_CMD_SIZE)
+               count = MAILBOX_CMD_SIZE - off;
 
        if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
                return -EINVAL;
@@ -1307,6 +1362,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
                        return -EPERM;
                }
 
+               if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+                       sysfs_mbox_idle(phba);
+                       spin_unlock_irq(host->host_lock);
+                       return  -EAGAIN;
+               }
+
                if ((phba->fc_flag & FC_OFFLINE_MODE) ||
                    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
 
@@ -1326,6 +1387,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
                }
 
                if (rc != MBX_SUCCESS) {
+                       if (rc == MBX_TIMEOUT) {
+                               phba->sysfs_mbox.mbox->mbox_cmpl =
+                                       lpfc_sli_def_mbox_cmpl;
+                               phba->sysfs_mbox.mbox = NULL;
+                       }
                        sysfs_mbox_idle(phba);
                        spin_unlock_irq(host->host_lock);
                        return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
@@ -1344,7 +1410,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 
        phba->sysfs_mbox.offset = off + count;
 
-       if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t))
+       if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
                sysfs_mbox_idle(phba);
 
        spin_unlock_irq(phba->host->host_lock);
@@ -1358,7 +1424,7 @@ static struct bin_attribute sysfs_mbox_attr = {
                .mode = S_IRUSR | S_IWUSR,
                .owner = THIS_MODULE,
        },
-       .size = sizeof(MAILBOX_t),
+       .size = MAILBOX_CMD_SIZE,
        .read = sysfs_mbox_read,
        .write = sysfs_mbox_write,
 };
@@ -1494,6 +1560,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
                        case LA_4GHZ_LINK:
                                fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
                        break;
+                       case LA_8GHZ_LINK:
+                               fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+                       break;
                        default:
                                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
                        break;
@@ -1546,6 +1615,9 @@ lpfc_get_stats(struct Scsi_Host *shost)
        unsigned long seconds;
        int rc = 0;
 
+       if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+               return NULL;
+
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq)
                return NULL;
@@ -1631,6 +1703,8 @@ lpfc_get_stats(struct Scsi_Host *shost)
        else
                hs->seconds_since_last_reset = seconds - psli->stats_start;
 
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+
        return hs;
 }
 
@@ -1644,6 +1718,9 @@ lpfc_reset_stats(struct Scsi_Host *shost)
        MAILBOX_t *pmb;
        int rc = 0;
 
+       if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+               return;
+
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq)
                return;
@@ -1699,6 +1776,8 @@ lpfc_reset_stats(struct Scsi_Host *shost)
 
        psli->stats_start = get_seconds();
 
+       mempool_free(pmboxq, phba->mbox_mem_pool);
+
        return;
 }
 
@@ -1706,67 +1785,51 @@ lpfc_reset_stats(struct Scsi_Host *shost)
  * The LPFC driver treats linkdown handling as target loss events so there
  * are no sysfs handlers for link_down_tmo.
  */
-static void
-lpfc_get_starget_port_id(struct scsi_target *starget)
+
+static struct lpfc_nodelist *
+lpfc_get_node_by_target(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       uint32_t did = -1;
-       struct lpfc_nodelist *ndlp = NULL;
+       struct lpfc_nodelist *ndlp;
 
        spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       did = ndlp->nlp_DID;
-                       break;
+       /* Search for this, mapped, target ID */
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+                   starget->id == ndlp->nlp_sid) {
+                       spin_unlock_irq(shost->host_lock);
+                       return ndlp;
                }
        }
        spin_unlock_irq(shost->host_lock);
+       return NULL;
+}
+
+static void
+lpfc_get_starget_port_id(struct scsi_target *starget)
+{
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_port_id(starget) = did;
+       fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1;
 }
 
 static void
 lpfc_get_starget_node_name(struct scsi_target *starget)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       u64 node_name = 0;
-       struct lpfc_nodelist *ndlp = NULL;
-
-       spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
-                       break;
-               }
-       }
-       spin_unlock_irq(shost->host_lock);
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_node_name(starget) = node_name;
+       fc_starget_node_name(starget) =
+               ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0;
 }
 
 static void
 lpfc_get_starget_port_name(struct scsi_target *starget)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
-       u64 port_name = 0;
-       struct lpfc_nodelist *ndlp = NULL;
-
-       spin_lock_irq(shost->host_lock);
-       /* Search the mapped list for this target ID */
-       list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-               if (starget->id == ndlp->nlp_sid) {
-                       port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
-                       break;
-               }
-       }
-       spin_unlock_irq(shost->host_lock);
+       struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
 
-       fc_starget_port_name(starget) = port_name;
+       fc_starget_port_name(starget) =
+               ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0;
 }
 
 static void
@@ -1895,25 +1958,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
                        sizeof(struct fcp_rsp) +
                        (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
 
-       switch (phba->pcidev->device) {
-       case PCI_DEVICE_ID_LP101:
-       case PCI_DEVICE_ID_BSMB:
-       case PCI_DEVICE_ID_ZSMB:
-               phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH;
-               break;
-       case PCI_DEVICE_ID_RFLY:
-       case PCI_DEVICE_ID_PFLY:
-       case PCI_DEVICE_ID_BMID:
-       case PCI_DEVICE_ID_ZMID:
-       case PCI_DEVICE_ID_TFLY:
-               phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH;
-               break;
-       default:
-               phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
-       }
 
-       if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth)
-               lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+       lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
 
        return;
 }
index 1251788ce2a36efa58b61c096c18b7350b8b5a66..b8c2a8862d8cbc8dda943a54f0153bfb19ed3f22 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,6 +18,8 @@
  * included with this package.                                     *
  *******************************************************************/
 
+typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
+
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -43,20 +45,24 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_set_disctmo(struct lpfc_hba *);
 int lpfc_can_disctmo(struct lpfc_hba *);
 int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
 int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
                    struct lpfc_iocbq *, struct lpfc_nodelist *);
-int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+int  lpfc_nlp_put(struct lpfc_nodelist *);
 struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
 void lpfc_disc_list_loopmap(struct lpfc_hba *);
 void lpfc_disc_start(struct lpfc_hba *);
 void lpfc_disc_flush_list(struct lpfc_hba *);
 void lpfc_disc_timeout(unsigned long);
 
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
 
 int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -66,8 +72,7 @@ int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
 
 int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
                     struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
-                       int);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_hba *);
 int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
@@ -113,7 +118,10 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
 int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
-int lpfc_offline(struct lpfc_hba *);
+void lpfc_block_mgmt_io(struct lpfc_hba *);
+void lpfc_unblock_mgmt_io(struct lpfc_hba *);
+void lpfc_offline_prep(struct lpfc_hba *);
+void lpfc_offline(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -162,8 +170,8 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
                                             struct lpfc_sli_ring *,
                                             dma_addr_t);
-int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
-                                struct lpfc_iocbq *);
+int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
+                              struct lpfc_iocbq *);
 int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
                          uint64_t, lpfc_ctx_cmd);
 int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -172,9 +180,8 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
-                                       struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
 
 int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                         uint32_t timeout);
@@ -193,6 +200,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
 
 /* Function prototypes. */
 const char* lpfc_info(struct Scsi_Host *);
+void lpfc_scan_start(struct Scsi_Host *);
+int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
+
 void lpfc_get_cfgparam(struct lpfc_hba *);
 int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
 void lpfc_free_sysfs_attr(struct lpfc_hba *);
index a51a41b7f15d55566277619d8be5e64d06b31324..34a9e3bb2614058c9ca827be246b65539564e0cb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -334,21 +334,22 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
 
        lpfc_set_disctmo(phba);
 
-       Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
 
        list_add_tail(&head, &mp->list);
        list_for_each_entry_safe(mp, next_mp, &head, list) {
                mlast = mp;
 
+               Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;
+
                Size -= Cnt;
 
-               if (!ctptr)
+               if (!ctptr) {
                        ctptr = (uint32_t *) mlast->virt;
-               else
+               else
                        Cnt -= 16;      /* subtract length of CT header */
 
                /* Loop through entire NameServer list of DIDs */
-               while (Cnt) {
+               while (Cnt >= sizeof (uint32_t)) {
 
                        /* Get next DID from NameServer List */
                        CTentry = *ctptr++;
@@ -442,10 +443,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
                        phba->fc_ns_retry++;
                        /* CT command is being retried */
-                       ndlp =
-                           lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                                             NameServer_DID);
-                       if (ndlp) {
+                       ndlp = lpfc_findnode_did(phba, NameServer_DID);
+                       if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                                if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
                                    0) {
                                        goto out;
@@ -729,7 +728,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
        uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
        uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+       ndlp = lpfc_findnode_did(phba, FDMI_DID);
        if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
                /* FDMI rsp failed */
                lpfc_printf_log(phba,
@@ -1039,6 +1038,9 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
                                case LA_4GHZ_LINK:
                                        ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
                                break;
+                               case LA_8GHZ_LINK:
+                                       ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+                               break;
                                default:
                                        ae->un.PortSpeed =
                                                HBA_PORTSPEED_UNKNOWN;
@@ -1161,7 +1163,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+       ndlp = lpfc_findnode_did(phba, FDMI_DID);
        if (ndlp) {
                if (init_utsname()->nodename[0] != '\0') {
                        lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
index 9766f909c9c69e02a912eb90686e62d3fdbd4bbf..498059f3f7f43583727fd98d7ea7120a08e686d2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -31,6 +31,7 @@
 /* worker thread events */
 enum lpfc_work_type {
        LPFC_EVT_ONLINE,
+       LPFC_EVT_OFFLINE_PREP,
        LPFC_EVT_OFFLINE,
        LPFC_EVT_WARM_START,
        LPFC_EVT_KILL,
@@ -68,7 +69,6 @@ struct lpfc_nodelist {
        uint16_t        nlp_maxframe;           /* Max RCV frame size */
        uint8_t         nlp_class_sup;          /* Supported Classes */
        uint8_t         nlp_retry;              /* used for ELS retries */
-       uint8_t         nlp_disc_refcnt;        /* used for DSM */
        uint8_t         nlp_fcp_info;           /* class info, bits 0-3 */
 #define NLP_FCP_2_DEVICE   0x10                        /* FCP-2 device */
 
@@ -79,20 +79,10 @@ struct lpfc_nodelist {
        struct lpfc_work_evt els_retry_evt;
        unsigned long last_ramp_up_time;        /* jiffy of last ramp up */
        unsigned long last_q_full_time;         /* jiffy of last queue full */
+       struct kref     kref;
 };
 
 /* Defines for nlp_flag (uint32) */
-#define NLP_NO_LIST        0x0         /* Indicates immediately free node */
-#define NLP_UNUSED_LIST    0x1         /* Flg to indicate node will be freed */
-#define NLP_PLOGI_LIST     0x2         /* Flg to indicate sent PLOGI */
-#define NLP_ADISC_LIST     0x3         /* Flg to indicate sent ADISC */
-#define NLP_REGLOGIN_LIST  0x4         /* Flg to indicate sent REG_LOGIN */
-#define NLP_PRLI_LIST      0x5         /* Flg to indicate sent PRLI */
-#define NLP_UNMAPPED_LIST  0x6         /* Node is now unmapped */
-#define NLP_MAPPED_LIST    0x7         /* Node is now mapped */
-#define NLP_NPR_LIST       0x8         /* Node is in NPort Recovery state */
-#define NLP_JUST_DQ        0x9         /* just deque ndlp in lpfc_nlp_list */
-#define NLP_LIST_MASK      0xf         /* mask to see what list node is on */
 #define NLP_PLOGI_SND      0x20                /* sent PLOGI request for this entry */
 #define NLP_PRLI_SND       0x40                /* sent PRLI request for this entry */
 #define NLP_ADISC_SND      0x80                /* sent ADISC request for this entry */
@@ -108,20 +98,8 @@ struct lpfc_nodelist {
                                           ACC */
 #define NLP_NPR_ADISC      0x2000000   /* Issue ADISC when dq'ed from
                                           NPR list */
-#define NLP_DELAY_REMOVE   0x4000000   /* Defer removal till end of DSM */
 #define NLP_NODEV_REMOVE   0x8000000   /* Defer removal till discovery ends */
 
-/* Defines for list searchs */
-#define NLP_SEARCH_MAPPED    0x1       /* search mapped */
-#define NLP_SEARCH_UNMAPPED  0x2       /* search unmapped */
-#define NLP_SEARCH_PLOGI     0x4       /* search plogi */
-#define NLP_SEARCH_ADISC     0x8       /* search adisc */
-#define NLP_SEARCH_REGLOGIN  0x10      /* search reglogin */
-#define NLP_SEARCH_PRLI      0x20      /* search prli */
-#define NLP_SEARCH_NPR       0x40      /* search npr */
-#define NLP_SEARCH_UNUSED    0x80      /* search mapped */
-#define NLP_SEARCH_ALL       0xff      /* search all lists */
-
 /* There are 4 different double linked lists nodelist entries can reside on.
  * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
  * when Link Up discovery or Registered State Change Notification (RSCN)
index a5f33a0dd4e7b79fb204cff5553d04c71c76177e..638b3cd677bdd30d68e82523901b50b23ada97b3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -182,6 +182,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
                icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
                icmd->un.elsreq64.remoteID = did;       /* DID */
                icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
+               icmd->ulpTimeout = phba->fc_ratov * 2;
        } else {
                icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
                icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
@@ -208,9 +209,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
        }
 
        /* Save for completion so we can release these resources */
-       elsiocb->context1 = (uint8_t *) ndlp;
-       elsiocb->context2 = (uint8_t *) pcmd;
-       elsiocb->context3 = (uint8_t *) pbuflist;
+       elsiocb->context1 = lpfc_nlp_get(ndlp);
+       elsiocb->context2 = pcmd;
+       elsiocb->context3 = pbuflist;
        elsiocb->retry = retry;
        elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
 
@@ -222,16 +223,16 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
                /* Xmit ELS command <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                                "%d:0116 Xmit ELS command x%x to remote "
-                               "NPORT x%x Data: x%x x%x\n",
+                               "NPORT x%x I/O tag: x%x, HBA state: x%x\n",
                                phba->brd_no, elscmd,
-                               did, icmd->ulpIoTag, phba->hba_state);
+                               did, elsiocb->iotag, phba->hba_state);
        } else {
                /* Xmit ELS response <elsCmd> to remote NPORT <did> */
                lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                                "%d:0117 Xmit ELS response x%x to remote "
-                               "NPORT x%x Data: x%x x%x\n",
+                               "NPORT x%x I/O tag: x%x, size: x%x\n",
                                phba->brd_no, elscmd,
-                               ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
+                               ndlp->nlp_DID, elsiocb->iotag, cmdSize);
        }
 
        return elsiocb;
@@ -304,7 +305,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                goto fail_free_mbox;
 
        mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
-       mbox->context2 = ndlp;
+       mbox->context2 = lpfc_nlp_get(ndlp);
 
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
        if (rc == MBX_NOT_FINISHED)
@@ -313,6 +314,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        return 0;
 
  fail_issue_reg_login:
+       lpfc_nlp_put(ndlp);
        mp = (struct lpfc_dmabuf *) mbox->context1;
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
@@ -368,9 +370,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                        mempool_free(mbox, phba->mbox_mem_pool);
                        goto fail;
                }
-               mempool_free(ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+               ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
                if (!ndlp) {
                        /*
                         * Cannot find existing Fabric ndlp, so allocate a
@@ -387,12 +389,11 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                                sizeof(struct lpfc_name));
                memcpy(&ndlp->nlp_nodename, &sp->nodeName,
                                sizeof(struct lpfc_name));
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
        } else {
                /* This side will wait for the PLOGI */
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
        }
 
        spin_lock_irq(phba->host->host_lock);
@@ -407,8 +408,8 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
 }
 
 static void
-lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
-                   struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                   struct lpfc_iocbq *rspiocb)
 {
        IOCB_t *irsp = &rspiocb->iocb;
        struct lpfc_nodelist *ndlp = cmdiocb->context1;
@@ -418,7 +419,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
 
        /* Check to see if link went down during discovery */
        if (lpfc_els_chk_latt(phba)) {
-               lpfc_nlp_remove(phba, ndlp);
+               lpfc_nlp_put(ndlp);
                goto out;
        }
 
@@ -433,13 +434,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
                phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
                spin_unlock_irq(phba->host->host_lock);
 
-               /* If private loop, then allow max outstandting els to be
+               /* If private loop, then allow max outstanding els to be
                 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
                 * alpa map would take too long otherwise.
                 */
                if (phba->alpa_map[0] == 0) {
-                       phba->cfg_discovery_threads =
-                           LPFC_MAX_DISC_THREADS;
+                       phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
                }
 
                /* FLOGI failure */
@@ -484,7 +484,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
        }
 
 flogifail:
-       lpfc_nlp_remove(phba, ndlp);
+       lpfc_nlp_put(ndlp);
 
        if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
            (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
@@ -582,24 +582,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
                icmd = &iocb->iocb;
                if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
                        ndlp = (struct lpfc_nodelist *)(iocb->context1);
-                       if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
-                               list_del(&iocb->list);
-                               pring->txcmplq_cnt--;
-
-                               if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
-                                       lpfc_sli_issue_abort_iotag32
-                                               (phba, pring, iocb);
-                               }
-                               if (iocb->iocb_cmpl) {
-                                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                                       icmd->un.ulpWord[4] =
-                                           IOERR_SLI_ABORTED;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       (iocb->iocb_cmpl) (phba, iocb, iocb);
-                                       spin_lock_irq(phba->host->host_lock);
-                               } else
-                                       lpfc_sli_release_iocbq(phba, iocb);
-                       }
+                       if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+                               lpfc_sli_issue_abort_iotag(phba, pring, iocb);
                }
        }
        spin_unlock_irq(phba->host->host_lock);
@@ -608,12 +592,12 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
 }
 
 int
-lpfc_initial_flogi(struct lpfc_hba * phba)
+lpfc_initial_flogi(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp;
 
        /* First look for the Fabric ndlp */
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID);
+       ndlp = lpfc_findnode_did(phba, Fabric_DID);
        if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
                ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -621,10 +605,10 @@ lpfc_initial_flogi(struct lpfc_hba * phba)
                        return 0;
                lpfc_nlp_init(phba, ndlp, Fabric_DID);
        } else {
-               lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
+               lpfc_dequeue_node(phba, ndlp);
        }
        if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
        }
        return 1;
 }
@@ -653,7 +637,7 @@ lpfc_more_plogi(struct lpfc_hba * phba)
 }
 
 static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
                         struct lpfc_nodelist *ndlp)
 {
        struct lpfc_nodelist *new_ndlp;
@@ -670,12 +654,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
 
        lp = (uint32_t *) prsp->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-       memset(name, 0, sizeof (struct lpfc_name));
+       memset(name, 0, sizeof(struct lpfc_name));
 
-       /* Now we to find out if the NPort we are logging into, matches the WWPN
+       /* Now we find out if the NPort we are logging into, matches the WWPN
         * we have for that ndlp. If not, we have some work to do.
         */
-       new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
+       new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
 
        if (new_ndlp == ndlp)
                return ndlp;
@@ -695,18 +679,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
        lpfc_unreg_rpi(phba, new_ndlp);
        new_ndlp->nlp_DID = ndlp->nlp_DID;
        new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
-       new_ndlp->nlp_state = ndlp->nlp_state;
-       lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
+       lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
 
        /* Move this back to NPR list */
-       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-       }
+       if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+               lpfc_drop_node(phba, ndlp);
        else {
                lpfc_unreg_rpi(phba, ndlp);
                ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        }
        return new_ndlp;
 }
@@ -720,13 +701,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        struct lpfc_dmabuf *prsp;
        int disc, rc, did, type;
 
-
        /* we pass cmdiocb to state machine which needs rspiocb as well */
        cmdiocb->context_un.rsp_iocb = rspiocb;
 
        irsp = &rspiocb->iocb;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL,
-                                               irsp->un.elsreq64.remoteID);
+       ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
        if (!ndlp)
                goto out;
 
@@ -1354,7 +1333,7 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_SCR);
        if (!elsiocb) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                return 1;
        }
 
@@ -1373,12 +1352,12 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                spin_unlock_irq(phba->host->host_lock);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
        spin_unlock_irq(phba->host->host_lock);
-       mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_nlp_put(ndlp);
        return 0;
 }
 
@@ -1407,7 +1386,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_RNID);
        if (!elsiocb) {
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                return 1;
        }
 
@@ -1428,7 +1407,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
 
        memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
        memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
-       if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) {
+       if ((ondlp = lpfc_findnode_did(phba, nportid))) {
                memcpy(&fp->OportName, &ondlp->nlp_portname,
                       sizeof (struct lpfc_name));
                memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
@@ -1440,12 +1419,12 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
        spin_lock_irq(phba->host->host_lock);
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                spin_unlock_irq(phba->host->host_lock);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               lpfc_nlp_put(ndlp);
                lpfc_els_free_iocb(phba, elsiocb);
                return 1;
        }
        spin_unlock_irq(phba->host->host_lock);
-       mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_nlp_put(ndlp);
        return 0;
 }
 
@@ -1554,29 +1533,25 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
        case ELS_CMD_PLOGI:
                if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                }
                break;
        case ELS_CMD_ADISC:
                if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                }
                break;
        case ELS_CMD_PRLI:
                if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
                }
                break;
        case ELS_CMD_LOGO:
                if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                }
                break;
        }
@@ -1614,12 +1589,12 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                cmd = *elscmd++;
        }
 
-       if(ndlp)
+       if (ndlp)
                did = ndlp->nlp_DID;
        else {
                /* We should only hit this case for retrying PLOGI */
                did = irsp->un.elsreq64.remoteID;
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+               ndlp = lpfc_findnode_did(phba, did);
                if (!ndlp && (cmd != ELS_CMD_PLOGI))
                        return 1;
        }
@@ -1746,8 +1721,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        ndlp->nlp_flag |= NLP_DELAY_TMO;
 
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                        ndlp->nlp_last_elscmd = cmd;
 
                        return 1;
@@ -1759,27 +1733,24 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                case ELS_CMD_PLOGI:
                        if (ndlp) {
                                ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_PLOGI_ISSUE);
                        }
                        lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
                        return 1;
                case ELS_CMD_ADISC:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                        lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
                        return 1;
                case ELS_CMD_PRLI:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
                        lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
                        return 1;
                case ELS_CMD_LOGO:
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_NPR_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                        lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
                        return 1;
                }
@@ -1796,10 +1767,14 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 int
-lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
+lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
        struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
 
+       if (elsiocb->context1) {
+               lpfc_nlp_put(elsiocb->context1);
+               elsiocb->context1 = NULL;
+       }
        /* context2  = cmd,  context2->next = rsp, context3 = bpl */
        if (elsiocb->context2) {
                buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
@@ -1843,7 +1818,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
        switch (ndlp->nlp_state) {
        case NLP_STE_UNUSED_NODE:       /* node is just allocated */
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                break;
        case NLP_STE_NPR_NODE:          /* NPort Recovery mode */
                lpfc_unreg_rpi(phba, ndlp);
@@ -1856,8 +1831,8 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 static void
-lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                 struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                 struct lpfc_iocbq *rspiocb)
 {
        IOCB_t *irsp;
        struct lpfc_nodelist *ndlp;
@@ -1872,14 +1847,14 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 
 
        /* Check to see if link went down during discovery */
-       if ((lpfc_els_chk_latt(phba)) || !ndlp) {
+       if (lpfc_els_chk_latt(phba) || !ndlp) {
                if (mbox) {
                        mp = (struct lpfc_dmabuf *) mbox->context1;
                        if (mp) {
                                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
                        }
-                       mempool_free( mbox, phba->mbox_mem_pool);
+                       mempool_free(mbox, phba->mbox_mem_pool);
                }
                goto out;
        }
@@ -1899,15 +1874,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
                        lpfc_unreg_rpi(phba, ndlp);
                        mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-                       mbox->context2 = ndlp;
+                       mbox->context2 = lpfc_nlp_get(ndlp);
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
                        if (lpfc_sli_issue_mbox(phba, mbox,
                                                (MBX_NOWAIT | MBX_STOP_IOCB))
                            != MBX_NOT_FINISHED) {
                                goto out;
                        }
+                       lpfc_nlp_put(ndlp);
                        /* NOTE: we should have messages for unsuccessful
                           reglogin */
                } else {
@@ -1917,7 +1892,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                               (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
                               (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
                                if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                       lpfc_drop_node(phba, ndlp);
                                        ndlp = NULL;
                                }
                        }
@@ -2012,15 +1987,16 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
                return 1;
        }
 
-       if (newnode)
+       if (newnode) {
+               lpfc_nlp_put(ndlp);
                elsiocb->context1 = NULL;
+       }
 
        /* Xmit ELS ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0128 Xmit ELS ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+                       "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2077,10 +2053,9 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
 
        /* Xmit ELS RJT <err> response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0129 Xmit ELS RJT x%x response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       rejectError, elsiocb->iocb.ulpIoTag,
+                       "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, rejectError, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -2119,18 +2094,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit ADISC ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0130 Xmit ADISC ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+                       "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2155,8 +2130,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
 }
 
 int
-lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
-                     struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+                     struct lpfc_nodelist *ndlp)
 {
        PRLI *npr;
        lpfc_vpd_t *vpd;
@@ -2178,18 +2153,18 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit PRLI ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0131 Xmit PRLI ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2232,9 +2207,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
 }
 
 static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
-                     uint8_t format,
-                     struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+                     struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
 {
        RNID *rn;
        IOCB_t *icmd;
@@ -2259,17 +2233,17 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
        if (!elsiocb)
                return 1;
 
+       icmd = &elsiocb->iocb;
+       oldcmd = &oldiocb->iocb;
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+
        /* Xmit RNID ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
                        "%d:0132 Xmit RNID ACC response tag x%x "
-                       "Data: x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "xri x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext);
 
-       icmd = &elsiocb->iocb;
-       oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2301,6 +2275,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
 
        phba->fc_stat.elsXmitACC++;
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+       lpfc_nlp_put(ndlp);
        elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
                                    * it could be freed */
 
@@ -2315,32 +2290,31 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
 }
 
 int
-lpfc_els_disc_adisc(struct lpfc_hba * phba)
+lpfc_els_disc_adisc(struct lpfc_hba *phba)
 {
        int sentadisc;
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
        sentadisc = 0;
-       /* go thru NPR list and issue any remaining ELS ADISCs */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                       nlp_listp) {
-               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-                       if (ndlp->nlp_flag & NLP_NPR_ADISC) {
-                               ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-                               ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                               lpfc_nlp_list(phba, ndlp,
-                                       NLP_ADISC_LIST);
-                               lpfc_issue_els_adisc(phba, ndlp, 0);
-                               sentadisc++;
-                               phba->num_disc_nodes++;
-                               if (phba->num_disc_nodes >=
-                                   phba->cfg_discovery_threads) {
-                                       spin_lock_irq(phba->host->host_lock);
-                                       phba->fc_flag |= FC_NLP_MORE;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       break;
-                               }
+       /* go thru NPR nodes and issue any remaining ELS ADISCs */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
+                       spin_lock_irq(phba->host->host_lock);
+                       ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                       spin_unlock_irq(phba->host->host_lock);
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+                       lpfc_issue_els_adisc(phba, ndlp, 0);
+                       sentadisc++;
+                       phba->num_disc_nodes++;
+                       if (phba->num_disc_nodes >=
+                           phba->cfg_discovery_threads) {
+                               spin_lock_irq(phba->host->host_lock);
+                               phba->fc_flag |= FC_NLP_MORE;
+                               spin_unlock_irq(phba->host->host_lock);
+                               break;
                        }
                }
        }
@@ -2360,24 +2334,22 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba)
 
        sentplogi = 0;
        /* go thru NPR list and issue any remaining ELS PLOGIs */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-                  (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
-                       if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-                               ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
-                               lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
-                               sentplogi++;
-                               phba->num_disc_nodes++;
-                               if (phba->num_disc_nodes >=
-                                   phba->cfg_discovery_threads) {
-                                       spin_lock_irq(phba->host->host_lock);
-                                       phba->fc_flag |= FC_NLP_MORE;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       break;
-                               }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
+                   (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+                       lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+                       sentplogi++;
+                       phba->num_disc_nodes++;
+                       if (phba->num_disc_nodes >=
+                           phba->cfg_discovery_threads) {
+                               spin_lock_irq(phba->host->host_lock);
+                               phba->fc_flag |= FC_NLP_MORE;
+                               spin_unlock_irq(phba->host->host_lock);
+                               break;
                        }
                }
        }
@@ -2479,42 +2451,30 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
 }
 
 static int
-lpfc_rscn_recovery_check(struct lpfc_hba * phba)
+lpfc_rscn_recovery_check(struct lpfc_hba *phba)
 {
-       struct lpfc_nodelist *ndlp = NULL, *next_ndlp;
-       struct list_head *listp;
-       struct list_head *node_list[7];
-       int i;
+       struct lpfc_nodelist *ndlp = NULL;
 
        /* Look at all nodes effected by pending RSCNs and move
-        * them to NPR list.
+        * them to NPR state.
         */
-       node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_nlpunmap_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_reglogin_list;
-       node_list[5] = &phba->fc_adisc_list;
-       node_list[6] = &phba->fc_plogi_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
 
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-                       if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
-                               continue;
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
+                   lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
+                       continue;
 
-                       lpfc_disc_state_machine(phba, ndlp, NULL,
+               lpfc_disc_state_machine(phba, ndlp, NULL,
                                        NLP_EVT_DEVICE_RECOVERY);
 
-                       /* Make sure NLP_DELAY_TMO is NOT running
-                        * after a device recovery event.
-                        */
-                       if (ndlp->nlp_flag & NLP_DELAY_TMO)
-                               lpfc_cancel_retry_delay_tmo(phba, ndlp);
-               }
+               /*
+                * Make sure NLP_DELAY_TMO is NOT running after a device
+                * recovery event.
+                */
+               if (ndlp->nlp_flag & NLP_DELAY_TMO)
+                       lpfc_cancel_retry_delay_tmo(phba, ndlp);
        }
+
        return 0;
 }
 
@@ -2639,8 +2599,8 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
 
        /* To process RSCN, first compare RSCN data with NameServer */
        phba->fc_ns_retry = 0;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID);
-       if (ndlp) {
+       ndlp = lpfc_findnode_did(phba, NameServer_DID);
+       if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                /* Good ndlp, issue CT Request to NameServer */
                if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
                        /* Wait for NameServer query cmpl before we can
@@ -2650,7 +2610,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
        } else {
                /* If login to NameServer does not exist, issue one */
                /* Good status, issue PLOGI to NameServer */
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (ndlp) {
                        /* Wait for NameServer login cmpl before we can
                           continue */
@@ -2664,8 +2624,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
                        lpfc_nlp_init(phba, ndlp, NameServer_DID);
                        ndlp->nlp_type |= NLP_FABRIC;
                        ndlp->nlp_prev_state = ndlp->nlp_state;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                        lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                        /* Wait for NameServer login cmpl before we can
                           continue */
@@ -2734,8 +2693,9 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
                        mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
                        rc = lpfc_sli_issue_mbox
                                (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+                       lpfc_set_loopback_flag(phba);
                        if (rc == MBX_NOT_FINISHED) {
-                               mempool_free( mbox, phba->mbox_mem_pool);
+                               mempool_free(mbox, phba->mbox_mem_pool);
                        }
                        return 1;
                } else if (rc > 0) {    /* greater than */
@@ -2800,8 +2760,8 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
 }
 
 static int
-lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                struct lpfc_nodelist *ndlp)
 {
        struct ls_rjt stat;
 
@@ -2815,7 +2775,7 @@ lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
 }
 
 static void
-lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
@@ -2838,14 +2798,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        pmb->context2 = NULL;
 
        if (mb->mbxStatus) {
-               mempool_free( pmb, phba->mbox_mem_pool);
+               mempool_free(pmb, phba->mbox_mem_pool);
                return;
        }
 
        cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
        elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
                                                ndlp->nlp_DID, ELS_CMD_ACC);
+       lpfc_nlp_put(ndlp);
        if (!elsiocb)
                return;
 
@@ -2875,15 +2836,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        /* Xmit ELS RPS ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0118 Xmit ELS RPS ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
        elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
        phba->fc_stat.elsXmitACC++;
+
        if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
                lpfc_els_free_iocb(phba, elsiocb);
        }
@@ -2923,13 +2884,14 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        lpfc_read_lnk_stat(phba, mbox);
                        mbox->context1 =
                            (void *)((unsigned long)cmdiocb->iocb.ulpContext);
-                       mbox->context2 = ndlp;
+                       mbox->context2 = lpfc_nlp_get(ndlp);
                        mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
                        if (lpfc_sli_issue_mbox (phba, mbox,
                            (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
                                /* Mbox completion will send ELS Response */
                                return 0;
                        }
+                       lpfc_nlp_put(ndlp);
                        mempool_free(mbox, phba->mbox_mem_pool);
                }
        }
@@ -2984,10 +2946,9 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
 
        /* Xmit ELS RPL ACC response tag <ulpIoTag> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "%d:0120 Xmit ELS RPL ACC response tag x%x "
-                       "Data: x%x x%x x%x x%x x%x\n",
-                       phba->brd_no,
-                       elsiocb->iocb.ulpIoTag,
+                       "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
+                       "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+                       phba->brd_no, elsiocb->iotag,
                        elsiocb->iocb.ulpContext, ndlp->nlp_DID,
                        ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
@@ -3091,8 +3052,8 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
                        /* Log back into the node before sending the FARP. */
                        if (fp->Rflags & FARP_REQUEST_PLOGI) {
                                ndlp->nlp_prev_state = ndlp->nlp_state;
-                               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_PLOGI_ISSUE);
                                lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                        }
 
@@ -3169,14 +3130,15 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                         */
 
                        list_for_each_entry_safe(ndlp, next_ndlp,
-                               &phba->fc_npr_list, nlp_listp) {
-
+                                                &phba->fc_nodes, nlp_listp) {
+                               if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                                       continue;
                                if (ndlp->nlp_type & NLP_FABRIC) {
                                        /*
                                         * Clean up old Fabric, Nameserver and
                                         * other NLP_FABRIC logins
                                         */
-                                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                       lpfc_drop_node(phba, ndlp);
                                } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                        /* Fail outstanding I/O now since this
                                         * device is marked for PLOGI
@@ -3193,20 +3155,22 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                /* Discovery not needed,
                 * move the nodes to their original state.
                 */
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                       nlp_listp) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                               continue;
 
                        switch (ndlp->nlp_prev_state) {
                        case NLP_STE_UNMAPPED_NODE:
                                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-                               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_UNMAPPED_NODE);
                                break;
 
                        case NLP_STE_MAPPED_NODE:
                                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                               ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-                               lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+                               lpfc_nlp_set_state(phba, ndlp,
+                                                  NLP_STE_MAPPED_NODE);
                                break;
 
                        default:
@@ -3246,9 +3210,8 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
        struct lpfc_dmabuf *pcmd;
-       struct list_head *dlp;
        uint32_t *elscmd;
-       uint32_t els_command;
+       uint32_t els_command=0;
        uint32_t timeout;
        uint32_t remote_ID;
 
@@ -3263,17 +3226,20 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
        timeout = (uint32_t)(phba->fc_ratov << 1);
 
        pring = &phba->sli.ring[LPFC_ELS_RING];
-       dlp = &pring->txcmplq;
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
                cmd = &piocb->iocb;
 
-               if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+               if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
+                       (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
+                       (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
                        continue;
                }
                pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
+               if (pcmd) {
+                       elscmd = (uint32_t *) (pcmd->virt);
+                       els_command = *elscmd;
+               }
 
                if ((els_command == ELS_CMD_FARP)
                    || (els_command == ELS_CMD_FARPR)) {
@@ -3289,19 +3255,10 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                        continue;
                }
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
-
                if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
                        struct lpfc_nodelist *ndlp;
-                       spin_unlock_irq(phba->host->host_lock);
-                       ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
-                       spin_lock_irq(phba->host->host_lock);
+                       ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
                        remote_ID = ndlp->nlp_DID;
-                       if (cmd->un.elsreq64.bdl.ulpIoTag32) {
-                               lpfc_sli_issue_abort_iotag32(phba,
-                                       pring, piocb);
-                       }
                } else {
                        remote_ID = cmd->un.elsreq64.remoteID;
                }
@@ -3313,17 +3270,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
                                phba->brd_no, els_command,
                                remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
 
-               /*
-                * The iocb has timed out; abort it.
-                */
-               if (piocb->iocb_cmpl) {
-                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                       spin_unlock_irq(phba->host->host_lock);
-                       (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
-               } else
-                       lpfc_sli_release_iocbq(phba, piocb);
+               lpfc_sli_issue_abort_iotag(phba, pring, piocb);
        }
        if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
                mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
@@ -3332,16 +3279,13 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
 }
 
 void
-lpfc_els_flush_cmd(struct lpfc_hba * phba)
+lpfc_els_flush_cmd(struct lpfc_hba *phba)
 {
-       struct lpfc_sli_ring *pring;
+       LIST_HEAD(completions);
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
        struct lpfc_iocbq *tmp_iocb, *piocb;
        IOCB_t *cmd = NULL;
-       struct lpfc_dmabuf *pcmd;
-       uint32_t *elscmd;
-       uint32_t els_command;
 
-       pring = &phba->sli.ring[LPFC_ELS_RING];
        spin_lock_irq(phba->host->host_lock);
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
                cmd = &piocb->iocb;
@@ -3351,29 +3295,15 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                }
 
                /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
-               if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) ||
-                   (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) ||
-                   (cmd->ulpCommand == CMD_CLOSE_XRI_CN) ||
-                   (cmd->ulpCommand == CMD_ABORT_XRI_CN)) {
+               if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+                   cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+                   cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+                   cmd->ulpCommand == CMD_ABORT_XRI_CN)
                        continue;
-               }
 
-               pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
+               list_move_tail(&piocb->list, &completions);
+               pring->txq_cnt--;
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
-
-               cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-               cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-
-               if (piocb->iocb_cmpl) {
-                       spin_unlock_irq(phba->host->host_lock);
-                       (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
-               } else
-                       lpfc_sli_release_iocbq(phba, piocb);
        }
 
        list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3382,24 +3312,24 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
                if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
                        continue;
                }
-               pcmd = (struct lpfc_dmabuf *) piocb->context2;
-               elscmd = (uint32_t *) (pcmd->virt);
-               els_command = *elscmd;
 
-               list_del(&piocb->list);
-               pring->txcmplq_cnt--;
+               lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+       }
+       spin_unlock_irq(phba->host->host_lock);
 
-               cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-               cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+       while(!list_empty(&completions)) {
+               piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &piocb->iocb;
+               list_del(&piocb->list);
 
                if (piocb->iocb_cmpl) {
-                       spin_unlock_irq(phba->host->host_lock);
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
                        (piocb->iocb_cmpl) (phba, piocb, piocb);
-                       spin_lock_irq(phba->host->host_lock);
                } else
                        lpfc_sli_release_iocbq(phba, piocb);
        }
-       spin_unlock_irq(phba->host->host_lock);
+
        return;
 }
 
@@ -3468,7 +3398,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        }
 
        did = icmd->un.rcvels.remoteID;
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+       ndlp = lpfc_findnode_did(phba, did);
        if (!ndlp) {
                /* Cannot find existing Fabric ndlp, so allocate a new one */
                ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -3484,12 +3414,13 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
                        ndlp->nlp_type |= NLP_FABRIC;
                }
-               ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
        }
 
        phba->fc_stat.elsRcvFrame++;
-       elsiocb->context1 = ndlp;
+       if (elsiocb->context1)
+               lpfc_nlp_put(elsiocb->context1);
+       elsiocb->context1 = lpfc_nlp_get(ndlp);
        elsiocb->context2 = mp;
 
        if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
@@ -3513,9 +3444,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_FLOGI:
                phba->fc_stat.elsRcvFLOGI++;
                lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_LOGO:
                phba->fc_stat.elsRcvLOGO++;
@@ -3536,9 +3466,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_RSCN:
                phba->fc_stat.elsRcvRSCN++;
                lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_ADISC:
                phba->fc_stat.elsRcvADISC++;
@@ -3579,30 +3508,26 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
        case ELS_CMD_LIRR:
                phba->fc_stat.elsRcvLIRR++;
                lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RPS:
                phba->fc_stat.elsRcvRPS++;
                lpfc_els_rcv_rps(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RPL:
                phba->fc_stat.elsRcvRPL++;
                lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        case ELS_CMD_RNID:
                phba->fc_stat.elsRcvRNID++;
                lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        default:
                /* Unsupported ELS command, reject */
@@ -3612,9 +3537,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
                                "%d:0115 Unknown ELS command x%x received from "
                                "NPORT x%x\n", phba->brd_no, cmd, did);
-               if (newnode) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-               }
+               if (newnode)
+                       lpfc_drop_node(phba, ndlp);
                break;
        }
 
@@ -3627,6 +3551,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
                lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
        }
 
+       lpfc_nlp_put(elsiocb->context1);
+       elsiocb->context1 = NULL;
        if (elsiocb->context2) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
index c39564e85e944f62ebed5d8b3d41a6f75daf4ff7..61caa8d379e2dc7a120481da5f8ad54f671289f5 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -109,6 +109,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                return;
        }
 
+       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+               return;
+
        name = (uint8_t *)&ndlp->nlp_portname;
        phba = ndlp->nlp_phba;
 
@@ -147,11 +150,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                                ndlp->nlp_state, ndlp->nlp_rpi);
        }
 
-       ndlp->rport = NULL;
-       rdata->pnode = NULL;
-
-       if (!(phba->fc_flag & FC_UNLOADING))
+       if (!(phba->fc_flag & FC_UNLOADING) &&
+           !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+           !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+           (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
                lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+       else {
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
+               lpfc_nlp_put(ndlp);
+               put_device(&rport->dev);
+       }
 
        return;
 }
@@ -182,29 +191,35 @@ lpfc_work_list_done(struct lpfc_hba * phba)
                                *(int *)(evtp->evt_arg1)  = 0;
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
-               case LPFC_EVT_OFFLINE:
+               case LPFC_EVT_OFFLINE_PREP:
                        if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                               lpfc_offline_prep(phba);
+                       *(int *)(evtp->evt_arg1) = 0;
+                       complete((struct completion *)(evtp->evt_arg2));
+                       break;
+               case LPFC_EVT_OFFLINE:
+                       lpfc_offline(phba);
                        lpfc_sli_brdrestart(phba);
                        *(int *)(evtp->evt_arg1) =
-                               lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY);
+                               lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                case LPFC_EVT_WARM_START:
-                       if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                       lpfc_offline(phba);
                        lpfc_reset_barrier(phba);
                        lpfc_sli_brdreset(phba);
                        lpfc_hba_down_post(phba);
                        *(int *)(evtp->evt_arg1) =
                                lpfc_sli_brdready(phba, HS_MBRDY);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                case LPFC_EVT_KILL:
-                       if (phba->hba_state >= LPFC_LINK_DOWN)
-                               lpfc_offline(phba);
+                       lpfc_offline(phba);
                        *(int *)(evtp->evt_arg1)
                                = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+                       lpfc_unblock_mgmt_io(phba);
                        complete((struct completion *)(evtp->evt_arg2));
                        break;
                }
@@ -359,13 +374,12 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
 }
 
 int
-lpfc_linkdown(struct lpfc_hba * phba)
+lpfc_linkdown(struct lpfc_hba *phba)
 {
        struct lpfc_sli       *psli;
        struct lpfc_nodelist  *ndlp, *next_ndlp;
-       struct list_head *listp, *node_list[7];
-       LPFC_MBOXQ_t     *mb;
-       int               rc, i;
+       LPFC_MBOXQ_t          *mb;
+       int                   rc;
 
        psli = &phba->sli;
        /* sysfs or selective reset may call this routine to clean up */
@@ -397,31 +411,16 @@ lpfc_linkdown(struct lpfc_hba * phba)
        /* Cleanup any outstanding ELS commands */
        lpfc_els_flush_cmd(phba);
 
-       /* Issue a LINK DOWN event to all nodes */
-       node_list[0] = &phba->fc_npr_list;  /* MUST do this list first */
-       node_list[1] = &phba->fc_nlpmap_list;
-       node_list[2] = &phba->fc_nlpunmap_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_reglogin_list;
-       node_list[5] = &phba->fc_adisc_list;
-       node_list[6] = &phba->fc_plogi_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-
+       /*
+        * Issue a LINK DOWN event to all nodes.
+        */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+                               /* free any ndlp's on unused list */
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                       lpfc_drop_node(phba, ndlp);
+               else            /* otherwise, force node recovery. */
                        rc = lpfc_disc_state_machine(phba, ndlp, NULL,
-                                            NLP_EVT_DEVICE_RECOVERY);
-
-               }
-       }
-
-       /* free any ndlp's on unused list */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                                                    NLP_EVT_DEVICE_RECOVERY);
        }
 
        /* Setup myDID for link up if we are in pt2pt mode */
@@ -452,11 +451,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
 }
 
 static int
-lpfc_linkup(struct lpfc_hba * phba)
+lpfc_linkup(struct lpfc_hba *phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
-       struct list_head *listp, *node_list[7];
-       int i;
 
        fc_host_post_event(phba->host, fc_get_event_number(),
                        FCH_EVT_LINKUP, 0);
@@ -470,29 +467,20 @@ lpfc_linkup(struct lpfc_hba * phba)
        spin_unlock_irq(phba->host->host_lock);
 
 
-       node_list[0] = &phba->fc_plogi_list;
-       node_list[1] = &phba->fc_adisc_list;
-       node_list[2] = &phba->fc_reglogin_list;
-       node_list[3] = &phba->fc_prli_list;
-       node_list[4] = &phba->fc_nlpunmap_list;
-       node_list[5] = &phba->fc_nlpmap_list;
-       node_list[6] = &phba->fc_npr_list;
-       for (i = 0; i < 7; i++) {
-               listp = node_list[i];
-               if (list_empty(listp))
-                       continue;
-
-               list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-                       if (phba->fc_flag & FC_LBIT) {
+       if (phba->fc_flag & FC_LBIT) {
+               list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
                                if (ndlp->nlp_type & NLP_FABRIC) {
-                                       /* On Linkup its safe to clean up the
+                                       /*
+                                        * On Linkup its safe to clean up the
                                         * ndlp from Fabric connections.
                                         */
-                                       lpfc_nlp_list(phba, ndlp,
-                                                       NLP_UNUSED_LIST);
+                                       lpfc_nlp_set_state(phba, ndlp,
+                                                          NLP_STE_UNUSED_NODE);
                                } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
-                                       /* Fail outstanding IO now since device
-                                        * is marked for PLOGI.
+                                       /*
+                                        * Fail outstanding IO now since
+                                        * device is marked for PLOGI.
                                         */
                                        lpfc_unreg_rpi(phba, ndlp);
                                }
@@ -501,9 +489,10 @@ lpfc_linkup(struct lpfc_hba * phba)
        }
 
        /* free any ndlp's on unused list */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+                       lpfc_drop_node(phba, ndlp);
        }
 
        return 0;
@@ -734,6 +723,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                case LA_4GHZ_LINK:
                        phba->fc_linkspeed = LA_4GHZ_LINK;
                        break;
+               case LA_8GHZ_LINK:
+                       phba->fc_linkspeed = LA_8GHZ_LINK;
+                       break;
                default:
                        phba->fc_linkspeed = LA_UNKNW_LINK;
                        break;
@@ -889,12 +881,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        if (la->attType == AT_LINK_UP) {
                phba->fc_stat.LinkUp++;
-               lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+               if (phba->fc_flag & FC_LOOPBACK_MODE) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
+                               "%d:1306 Link Up Event in loop back mode "
+                               "x%x received Data: x%x x%x x%x x%x\n",
+                               phba->brd_no, la->eventTag, phba->fc_eventTag,
+                               la->granted_AL_PA, la->UlnkSpeed,
+                               phba->alpa_map[0]);
+               } else {
+                       lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
                                "%d:1303 Link Up Event x%x received "
                                "Data: x%x x%x x%x x%x\n",
                                phba->brd_no, la->eventTag, phba->fc_eventTag,
                                la->granted_AL_PA, la->UlnkSpeed,
                                phba->alpa_map[0]);
+               }
                lpfc_mbx_process_link_up(phba, la);
        } else {
                phba->fc_stat.LinkDown++;
@@ -940,6 +941,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free( pmb, phba->mbox_mem_pool);
+       lpfc_nlp_put(ndlp);
 
        return;
 }
@@ -966,11 +968,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        ndlp = (struct lpfc_nodelist *) pmb->context2;
        mp = (struct lpfc_dmabuf *) (pmb->context1);
 
+       pmb->context1 = NULL;
+       pmb->context2 = NULL;
+
        if (mb->mbxStatus) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
-               mempool_free( pmb, phba->mbox_mem_pool);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+               mempool_free(pmb, phba->mbox_mem_pool);
+               lpfc_nlp_put(ndlp);
 
                /* FLOGI failed, so just use loop map to make discovery list */
                lpfc_disc_list_loopmap(phba);
@@ -980,12 +985,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                return;
        }
 
-       pmb->context1 = NULL;
-
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+
+       lpfc_nlp_put(ndlp);     /* Drop the reference from the mbox */
 
        if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
                /* This NPort has been assigned an NPort_ID by the fabric as a
@@ -996,7 +1000,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                 */
                lpfc_issue_els_scr(phba, SCR_DID, 0);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (!ndlp) {
                        /* Allocate a new node instance. If the pool is empty,
                         * start the discovery process and skip the Nameserver
@@ -1008,15 +1012,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                                lpfc_disc_start(phba);
                                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
-                               mempool_free( pmb, phba->mbox_mem_pool);
+                               mempool_free(pmb, phba->mbox_mem_pool);
                                return;
                        } else {
                                lpfc_nlp_init(phba, ndlp, NameServer_DID);
                                ndlp->nlp_type |= NLP_FABRIC;
                        }
                }
-               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                if (phba->cfg_fdmi_on) {
                        ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
@@ -1032,7 +1035,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
        return;
 }
 
@@ -1057,10 +1060,11 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        mp = (struct lpfc_dmabuf *) (pmb->context1);
 
        if (mb->mbxStatus) {
+               lpfc_nlp_put(ndlp);
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
-               mempool_free( pmb, phba->mbox_mem_pool);
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               mempool_free(pmb, phba->mbox_mem_pool);
+               lpfc_drop_node(phba, ndlp);
 
                /* RegLogin failed, so just use loop map to make discovery
                   list */
@@ -1075,8 +1079,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
        if (phba->hba_state < LPFC_HBA_READY) {
                /* Link up discovery requires Fabrib registration. */
@@ -1093,6 +1096,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                lpfc_disc_start(phba);
        }
 
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
        mempool_free( pmb, phba->mbox_mem_pool);
@@ -1101,8 +1105,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 }
 
 static void
-lpfc_register_remote_port(struct lpfc_hba * phba,
-                           struct lpfc_nodelist * ndlp)
+lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct fc_rport *rport;
        struct lpfc_rport_data *rdata;
@@ -1114,8 +1117,19 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
        rport_ids.port_id = ndlp->nlp_DID;
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
+       /*
+        * We leave our node pointer in rport->dd_data when we unregister a
+        * FCP target port.  But fc_remote_port_add zeros the space to which
+        * rport->dd_data points.  So, if we're reusing a previously
+        * registered port, drop the reference that we took the last time we
+        * registered the port.
+        */
+       if (ndlp->rport && ndlp->rport->dd_data &&
+           *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+               lpfc_nlp_put(ndlp);
+       }
        ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
-       if (!rport) {
+       if (!rport || !get_device(&rport->dev)) {
                dev_printk(KERN_WARNING, &phba->pcidev->dev,
                           "Warning: fc_remote_port_add failed\n");
                return;
@@ -1125,7 +1139,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
        rport->maxframe_size = ndlp->nlp_maxframe;
        rport->supported_classes = ndlp->nlp_class_sup;
        rdata = rport->dd_data;
-       rdata->pnode = ndlp;
+       rdata->pnode = lpfc_nlp_get(ndlp);
 
        if (ndlp->nlp_type & NLP_FCP_TARGET)
                rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
@@ -1145,8 +1159,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
 }
 
 static void
-lpfc_unregister_remote_port(struct lpfc_hba * phba,
-                           struct lpfc_nodelist * ndlp)
+lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct fc_rport *rport = ndlp->rport;
        struct lpfc_rport_data *rdata = rport->dd_data;
@@ -1154,6 +1167,8 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
        if (rport->scsi_target_id == -1) {
                ndlp->rport = NULL;
                rdata->pnode = NULL;
+               lpfc_nlp_put(ndlp);
+               put_device(&rport->dev);
        }
 
        fc_remote_port_delete(rport);
@@ -1161,178 +1176,70 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
        return;
 }
 
-int
-lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
+static void
+lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
 {
-       enum { none, unmapped, mapped } rport_add = none, rport_del = none;
-       struct lpfc_sli      *psli;
-
-       psli = &phba->sli;
-       /* Sanity check to ensure we are not moving to / from the same list */
-       if ((nlp->nlp_flag & NLP_LIST_MASK) == list)
-               if (list != NLP_NO_LIST)
-                       return 0;
-
        spin_lock_irq(phba->host->host_lock);
-       switch (nlp->nlp_flag & NLP_LIST_MASK) {
-       case NLP_NO_LIST: /* Not on any list */
+       switch (state) {
+       case NLP_STE_UNUSED_NODE:
+               phba->fc_unused_cnt += count;
                break;
-       case NLP_UNUSED_LIST:
-               phba->fc_unused_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_PLOGI_ISSUE:
+               phba->fc_plogi_cnt += count;
                break;
-       case NLP_PLOGI_LIST:
-               phba->fc_plogi_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_ADISC_ISSUE:
+               phba->fc_adisc_cnt += count;
                break;
-       case NLP_ADISC_LIST:
-               phba->fc_adisc_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_REG_LOGIN_ISSUE:
+               phba->fc_reglogin_cnt += count;
                break;
-       case NLP_REGLOGIN_LIST:
-               phba->fc_reglogin_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_PRLI_ISSUE:
+               phba->fc_prli_cnt += count;
                break;
-       case NLP_PRLI_LIST:
-               phba->fc_prli_cnt--;
-               list_del(&nlp->nlp_listp);
+       case NLP_STE_UNMAPPED_NODE:
+               phba->fc_unmap_cnt += count;
                break;
-       case NLP_UNMAPPED_LIST:
-               phba->fc_unmap_cnt--;
-               list_del(&nlp->nlp_listp);
-               nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
-               nlp->nlp_type &= ~NLP_FC_NODE;
-               phba->nport_event_cnt++;
-               if (nlp->rport)
-                       rport_del = unmapped;
+       case NLP_STE_MAPPED_NODE:
+               phba->fc_map_cnt += count;
                break;
-       case NLP_MAPPED_LIST:
-               phba->fc_map_cnt--;
-               list_del(&nlp->nlp_listp);
-               phba->nport_event_cnt++;
-               if (nlp->rport)
-                       rport_del = mapped;
-               break;
-       case NLP_NPR_LIST:
-               phba->fc_npr_cnt--;
-               list_del(&nlp->nlp_listp);
-               /* Stop delay tmo if taking node off NPR list */
-               if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
-                  (list != NLP_NPR_LIST)) {
-                       spin_unlock_irq(phba->host->host_lock);
-                       lpfc_cancel_retry_delay_tmo(phba, nlp);
-                       spin_lock_irq(phba->host->host_lock);
-               }
+       case NLP_STE_NPR_NODE:
+               phba->fc_npr_cnt += count;
                break;
        }
+       spin_unlock_irq(phba->host->host_lock);
+}
 
-       nlp->nlp_flag &= ~NLP_LIST_MASK;
-
-       /* Add NPort <did> to <num> list */
-       lpfc_printf_log(phba,
-                       KERN_INFO,
-                       LOG_NODE,
-                       "%d:0904 Add NPort x%x to %d list Data: x%x\n",
-                       phba->brd_no,
-                       nlp->nlp_DID, list, nlp->nlp_flag);
-
-       switch (list) {
-       case NLP_NO_LIST: /* No list, just remove it */
-               spin_unlock_irq(phba->host->host_lock);
-               lpfc_nlp_remove(phba, nlp);
-               spin_lock_irq(phba->host->host_lock);
-               /* as node removed - stop further transport calls */
-               rport_del = none;
-               break;
-       case NLP_UNUSED_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the unused list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list);
-               phba->fc_unused_cnt++;
-               break;
-       case NLP_PLOGI_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the plogi list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list);
-               phba->fc_plogi_cnt++;
-               break;
-       case NLP_ADISC_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the adisc list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list);
-               phba->fc_adisc_cnt++;
-               break;
-       case NLP_REGLOGIN_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the reglogin list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list);
-               phba->fc_reglogin_cnt++;
-               break;
-       case NLP_PRLI_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the prli list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list);
-               phba->fc_prli_cnt++;
-               break;
-       case NLP_UNMAPPED_LIST:
-               rport_add = unmapped;
-               /* ensure all vestiges of "mapped" significance are gone */
-               nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the unmap list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
-               phba->fc_unmap_cnt++;
-               phba->nport_event_cnt++;
-               nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-               nlp->nlp_type |= NLP_FC_NODE;
-               break;
-       case NLP_MAPPED_LIST:
-               rport_add = mapped;
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the map list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
-               phba->fc_map_cnt++;
+static void
+lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+                      int old_state, int new_state)
+{
+       if (new_state == NLP_STE_UNMAPPED_NODE) {
+               ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+               ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+               ndlp->nlp_type |= NLP_FC_NODE;
+       }
+       if (new_state == NLP_STE_MAPPED_NODE)
+               ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+       if (new_state == NLP_STE_NPR_NODE)
+               ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
+
+       /* Transport interface */
+       if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
+                           old_state == NLP_STE_UNMAPPED_NODE)) {
                phba->nport_event_cnt++;
-               nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
-               break;
-       case NLP_NPR_LIST:
-               nlp->nlp_flag |= list;
-               /* Put it at the end of the npr list */
-               list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
-               phba->fc_npr_cnt++;
-
-               nlp->nlp_flag &= ~NLP_RCV_PLOGI;
-               break;
-       case NLP_JUST_DQ:
-               break;
+               lpfc_unregister_remote_port(phba, ndlp);
        }
 
-       spin_unlock_irq(phba->host->host_lock);
-
-       /*
-        * We make all the calls into the transport after we have
-        * moved the node between lists. This so that we don't
-        * release the lock while in-between lists.
-        */
-
-       /* Don't upcall midlayer if we're unloading */
-       if (!(phba->fc_flag & FC_UNLOADING)) {
-               /*
-                * We revalidate the rport pointer as the "add" function
-                * may have removed the remote port.
-                */
-               if ((rport_del != none) && nlp->rport)
-                       lpfc_unregister_remote_port(phba, nlp);
-
-               if (rport_add != none) {
+       if (new_state ==  NLP_STE_MAPPED_NODE ||
+           new_state == NLP_STE_UNMAPPED_NODE) {
+               phba->nport_event_cnt++;
                        /*
                         * Tell the fc transport about the port, if we haven't
                         * already. If we have, and it's a scsi entity, be
                         * sure to unblock any attached scsi devices
                         */
-                       if ((!nlp->rport) || (nlp->rport->port_state ==
-                                       FC_PORTSTATE_BLOCKED))
-                               lpfc_register_remote_port(phba, nlp);
+                       lpfc_register_remote_port(phba, ndlp);
+       }
 
                        /*
                         * if we added to Mapped list, but the remote port
@@ -1340,19 +1247,95 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
                         * our presentable range - move the node to the
                         * Unmapped List
                         */
-                       if ((rport_add == mapped) &&
-                           ((!nlp->rport) ||
-                            (nlp->rport->scsi_target_id == -1) ||
-                            (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
-                               nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-                               spin_lock_irq(phba->host->host_lock);
-                               nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
-                               spin_unlock_irq(phba->host->host_lock);
-                               lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST);
-                       }
-               }
+       if (new_state == NLP_STE_MAPPED_NODE &&
+           (!ndlp->rport ||
+            ndlp->rport->scsi_target_id == -1 ||
+            ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
+               spin_lock_irq(phba->host->host_lock);
+               ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
+               spin_unlock_irq(phba->host->host_lock);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
        }
-       return 0;
+}
+
+static char *
+lpfc_nlp_state_name(char *buffer, size_t size, int state)
+{
+       static char *states[] = {
+               [NLP_STE_UNUSED_NODE] = "UNUSED",
+               [NLP_STE_PLOGI_ISSUE] = "PLOGI",
+               [NLP_STE_ADISC_ISSUE] = "ADISC",
+               [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN",
+               [NLP_STE_PRLI_ISSUE] = "PRLI",
+               [NLP_STE_UNMAPPED_NODE] = "UNMAPPED",
+               [NLP_STE_MAPPED_NODE] = "MAPPED",
+               [NLP_STE_NPR_NODE] = "NPR",
+       };
+
+       if (state < ARRAY_SIZE(states) && states[state])
+               strlcpy(buffer, states[state], size);
+       else
+               snprintf(buffer, size, "unknown (%d)", state);
+       return buffer;
+}
+
+void
+lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+{
+       int  old_state = ndlp->nlp_state;
+       char name1[16], name2[16];
+
+       lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+                       "%d:0904 NPort state transition x%06x, %s -> %s\n",
+                       phba->brd_no,
+                       ndlp->nlp_DID,
+                       lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+                       lpfc_nlp_state_name(name2, sizeof(name2), state));
+       if (old_state == NLP_STE_NPR_NODE &&
+           (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
+           state != NLP_STE_NPR_NODE)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (old_state == NLP_STE_UNMAPPED_NODE) {
+               ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
+               ndlp->nlp_type &= ~NLP_FC_NODE;
+       }
+
+       if (list_empty(&ndlp->nlp_listp)) {
+               spin_lock_irq(phba->host->host_lock);
+               list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
+               spin_unlock_irq(phba->host->host_lock);
+       } else if (old_state)
+               lpfc_nlp_counters(phba, old_state, -1);
+
+       ndlp->nlp_state = state;
+       lpfc_nlp_counters(phba, state, 1);
+       lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+}
+
+void
+lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+       if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+               lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+       spin_lock_irq(phba->host->host_lock);
+       list_del_init(&ndlp->nlp_listp);
+       spin_unlock_irq(phba->host->host_lock);
+       lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+}
+
+void
+lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+       if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+               lpfc_cancel_retry_delay_tmo(phba, ndlp);
+       if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+               lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+       spin_lock_irq(phba->host->host_lock);
+       list_del_init(&ndlp->nlp_listp);
+       spin_unlock_irq(phba->host->host_lock);
+       lpfc_nlp_put(ndlp);
 }
 
 /*
@@ -1464,6 +1447,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
 static int
 lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *iocb, *next_iocb;
@@ -1492,29 +1476,29 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                                     (phba, pring, iocb, ndlp))) {
                                        /* It matches, so deque and call compl
                                           with an error */
-                                       list_del(&iocb->list);
+                                       list_move_tail(&iocb->list,
+                                                      &completions);
                                        pring->txq_cnt--;
-                                       if (iocb->iocb_cmpl) {
-                                               icmd = &iocb->iocb;
-                                               icmd->ulpStatus =
-                                                   IOSTAT_LOCAL_REJECT;
-                                               icmd->un.ulpWord[4] =
-                                                   IOERR_SLI_ABORTED;
-                                               spin_unlock_irq(phba->host->
-                                                               host_lock);
-                                               (iocb->iocb_cmpl) (phba,
-                                                                  iocb, iocb);
-                                               spin_lock_irq(phba->host->
-                                                             host_lock);
-                                       } else
-                                               lpfc_sli_release_iocbq(phba,
-                                                                      iocb);
                                }
                        }
                        spin_unlock_irq(phba->host->host_lock);
 
                }
        }
+
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               list_del(&iocb->list);
+
+               if (iocb->iocb_cmpl) {
+                       icmd = &iocb->iocb;
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
+       }
+
        return 0;
 }
 
@@ -1554,7 +1538,7 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
  * so it can be freed.
  */
 static int
-lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
        LPFC_MBOXQ_t       *mb;
        LPFC_MBOXQ_t       *nextmb;
@@ -1567,17 +1551,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                        phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
                        ndlp->nlp_state, ndlp->nlp_rpi);
 
-       lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
-
-       /*
-        * if unloading the driver - just leave the remote port in place.
-        * The driver unload will force the attached devices to detach
-        * and flush cache's w/o generating flush errors.
-        */
-       if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
-               lpfc_unregister_remote_port(phba, ndlp);
-               ndlp->nlp_sid = NLP_NO_SID;
-       }
+       lpfc_dequeue_node(phba, ndlp);
 
        /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
        if ((mb = phba->sli.mbox_active)) {
@@ -1599,11 +1573,12 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                        }
                        list_del(&mb->list);
                        mempool_free(mb, phba->mbox_mem_pool);
+                       lpfc_nlp_put(ndlp);
                }
        }
        spin_unlock_irq(phba->host->host_lock);
 
-       lpfc_els_abort(phba,ndlp,0);
+       lpfc_els_abort(phba,ndlp);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~NLP_DELAY_TMO;
        spin_unlock_irq(phba->host->host_lock);
@@ -1624,27 +1599,27 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
  * If we are in the middle of using the nlp in the discovery state
  * machine, defer the free till we reach the end of the state machine.
  */
-int
-lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+static void
+lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
+       struct lpfc_rport_data *rdata;
 
        if (ndlp->nlp_flag & NLP_DELAY_TMO) {
                lpfc_cancel_retry_delay_tmo(phba, ndlp);
        }
 
-       if (ndlp->nlp_disc_refcnt) {
-               spin_lock_irq(phba->host->host_lock);
-               ndlp->nlp_flag |= NLP_DELAY_REMOVE;
-               spin_unlock_irq(phba->host->host_lock);
-       } else {
-               lpfc_freenode(phba, ndlp);
-               mempool_free( ndlp, phba->nlp_mem_pool);
+       lpfc_cleanup_node(phba, ndlp);
+
+       if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
+               put_device(&ndlp->rport->dev);
+               rdata = ndlp->rport->dd_data;
+               rdata->pnode = NULL;
+               ndlp->rport = NULL;
        }
-       return 0;
 }
 
 static int
-lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
        D_ID mydid;
        D_ID ndlpdid;
@@ -1693,57 +1668,36 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
        return 0;
 }
 
-/* Search for a nodelist entry on a specific list */
+/* Search for a nodelist entry */
 struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
+lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head *lists[]={&phba->fc_nlpunmap_list,
-                                  &phba->fc_nlpmap_list,
-                                  &phba->fc_plogi_list,
-                                  &phba->fc_adisc_list,
-                                  &phba->fc_reglogin_list,
-                                  &phba->fc_prli_list,
-                                  &phba->fc_npr_list,
-                                  &phba->fc_unused_list};
-       uint32_t search[]={NLP_SEARCH_UNMAPPED,
-                          NLP_SEARCH_MAPPED,
-                          NLP_SEARCH_PLOGI,
-                          NLP_SEARCH_ADISC,
-                          NLP_SEARCH_REGLOGIN,
-                          NLP_SEARCH_PRLI,
-                          NLP_SEARCH_NPR,
-                          NLP_SEARCH_UNUSED};
-       int i;
        uint32_t data1;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-               if (!(order & search[i]))
-                       continue;
-               list_for_each_entry(ndlp, lists[i], nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0929 FIND node DID "
-                                               " Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (lpfc_matchdid(phba, ndlp, did)) {
+                       data1 = (((uint32_t) ndlp->nlp_state << 24) |
+                                ((uint32_t) ndlp->nlp_xri << 16) |
+                                ((uint32_t) ndlp->nlp_type << 8) |
+                                ((uint32_t) ndlp->nlp_rpi & 0xff));
+                       lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+                                       "%d:0929 FIND node DID "
+                                       " Data: x%p x%x x%x x%x\n",
+                                       phba->brd_no,
+                                       ndlp, ndlp->nlp_DID,
+                                       ndlp->nlp_flag, data1);
+                       spin_unlock_irq(phba->host->host_lock);
+                       return ndlp;
                }
        }
        spin_unlock_irq(phba->host->host_lock);
 
        /* FIND node did <did> NOT FOUND */
        lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                       "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
-                       phba->brd_no, did, order);
+                       "%d:0932 FIND node did x%x NOT FOUND.\n",
+                       phba->brd_no, did);
        return NULL;
 }
 
@@ -1751,9 +1705,8 @@ struct lpfc_nodelist *
 lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
 {
        struct lpfc_nodelist *ndlp;
-       uint32_t flg;
 
-       ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+       ndlp = lpfc_findnode_did(phba, did);
        if (!ndlp) {
                if ((phba->fc_flag & FC_RSCN_MODE) &&
                   ((lpfc_rscn_payload_check(phba, did) == 0)))
@@ -1763,8 +1716,7 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
                if (!ndlp)
                        return NULL;
                lpfc_nlp_init(phba, ndlp, did);
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
                return ndlp;
        }
@@ -1780,11 +1732,10 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
                } else
                        ndlp = NULL;
        } else {
-               flg = ndlp->nlp_flag & NLP_LIST_MASK;
-               if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST))
+               if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
+                   ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
                        return NULL;
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                ndlp->nlp_flag |= NLP_NPR_2B_DISC;
        }
        return ndlp;
@@ -1842,8 +1793,9 @@ lpfc_disc_start(struct lpfc_hba * phba)
        struct lpfc_sli *psli;
        LPFC_MBOXQ_t *mbox;
        struct lpfc_nodelist *ndlp, *next_ndlp;
-       uint32_t did_changed, num_sent;
+       uint32_t num_sent;
        uint32_t clear_la_pending;
+       int did_changed;
        int rc;
 
        psli = &phba->sli;
@@ -1877,14 +1829,13 @@ lpfc_disc_start(struct lpfc_hba * phba)
                        phba->fc_plogi_cnt, phba->fc_adisc_cnt);
 
        /* If our did changed, we MUST do PLOGI */
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
-                       if (did_changed) {
-                               spin_lock_irq(phba->host->host_lock);
-                               ndlp->nlp_flag &= ~NLP_NPR_ADISC;
-                               spin_unlock_irq(phba->host->host_lock);
-                       }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+                   (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+                   did_changed) {
+                       spin_lock_irq(phba->host->host_lock);
+                       ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+                       spin_unlock_irq(phba->host->host_lock);
                }
        }
 
@@ -1944,11 +1895,11 @@ lpfc_disc_start(struct lpfc_hba * phba)
 static void
 lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        IOCB_t     *icmd;
        struct lpfc_iocbq    *iocb, *next_iocb;
        struct lpfc_sli_ring *pring;
-       struct lpfc_dmabuf   *mp;
 
        psli = &phba->sli;
        pring = &psli->ring[LPFC_ELS_RING];
@@ -1956,6 +1907,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
        /* Error matching iocb on txq or txcmplq
         * First check the txq.
         */
+       spin_lock_irq(phba->host->host_lock);
        list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
                if (iocb->context1 != ndlp) {
                        continue;
@@ -1964,9 +1916,8 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
                    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
 
-                       list_del(&iocb->list);
+                       list_move_tail(&iocb->list, &completions);
                        pring->txq_cnt--;
-                       lpfc_els_free_iocb(phba, iocb);
                }
        }
 
@@ -1978,43 +1929,22 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
                icmd = &iocb->iocb;
                if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
                    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+                       lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+               }
+       }
+       spin_unlock_irq(phba->host->host_lock);
 
-                       iocb->iocb_cmpl = NULL;
-                       /* context2 = cmd, context2->next = rsp, context3 =
-                          bpl */
-                       if (iocb->context2) {
-                               /* Free the response IOCB before handling the
-                                  command. */
-
-                               mp = (struct lpfc_dmabuf *) (iocb->context2);
-                               mp = list_get_first(&mp->list,
-                                                   struct lpfc_dmabuf,
-                                                   list);
-                               if (mp) {
-                                       /* Delay before releasing rsp buffer to
-                                        * give UNREG mbox a chance to take
-                                        * effect.
-                                        */
-                                       list_add(&mp->list,
-                                               &phba->freebufList);
-                               }
-                               lpfc_mbuf_free(phba,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context2)->virt,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context2)->phys);
-                               kfree(iocb->context2);
-                       }
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               list_del(&iocb->list);
 
-                       if (iocb->context3) {
-                               lpfc_mbuf_free(phba,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context3)->virt,
-                                              ((struct lpfc_dmabuf *)
-                                               iocb->context3)->phys);
-                               kfree(iocb->context3);
-                       }
-               }
+               if (iocb->iocb_cmpl) {
+                       icmd = &iocb->iocb;
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
 
        return;
@@ -2025,21 +1955,16 @@ lpfc_disc_flush_list(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
-       if (phba->fc_plogi_cnt) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                                       nlp_listp) {
-                       lpfc_free_tx(phba, ndlp);
-                       lpfc_nlp_remove(phba, ndlp);
-               }
-       }
-       if (phba->fc_adisc_cnt) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                                       nlp_listp) {
-                       lpfc_free_tx(phba, ndlp);
-                       lpfc_nlp_remove(phba, ndlp);
+       if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+                           ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
+                               lpfc_free_tx(phba, ndlp);
+                               lpfc_nlp_put(ndlp);
+                       }
                }
        }
-       return;
 }
 
 /*****************************************************************************/
@@ -2108,11 +2033,13 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                 phba->brd_no);
 
                /* Start discovery by sending FLOGI, clean up old rpis */
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                                       nlp_listp) {
+               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+                                        nlp_listp) {
+                       if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+                               continue;
                        if (ndlp->nlp_type & NLP_FABRIC) {
                                /* Clean up the ndlp on Fabric connections */
-                               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                               lpfc_drop_node(phba, ndlp);
                        } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
                                /* Fail outstanding IO now since device
                                 * is marked for PLOGI.
@@ -2153,9 +2080,9 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                "login\n", phba->brd_no);
 
                /* Next look for NameServer ndlp */
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
                if (ndlp)
-                       lpfc_nlp_remove(phba, ndlp);
+                       lpfc_nlp_put(ndlp);
                /* Start discovery */
                lpfc_disc_start(phba);
                break;
@@ -2168,9 +2095,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                                phba->brd_no,
                                phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
 
-               ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
-                                                               NameServer_DID);
-               if (ndlp) {
+               ndlp = lpfc_findnode_did(phba, NameServer_DID);
+               if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
                        if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
                                /* Try it one more time */
                                rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
@@ -2220,6 +2146,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
                initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
                rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
                                         (MBX_NOWAIT | MBX_STOP_IOCB));
+               lpfc_set_loopback_flag(phba);
                if (rc == MBX_NOT_FINISHED)
                        mempool_free(initlinkmbox, phba->mbox_mem_pool);
 
@@ -2317,8 +2244,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        ndlp->nlp_rpi = mb->un.varWords[0];
        ndlp->nlp_type |= NLP_FABRIC;
-       ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
 
        /* Start issuing Fabric-Device Management Interface (FDMI)
         * command to 0xfffffa (FDMI well known port)
@@ -2333,87 +2259,100 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
        }
 
+                               /* Mailbox took a reference to the node */
+       lpfc_nlp_put(ndlp);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
        kfree(mp);
-       mempool_free( pmb, phba->mbox_mem_pool);
+       mempool_free(pmb, phba->mbox_mem_pool);
 
        return;
 }
 
+static int
+lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
+{
+       uint16_t *rpi = param;
+
+       return ndlp->nlp_rpi == *rpi;
+}
+
+static int
+lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
+{
+       return memcmp(&ndlp->nlp_portname, param,
+                     sizeof(ndlp->nlp_portname)) == 0;
+}
+
+/*
+ * Search node lists for a remote port matching filter criteria
+ * Caller needs to hold host_lock before calling this routine.
+ */
+struct lpfc_nodelist *
+__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+       struct lpfc_nodelist *ndlp;
+
+       list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
+                   filter(ndlp, param))
+                       return ndlp;
+       }
+       return NULL;
+}
+
 /*
- * This routine looks up the ndlp  lists
- * for the given RPI. If rpi found
- * it return the node list pointer
- * else return NULL.
+ * Search node lists for a remote port matching filter criteria
+ * This routine is used when the caller does NOT have host_lock.
  */
+struct lpfc_nodelist *
+lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+       struct lpfc_nodelist *ndlp;
+
+       spin_lock_irq(phba->host->host_lock);
+       ndlp = __lpfc_find_node(phba, filter, param);
+       spin_unlock_irq(phba->host->host_lock);
+       return ndlp;
+}
+
+/*
+ * This routine looks up the ndlp lists for the given RPI. If rpi found it
+ * returns the node list pointer else return NULL.
+ */
+struct lpfc_nodelist *
+__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+{
+       return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+}
+
 struct lpfc_nodelist *
 lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head * lists[]={&phba->fc_nlpunmap_list,
-                                   &phba->fc_nlpmap_list,
-                                   &phba->fc_plogi_list,
-                                   &phba->fc_adisc_list,
-                                   &phba->fc_reglogin_list};
-       int i;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ )
-               list_for_each_entry(ndlp, lists[i], nlp_listp)
-                       if (ndlp->nlp_rpi == rpi) {
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
+       ndlp = __lpfc_findnode_rpi(phba, rpi);
        spin_unlock_irq(phba->host->host_lock);
-       return NULL;
+       return ndlp;
 }
 
 /*
- * This routine looks up the ndlp  lists
- * for the given WWPN. If WWPN found
- * it return the node list pointer
- * else return NULL.
+ * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
+ * returns the node list pointer else return NULL.
  */
 struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order,
-                  struct lpfc_name * wwpn)
+lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
 {
        struct lpfc_nodelist *ndlp;
-       struct list_head * lists[]={&phba->fc_nlpunmap_list,
-                                   &phba->fc_nlpmap_list,
-                                   &phba->fc_npr_list,
-                                   &phba->fc_plogi_list,
-                                   &phba->fc_adisc_list,
-                                   &phba->fc_reglogin_list,
-                                   &phba->fc_prli_list};
-       uint32_t search[]={NLP_SEARCH_UNMAPPED,
-                          NLP_SEARCH_MAPPED,
-                          NLP_SEARCH_NPR,
-                          NLP_SEARCH_PLOGI,
-                          NLP_SEARCH_ADISC,
-                          NLP_SEARCH_REGLOGIN,
-                          NLP_SEARCH_PRLI};
-       int i;
 
        spin_lock_irq(phba->host->host_lock);
-       for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
-               if (!(order & search[i]))
-                       continue;
-               list_for_each_entry(ndlp, lists[i], nlp_listp) {
-                       if (memcmp(&ndlp->nlp_portname, wwpn,
-                                  sizeof(struct lpfc_name)) == 0) {
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
+       ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
        spin_unlock_irq(phba->host->host_lock);
        return NULL;
 }
 
 void
-lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-                uint32_t did)
+lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
 {
        memset(ndlp, 0, sizeof (struct lpfc_nodelist));
        INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
@@ -2423,5 +2362,30 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        ndlp->nlp_DID = did;
        ndlp->nlp_phba = phba;
        ndlp->nlp_sid = NLP_NO_SID;
+       INIT_LIST_HEAD(&ndlp->nlp_listp);
+       kref_init(&ndlp->kref);
        return;
 }
+
+void
+lpfc_nlp_release(struct kref *kref)
+{
+       struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
+                                                 kref);
+       lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
+       mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+}
+
+struct lpfc_nodelist *
+lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+{
+       if (ndlp)
+               kref_get(&ndlp->kref);
+       return ndlp;
+}
+
+int
+lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+{
+       return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
+}
index f79cb61369065007a88ca4dccb6e50c2bb1ec174..2623a9bc7775f0f4fe8bd5026f8964303ad42ee2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -1078,6 +1078,8 @@ typedef struct {
 /* Start FireFly Register definitions */
 #define PCI_VENDOR_ID_EMULEX        0x10df
 #define PCI_DEVICE_ID_FIREFLY       0x1ae5
+#define PCI_DEVICE_ID_SAT_SMB       0xf011
+#define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_RFLY          0xf095
 #define PCI_DEVICE_ID_PFLY          0xf098
 #define PCI_DEVICE_ID_LP101         0xf0a1
@@ -1089,6 +1091,9 @@ typedef struct {
 #define PCI_DEVICE_ID_NEPTUNE       0xf0f5
 #define PCI_DEVICE_ID_NEPTUNE_SCSP  0xf0f6
 #define PCI_DEVICE_ID_NEPTUNE_DCSP  0xf0f7
+#define PCI_DEVICE_ID_SAT           0xf100
+#define PCI_DEVICE_ID_SAT_SCSP      0xf111
+#define PCI_DEVICE_ID_SAT_DCSP      0xf112
 #define PCI_DEVICE_ID_SUPERFLY      0xf700
 #define PCI_DEVICE_ID_DRAGONFLY     0xf800
 #define PCI_DEVICE_ID_CENTAUR       0xf900
@@ -1098,6 +1103,7 @@ typedef struct {
 #define PCI_DEVICE_ID_LP10000S      0xfc00
 #define PCI_DEVICE_ID_LP11000S      0xfc10
 #define PCI_DEVICE_ID_LPE11000S     0xfc20
+#define PCI_DEVICE_ID_SAT_S         0xfc40
 #define PCI_DEVICE_ID_HELIOS        0xfd00
 #define PCI_DEVICE_ID_HELIOS_SCSP   0xfd11
 #define PCI_DEVICE_ID_HELIOS_DCSP   0xfd12
@@ -1118,6 +1124,7 @@ typedef struct {
 #define HELIOS_JEDEC_ID             0x0364
 #define ZEPHYR_JEDEC_ID             0x0577
 #define VIPER_JEDEC_ID              0x4838
+#define SATURN_JEDEC_ID             0x1004
 
 #define JEDEC_ID_MASK               0x0FFFF000
 #define JEDEC_ID_SHIFT              12
@@ -1565,7 +1572,7 @@ typedef struct {
 #define LINK_SPEED_1G   1       /* 1 Gigabaud */
 #define LINK_SPEED_2G   2       /* 2 Gigabaud */
 #define LINK_SPEED_4G   4       /* 4 Gigabaud */
-#define LINK_SPEED_8G   8       /* 4 Gigabaud */
+#define LINK_SPEED_8G   8       /* 8 Gigabaud */
 #define LINK_SPEED_10G   16      /* 10 Gigabaud */
 
 } INIT_LINK_VAR;
index dcf6106f557a0dac93efb20710dcbf9d1bec7bc7..dcb4ba0ecee1825067b2344562ab0e21d4df0601 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -386,12 +386,12 @@ lpfc_config_port_post(struct lpfc_hba * phba)
         * Setup the ring 0 (els)  timeout handler
         */
        timeout = phba->fc_ratov << 1;
-       phba->els_tmofunc.expires = jiffies + HZ * timeout;
-       add_timer(&phba->els_tmofunc);
+       mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
 
        lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
        pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
        rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+       lpfc_set_loopback_flag(phba);
        if (rc != MBX_SUCCESS) {
                lpfc_printf_log(phba,
                                KERN_ERR,
@@ -418,33 +418,6 @@ lpfc_config_port_post(struct lpfc_hba * phba)
        return (0);
 }
 
-static int
-lpfc_discovery_wait(struct lpfc_hba *phba)
-{
-       int i = 0;
-
-       while ((phba->hba_state != LPFC_HBA_READY) ||
-              (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
-              ((phba->fc_map_cnt == 0) && (i<2)) ||
-              (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
-               /* Check every second for 30 retries. */
-               i++;
-               if (i > 30) {
-                       return -ETIMEDOUT;
-               }
-               if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
-                       /* The link is down.  Set linkdown timeout */
-                       return -ETIMEDOUT;
-               }
-
-               /* Delay for 1 second to give discovery time to complete. */
-               msleep(1000);
-
-       }
-
-       return 0;
-}
-
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_hba_down_prep                                                */
@@ -550,12 +523,15 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
                 * There was a firmware error.  Take the hba offline and then
                 * attempt to restart it.
                 */
+               lpfc_offline_prep(phba);
                lpfc_offline(phba);
                lpfc_sli_brdrestart(phba);
                if (lpfc_online(phba) == 0) {   /* Initialize the HBA */
                        mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+                       lpfc_unblock_mgmt_io(phba);
                        return;
                }
+               lpfc_unblock_mgmt_io(phba);
        } else {
                /* The if clause above forces this code path when the status
                 * failure is a value other than FFER6.  Do not call the offline
@@ -573,7 +549,9 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
                                SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
                psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+               lpfc_offline_prep(phba);
                lpfc_offline(phba);
+               lpfc_unblock_mgmt_io(phba);
                phba->hba_state = LPFC_HBA_ERROR;
                lpfc_hba_down_post(phba);
        }
@@ -633,7 +611,7 @@ lpfc_handle_latt_free_mbuf:
 lpfc_handle_latt_free_mp:
        kfree(mp);
 lpfc_handle_latt_free_pmb:
-       kfree(pmb);
+       mempool_free(pmb, phba->mbox_mem_pool);
 lpfc_handle_latt_err_exit:
        /* Enable Link attention interrupts */
        spin_lock_irq(phba->host->host_lock);
@@ -925,6 +903,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
                m = (typeof(m)){"LPe11000-S", max_speed,
                        "PCIe"};
                break;
+       case PCI_DEVICE_ID_SAT:
+               m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_MID:
+               m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SMB:
+               m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_DCSP:
+               m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_SCSP:
+               m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+               break;
+       case PCI_DEVICE_ID_SAT_S:
+               m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+               break;
        default:
                m = (typeof(m)){ NULL };
                break;
@@ -1174,69 +1170,17 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
 }
 
 static void
-lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind)
+lpfc_cleanup(struct lpfc_hba * phba)
 {
        struct lpfc_nodelist *ndlp, *next_ndlp;
 
        /* clean up phba - lpfc specific */
        lpfc_can_disctmo(phba);
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               lpfc_nlp_put(ndlp);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
-                                nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
-                               nlp_listp) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                               nlp_listp) {
-               lpfc_nlp_remove(phba, ndlp);
-       }
-
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
-       phba->fc_map_cnt   = 0;
-       phba->fc_unmap_cnt = 0;
-       phba->fc_plogi_cnt = 0;
-       phba->fc_adisc_cnt = 0;
-       phba->fc_reglogin_cnt = 0;
-       phba->fc_prli_cnt  = 0;
-       phba->fc_npr_cnt   = 0;
-       phba->fc_unused_cnt= 0;
        return;
 }
 
@@ -1262,21 +1206,6 @@ lpfc_stop_timer(struct lpfc_hba * phba)
 {
        struct lpfc_sli *psli = &phba->sli;
 
-       /* Instead of a timer, this has been converted to a
-        * deferred procedding list.
-        */
-       while (!list_empty(&phba->freebufList)) {
-
-               struct lpfc_dmabuf *mp = NULL;
-
-               list_remove_head((&phba->freebufList), mp,
-                                struct lpfc_dmabuf, list);
-               if (mp) {
-                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
-                       kfree(mp);
-               }
-       }
-
        del_timer_sync(&phba->fcp_poll_timer);
        del_timer_sync(&phba->fc_estabtmo);
        del_timer_sync(&phba->fc_disctmo);
@@ -1302,60 +1231,76 @@ lpfc_online(struct lpfc_hba * phba)
                       "%d:0458 Bring Adapter online\n",
                       phba->brd_no);
 
-       if (!lpfc_sli_queue_setup(phba))
+       lpfc_block_mgmt_io(phba);
+
+       if (!lpfc_sli_queue_setup(phba)) {
+               lpfc_unblock_mgmt_io(phba);
                return 1;
+       }
 
-       if (lpfc_sli_hba_setup(phba))   /* Initialize the HBA */
+       if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */
+               lpfc_unblock_mgmt_io(phba);
                return 1;
+       }
 
        spin_lock_irq(phba->host->host_lock);
        phba->fc_flag &= ~FC_OFFLINE_MODE;
        spin_unlock_irq(phba->host->host_lock);
 
+       lpfc_unblock_mgmt_io(phba);
        return 0;
 }
 
-int
-lpfc_offline(struct lpfc_hba * phba)
+void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
 {
-       struct lpfc_sli_ring *pring;
-       struct lpfc_sli *psli;
        unsigned long iflag;
-       int i;
-       int cnt = 0;
 
-       if (!phba)
-               return 0;
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag |= FC_BLOCK_MGMT_IO;
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+{
+       unsigned long iflag;
+
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_offline_prep(struct lpfc_hba * phba)
+{
+       struct lpfc_nodelist  *ndlp, *next_ndlp;
 
        if (phba->fc_flag & FC_OFFLINE_MODE)
-               return 0;
+               return;
 
-       psli = &phba->sli;
+       lpfc_block_mgmt_io(phba);
 
        lpfc_linkdown(phba);
+
+       /* Issue an unreg_login to all nodes */
+       list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+               if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+                       lpfc_unreg_rpi(phba, ndlp);
+
        lpfc_sli_flush_mbox_queue(phba);
+}
 
-       for (i = 0; i < psli->num_rings; i++) {
-               pring = &psli->ring[i];
-               /* The linkdown event takes 30 seconds to timeout. */
-               while (pring->txcmplq_cnt) {
-                       mdelay(10);
-                       if (cnt++ > 3000) {
-                               lpfc_printf_log(phba,
-                                       KERN_WARNING, LOG_INIT,
-                                       "%d:0466 Outstanding IO when "
-                                       "bringing Adapter offline\n",
-                                       phba->brd_no);
-                               break;
-                       }
-               }
-       }
+void
+lpfc_offline(struct lpfc_hba * phba)
+{
+       unsigned long iflag;
 
+       if (phba->fc_flag & FC_OFFLINE_MODE)
+               return;
 
        /* stop all timers associated with this hba */
        lpfc_stop_timer(phba);
-       phba->work_hba_events = 0;
-       phba->work_ha = 0;
 
        lpfc_printf_log(phba,
                       KERN_WARNING,
@@ -1366,11 +1311,12 @@ lpfc_offline(struct lpfc_hba * phba)
        /* Bring down the SLI Layer and cleanup.  The HBA is offline
           now.  */
        lpfc_sli_hba_down(phba);
-       lpfc_cleanup(phba, 1);
+       lpfc_cleanup(phba);
        spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->work_hba_events = 0;
+       phba->work_ha = 0;
        phba->fc_flag |= FC_OFFLINE_MODE;
        spin_unlock_irqrestore(phba->host->host_lock, iflag);
-       return 0;
 }
 
 /******************************************************************************
@@ -1407,6 +1353,156 @@ lpfc_scsi_free(struct lpfc_hba * phba)
        return 0;
 }
 
+void lpfc_remove_device(struct lpfc_hba *phba)
+{
+       unsigned long iflag;
+
+       lpfc_free_sysfs_attr(phba);
+
+       spin_lock_irqsave(phba->host->host_lock, iflag);
+       phba->fc_flag |= FC_UNLOADING;
+
+       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+       fc_remove_host(phba->host);
+       scsi_remove_host(phba->host);
+
+       kthread_stop(phba->worker_thread);
+
+       /*
+        * Bring down the SLI Layer. This step disable all interrupts,
+        * clears the rings, discards all mailbox commands, and resets
+        * the HBA.
+        */
+       lpfc_sli_hba_down(phba);
+       lpfc_sli_brdrestart(phba);
+
+       /* Release the irq reservation */
+       free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
+
+       lpfc_cleanup(phba);
+       lpfc_stop_timer(phba);
+       phba->work_hba_events = 0;
+
+       /*
+        * Call scsi_free before mem_free since scsi bufs are released to their
+        * corresponding pools here.
+        */
+       lpfc_scsi_free(phba);
+       lpfc_mem_free(phba);
+
+       /* Free resources associated with SLI2 interface */
+       dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
+                         phba->slim2p, phba->slim2p_mapping);
+
+       /* unmap adapter SLIM and Control Registers */
+       iounmap(phba->ctrl_regs_memmap_p);
+       iounmap(phba->slim_memmap_p);
+
+       pci_release_regions(phba->pcidev);
+       pci_disable_device(phba->pcidev);
+
+       idr_remove(&lpfc_hba_index, phba->brd_no);
+       scsi_host_put(phba->host);
+}
+
+void lpfc_scan_start(struct Scsi_Host *host)
+{
+       struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+
+       if (lpfc_alloc_sysfs_attr(phba))
+               goto error;
+
+       phba->MBslimaddr = phba->slim_memmap_p;
+       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+       if (lpfc_sli_hba_setup(phba))
+               goto error;
+
+       /*
+        * hba setup may have changed the hba_queue_depth so we need to adjust
+        * the value of can_queue.
+        */
+       host->can_queue = phba->cfg_hba_queue_depth - 10;
+       return;
+
+error:
+       lpfc_remove_device(phba);
+}
+
+int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+
+       if (!phba->host)
+               return 1;
+       if (time >= 30 * HZ)
+               goto finished;
+
+       if (phba->hba_state != LPFC_HBA_READY)
+               return 0;
+       if (phba->num_disc_nodes || phba->fc_prli_sent)
+               return 0;
+       if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
+               return 0;
+       if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
+               return 0;
+       if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
+               return 0;
+
+finished:
+       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+               spin_lock_irq(shost->host_lock);
+               lpfc_poll_start_timer(phba);
+               spin_unlock_irq(shost->host_lock);
+       }
+
+       /*
+        * set fixed host attributes
+        * Must done after lpfc_sli_hba_setup()
+        */
+
+       fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
+       fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+       fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+       memset(fc_host_supported_fc4s(shost), 0,
+               sizeof(fc_host_supported_fc4s(shost)));
+       fc_host_supported_fc4s(shost)[2] = 1;
+       fc_host_supported_fc4s(shost)[7] = 1;
+
+       lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+
+       fc_host_supported_speeds(shost) = 0;
+       if (phba->lmt & LMT_10Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+       if (phba->lmt & LMT_4Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
+       if (phba->lmt & LMT_2Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT;
+       if (phba->lmt & LMT_1Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
+
+       fc_host_maxframe_size(shost) =
+               ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+                (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+
+       /* This value is also unchanging */
+       memset(fc_host_active_fc4s(shost), 0,
+               sizeof(fc_host_active_fc4s(shost)));
+       fc_host_active_fc4s(shost)[2] = 1;
+       fc_host_active_fc4s(shost)[7] = 1;
+
+       spin_lock_irq(shost->host_lock);
+       phba->fc_flag &= ~FC_LOADING;
+       spin_unlock_irq(shost->host_lock);
+
+       return 1;
+}
 
 static int __devinit
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
@@ -1445,9 +1541,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                goto out_put_host;
 
        host->unique_id = phba->brd_no;
-       INIT_LIST_HEAD(&phba->ctrspbuflist);
-       INIT_LIST_HEAD(&phba->rnidrspbuflist);
-       INIT_LIST_HEAD(&phba->freebufList);
 
        /* Initialize timers used by driver */
        init_timer(&phba->fc_estabtmo);
@@ -1482,16 +1575,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        host->max_lun = phba->cfg_max_luns;
        host->this_id = -1;
 
-       /* Initialize all internally managed lists. */
-       INIT_LIST_HEAD(&phba->fc_nlpmap_list);
-       INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
-       INIT_LIST_HEAD(&phba->fc_unused_list);
-       INIT_LIST_HEAD(&phba->fc_plogi_list);
-       INIT_LIST_HEAD(&phba->fc_adisc_list);
-       INIT_LIST_HEAD(&phba->fc_reglogin_list);
-       INIT_LIST_HEAD(&phba->fc_prli_list);
-       INIT_LIST_HEAD(&phba->fc_npr_list);
-
+       INIT_LIST_HEAD(&phba->fc_nodes);
 
        pci_set_master(pdev);
        retval = pci_set_mwi(pdev);
@@ -1609,13 +1693,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 
        host->transportt = lpfc_transport_template;
        pci_set_drvdata(pdev, host);
-       error = scsi_add_host(host, &pdev->dev);
-       if (error)
-               goto out_kthread_stop;
-
-       error = lpfc_alloc_sysfs_attr(phba);
-       if (error)
-               goto out_remove_host;
 
        if (phba->cfg_use_msi) {
                error = pci_enable_msi(phba->pcidev);
@@ -1631,73 +1708,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "%d:0451 Enable interrupt handler failed\n",
                        phba->brd_no);
-               goto out_free_sysfs_attr;
+               goto out_kthread_stop;
        }
-       phba->MBslimaddr = phba->slim_memmap_p;
-       phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
-       phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
-       phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
-       phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-       error = lpfc_sli_hba_setup(phba);
-       if (error) {
-               error = -ENODEV;
+       error = scsi_add_host(host, &pdev->dev);
+       if (error)
                goto out_free_irq;
-       }
-
-       /*
-        * hba setup may have changed the hba_queue_depth so we need to adjust
-        * the value of can_queue.
-        */
-       host->can_queue = phba->cfg_hba_queue_depth - 10;
-
-       lpfc_discovery_wait(phba);
 
-       if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
-               spin_lock_irq(phba->host->host_lock);
-               lpfc_poll_start_timer(phba);
-               spin_unlock_irq(phba->host->host_lock);
-       }
+       scsi_scan_host(host);
 
-       /*
-        * set fixed host attributes
-        * Must done after lpfc_sli_hba_setup()
-        */
-
-       fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
-       fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
-       fc_host_supported_classes(host) = FC_COS_CLASS3;
-
-       memset(fc_host_supported_fc4s(host), 0,
-               sizeof(fc_host_supported_fc4s(host)));
-       fc_host_supported_fc4s(host)[2] = 1;
-       fc_host_supported_fc4s(host)[7] = 1;
-
-       lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
-
-       fc_host_supported_speeds(host) = 0;
-       if (phba->lmt & LMT_10Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
-       if (phba->lmt & LMT_4Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
-       if (phba->lmt & LMT_2Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
-       if (phba->lmt & LMT_1Gb)
-               fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT;
-
-       fc_host_maxframe_size(host) =
-               ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
-                (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
-
-       /* This value is also unchanging */
-       memset(fc_host_active_fc4s(host), 0,
-               sizeof(fc_host_active_fc4s(host)));
-       fc_host_active_fc4s(host)[2] = 1;
-       fc_host_active_fc4s(host)[7] = 1;
-
-       spin_lock_irq(phba->host->host_lock);
-       phba->fc_flag &= ~FC_LOADING;
-       spin_unlock_irq(phba->host->host_lock);
        return 0;
 
 out_free_irq:
@@ -1705,11 +1724,6 @@ out_free_irq:
        phba->work_hba_events = 0;
        free_irq(phba->pcidev->irq, phba);
        pci_disable_msi(phba->pcidev);
-out_free_sysfs_attr:
-       lpfc_free_sysfs_attr(phba);
-out_remove_host:
-       fc_remove_host(phba->host);
-       scsi_remove_host(phba->host);
 out_kthread_stop:
        kthread_stop(phba->worker_thread);
 out_free_iocbq:
@@ -1747,56 +1761,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host   *host = pci_get_drvdata(pdev);
        struct lpfc_hba    *phba = (struct lpfc_hba *)host->hostdata;
-       unsigned long iflag;
-
-       lpfc_free_sysfs_attr(phba);
-
-       spin_lock_irqsave(phba->host->host_lock, iflag);
-       phba->fc_flag |= FC_UNLOADING;
-
-       spin_unlock_irqrestore(phba->host->host_lock, iflag);
 
-       fc_remove_host(phba->host);
-       scsi_remove_host(phba->host);
-
-       kthread_stop(phba->worker_thread);
-
-       /*
-        * Bring down the SLI Layer. This step disable all interrupts,
-        * clears the rings, discards all mailbox commands, and resets
-        * the HBA.
-        */
-       lpfc_sli_hba_down(phba);
-       lpfc_sli_brdrestart(phba);
-
-       /* Release the irq reservation */
-       free_irq(phba->pcidev->irq, phba);
-       pci_disable_msi(phba->pcidev);
-
-       lpfc_cleanup(phba, 0);
-       lpfc_stop_timer(phba);
-       phba->work_hba_events = 0;
-
-       /*
-        * Call scsi_free before mem_free since scsi bufs are released to their
-        * corresponding pools here.
-        */
-       lpfc_scsi_free(phba);
-       lpfc_mem_free(phba);
-
-       /* Free resources associated with SLI2 interface */
-       dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
-                         phba->slim2p, phba->slim2p_mapping);
-
-       /* unmap adapter SLIM and Control Registers */
-       iounmap(phba->ctrl_regs_memmap_p);
-       iounmap(phba->slim_memmap_p);
-
-       pci_release_regions(phba->pcidev);
-       pci_disable_device(phba->pcidev);
-
-       idr_remove(&lpfc_hba_index, phba->brd_no);
-       scsi_host_put(phba->host);
+       lpfc_remove_device(phba);
 
        pci_set_drvdata(pdev, NULL);
 }
@@ -1941,6 +1907,18 @@ static struct pci_device_id lpfc_id_table[] = {
                PCI_ANY_ID, PCI_ANY_ID, },
        {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
                PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+               PCI_ANY_ID, PCI_ANY_ID, },
+       {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+               PCI_ANY_ID, PCI_ANY_ID, },
        { 0 }
 };
 
index 4d016c2a1b26ebd14a8eb577d73c2c809bdd1337..8041c3f06f7b466483c4ec61d256adc49c2b6d6c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -212,6 +212,7 @@ lpfc_init_link(struct lpfc_hba * phba,
                        case LINK_SPEED_1G:
                        case LINK_SPEED_2G:
                        case LINK_SPEED_4G:
+                       case LINK_SPEED_8G:
                                mb->un.varInitLnk.link_flags |=
                                                        FLAGS_LINK_SPEED;
                                mb->un.varInitLnk.link_speed = linkspeed;
index 0c7e731dc45a6cdba715693d4c72ae0526920a7b..b309841e3846a571aaadd44fe60c950587315203 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -168,14 +168,13 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
  * routine effectively results in a "software abort".
  */
 int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
-       int send_abts)
+lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *iocb, *next_iocb;
-       IOCB_t *icmd;
-       int    found = 0;
+       IOCB_t *cmd;
 
        /* Abort outstanding I/O on NPort <nlp_DID> */
        lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
@@ -188,75 +187,39 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
        pring = &psli->ring[LPFC_ELS_RING];
 
        /* First check the txq */
-       do {
-               found = 0;
-               spin_lock_irq(phba->host->host_lock);
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-                       /* Check to see if iocb matches the nport we are looking
-                          for */
-                       if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
-                               found = 1;
-                               /* It matches, so deque and call compl with an
-                                  error */
-                               list_del(&iocb->list);
-                               pring->txq_cnt--;
-                               if (iocb->iocb_cmpl) {
-                                       icmd = &iocb->iocb;
-                                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       (iocb->iocb_cmpl) (phba, iocb, iocb);
-                                       spin_lock_irq(phba->host->host_lock);
-                               } else
-                                       lpfc_sli_release_iocbq(phba, iocb);
-                               break;
-                       }
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+               /* Check to see if iocb matches the nport we are looking
+                  for */
+               if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+                       /* It matches, so deque and call compl with an
+                          error */
+                       list_move_tail(&iocb->list, &completions);
+                       pring->txq_cnt--;
                }
-               spin_unlock_irq(phba->host->host_lock);
-       } while (found);
+       }
 
-       /* Everything on txcmplq will be returned by firmware
-        * with a no rpi / linkdown / abort error.  For ring 0,
-        * ELS discovery, we want to get rid of it right here.
-        */
        /* Next check the txcmplq */
-       do {
-               found = 0;
-               spin_lock_irq(phba->host->host_lock);
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
-                                        list) {
-                       /* Check to see if iocb matches the nport we are looking
-                          for */
-                       if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
-                               found = 1;
-                               /* It matches, so deque and call compl with an
-                                  error */
-                               list_del(&iocb->list);
-                               pring->txcmplq_cnt--;
-
-                               icmd = &iocb->iocb;
-                               /* If the driver is completing an ELS
-                                * command early, flush it out of the firmware.
-                                */
-                               if (send_abts &&
-                                  (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) &&
-                                  (icmd->un.elsreq64.bdl.ulpIoTag32)) {
-                                       lpfc_sli_issue_abort_iotag32(phba,
-                                                            pring, iocb);
-                               }
-                               if (iocb->iocb_cmpl) {
-                                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                                       spin_unlock_irq(phba->host->host_lock);
-                                       (iocb->iocb_cmpl) (phba, iocb, iocb);
-                                       spin_lock_irq(phba->host->host_lock);
-                               } else
-                                       lpfc_sli_release_iocbq(phba, iocb);
-                               break;
-                       }
-               }
-               spin_unlock_irq(phba->host->host_lock);
-       } while(found);
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+               /* Check to see if iocb matches the nport we are looking
+                  for */
+               if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+                       lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+       }
+       spin_unlock_irq(phba->host->host_lock);
+
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
+
+               if (iocb->iocb_cmpl) {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
+       }
 
        /* If we are delaying issuing an ELS command, cancel it */
        if (ndlp->nlp_flag & NLP_DELAY_TMO)
@@ -390,7 +353,10 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
         * queue this mbox command to be processed later.
         */
        mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
-       mbox->context2  = ndlp;
+       /*
+        * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
+        * command issued in lpfc_cmpl_els_acc().
+        */
        ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
 
        /*
@@ -404,7 +370,7 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
         */
        if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
        }
 
        lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
@@ -471,8 +437,7 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
        spin_unlock_irq(phba->host->host_lock);
        ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
        ndlp->nlp_prev_state = ndlp->nlp_state;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        return 0;
 }
 
@@ -502,12 +467,10 @@ lpfc_rcv_logo(struct lpfc_hba * phba,
 
                ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
                ndlp->nlp_prev_state = ndlp->nlp_state;
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        } else {
                ndlp->nlp_prev_state = ndlp->nlp_state;
-               ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
        }
 
        spin_lock_irq(phba->host->host_lock);
@@ -601,11 +564,10 @@ lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
 
        if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
                ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-               ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
                return ndlp->nlp_state;
        }
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -614,7 +576,7 @@ lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
                         struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        lpfc_issue_els_logo(phba, ndlp, 0);
-       lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
        return ndlp->nlp_state;
 }
 
@@ -630,7 +592,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
        ndlp->nlp_flag |= NLP_LOGO_ACC;
        spin_unlock_irq(phba->host->host_lock);
        lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
-       lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
 
        return ndlp->nlp_state;
 }
@@ -639,7 +601,7 @@ static uint32_t
 lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
                          struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -647,7 +609,7 @@ static uint32_t
 lpfc_device_rm_unused_node(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -697,7 +659,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -712,7 +674,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        if (evt == NLP_EVT_RCV_LOGO) {
                lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
@@ -727,8 +689,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
        spin_unlock_irq(phba->host->host_lock);
        ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
        ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
 
        return ndlp->nlp_state;
 }
@@ -803,32 +764,26 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
                goto out;
 
        lpfc_unreg_rpi(phba, ndlp);
-       if (lpfc_reg_login
-           (phba, irsp->un.elsreq64.remoteID,
-            (uint8_t *) sp, mbox, 0) == 0) {
+       if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
+                          mbox, 0) == 0) {
                switch (ndlp->nlp_DID) {
                case NameServer_DID:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_ns_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
                        break;
                case FDMI_DID:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_fdmi_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
                        break;
                default:
-                       mbox->mbox_cmpl =
-                               lpfc_mbx_cmpl_reg_login;
+                       mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
                }
-               mbox->context2 = ndlp;
+               mbox->context2 = lpfc_nlp_get(ndlp);
                if (lpfc_sli_issue_mbox(phba, mbox,
                                        (MBX_NOWAIT | MBX_STOP_IOCB))
                    != MBX_NOT_FINISHED) {
-                       ndlp->nlp_state =
-                               NLP_STE_REG_LOGIN_ISSUE;
-                       lpfc_nlp_list(phba, ndlp,
-                                     NLP_REGLOGIN_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
                        return ndlp->nlp_state;
                }
+               lpfc_nlp_put(ndlp);
                mp = (struct lpfc_dmabuf *)mbox->context1;
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
@@ -841,7 +796,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
  out:
        /* Free this node since the driver cannot login or has the wrong
           sparm */
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -855,9 +810,9 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -868,11 +823,10 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        /* software abort outstanding PLOGI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -888,7 +842,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
        struct lpfc_iocbq *cmdiocb;
 
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        cmdiocb = (struct lpfc_iocbq *) arg;
 
@@ -896,8 +850,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
                return ndlp->nlp_state;
        }
        ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
        lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
 
        return ndlp->nlp_state;
@@ -926,7 +879,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 0);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -987,20 +940,17 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
                memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
 
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                lpfc_unreg_rpi(phba, ndlp);
                return ndlp->nlp_state;
        }
 
        if (ndlp->nlp_type & NLP_FCP_TARGET) {
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
        } else {
                ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
        }
        return ndlp->nlp_state;
 }
@@ -1016,9 +966,9 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding ADISC */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1029,11 +979,10 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        /* software abort outstanding ADISC */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -1074,9 +1023,36 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
                             uint32_t evt)
 {
        struct lpfc_iocbq *cmdiocb;
+       LPFC_MBOXQ_t      *mb;
+       LPFC_MBOXQ_t      *nextmb;
+       struct lpfc_dmabuf *mp;
 
        cmdiocb = (struct lpfc_iocbq *) arg;
 
+       /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
+       if ((mb = phba->sli.mbox_active)) {
+               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+                  (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+                       mb->context2 = NULL;
+                       mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               }
+       }
+
+       spin_lock_irq(phba->host->host_lock);
+       list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+               if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+                  (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+                       mp = (struct lpfc_dmabuf *) (mb->context1);
+                       if (mp) {
+                               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                               kfree(mp);
+                       }
+                       list_del(&mb->list);
+                       mempool_free(mb, phba->mbox_mem_pool);
+               }
+       }
+       spin_unlock_irq(phba->host->host_lock);
+
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
 }
@@ -1133,8 +1109,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
                 */
                if (mb->mbxStatus == MBXERR_RPI_FULL) {
                        ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-                       ndlp->nlp_state = NLP_STE_UNUSED_NODE;
-                       lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
                        return ndlp->nlp_state;
                }
 
@@ -1147,8 +1122,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
 
                lpfc_issue_els_logo(phba, ndlp, 0);
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               ndlp->nlp_state = NLP_STE_NPR_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
                return ndlp->nlp_state;
        }
 
@@ -1157,13 +1131,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
        /* Only if we are not a fabric nport do we issue PRLI */
        if (!(ndlp->nlp_type & NLP_FABRIC)) {
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
                lpfc_issue_els_prli(phba, ndlp, 0);
        } else {
                ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
        }
        return ndlp->nlp_state;
 }
@@ -1178,7 +1150,7 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
                return ndlp->nlp_state;
        }
        else {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1189,8 +1161,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
                               uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1230,7 +1201,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
        cmdiocb = (struct lpfc_iocbq *) arg;
 
        /* Software abort outstanding PRLI before sending acc */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
        return ndlp->nlp_state;
@@ -1279,8 +1250,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus) {
                ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-               ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
-               lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
                return ndlp->nlp_state;
        }
 
@@ -1298,8 +1268,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
        }
 
        ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-       ndlp->nlp_state = NLP_STE_MAPPED_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
        return ndlp->nlp_state;
 }
 
@@ -1330,9 +1299,9 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
        }
        else {
                /* software abort outstanding PLOGI */
-               lpfc_els_abort(phba, ndlp, 1);
+               lpfc_els_abort(phba, ndlp);
 
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
 }
@@ -1359,11 +1328,10 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        /* software abort outstanding PRLI */
-       lpfc_els_abort(phba, ndlp, 1);
+       lpfc_els_abort(phba, ndlp);
 
        ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1436,8 +1404,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
                           struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        lpfc_disc_set_adisc(phba, ndlp);
 
@@ -1518,8 +1485,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
-       ndlp->nlp_state = NLP_STE_NPR_NODE;
-       lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+       lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
        spin_lock_irq(phba->host->host_lock);
        ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
        spin_unlock_irq(phba->host->host_lock);
@@ -1551,8 +1517,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
        /* send PLOGI immediately, move to PLOGI issue state */
        if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
                ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-               ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-               lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+               lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
        }
 
@@ -1580,16 +1545,13 @@ lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
                        ndlp->nlp_flag &= ~NLP_NPR_ADISC;
                        spin_unlock_irq(phba->host->host_lock);
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                        lpfc_issue_els_adisc(phba, ndlp, 0);
                } else {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                        lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                }
-
        }
        return ndlp->nlp_state;
 }
@@ -1627,13 +1589,11 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
                !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
                if (ndlp->nlp_flag & NLP_NPR_ADISC) {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
                        lpfc_issue_els_adisc(phba, ndlp, 0);
                } else {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
-                       ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
-                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+                       lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
                        lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
                }
        }
@@ -1682,7 +1642,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1700,7 +1660,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1728,7 +1688,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
 
        irsp = &rspiocb->iocb;
        if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
-               lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+               lpfc_drop_node(phba, ndlp);
                return NLP_STE_FREED_NODE;
        }
        return ndlp->nlp_state;
@@ -1749,7 +1709,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
                ndlp->nlp_rpi = mb->un.varWords[0];
        else {
                if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
-                       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+                       lpfc_drop_node(phba, ndlp);
                        return NLP_STE_FREED_NODE;
                }
        }
@@ -1765,7 +1725,7 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba,
                ndlp->nlp_flag |= NLP_NODEV_REMOVE;
                return ndlp->nlp_state;
        }
-       lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+       lpfc_drop_node(phba, ndlp);
        return NLP_STE_FREED_NODE;
 }
 
@@ -1964,7 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
        uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
                         uint32_t);
 
-       ndlp->nlp_disc_refcnt++;
+       lpfc_nlp_get(ndlp);
        cur_state = ndlp->nlp_state;
 
        /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
@@ -1987,18 +1947,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
                       phba->brd_no,
                       rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
-       ndlp->nlp_disc_refcnt--;
+       lpfc_nlp_put(ndlp);
 
-       /* Check to see if ndlp removal is deferred */
-       if ((ndlp->nlp_disc_refcnt == 0)
-           && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) {
-               spin_lock_irq(phba->host->host_lock);
-               ndlp->nlp_flag &= ~NLP_DELAY_REMOVE;
-               spin_unlock_irq(phba->host->host_lock);
-               lpfc_nlp_remove(phba, ndlp);
-               return NLP_STE_FREED_NODE;
-       }
-       if (rc == NLP_STE_FREED_NODE)
-               return NLP_STE_FREED_NODE;
        return rc;
 }
index c3e68e0d8f7445e426fa0ee28cc35ab5903c37cc..9a12d05e99e4d938460948186e8d0df9f7f9df5d 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -146,6 +146,10 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
 
        spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
        list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+       if (lpfc_cmd) {
+               lpfc_cmd->seg_cnt = 0;
+               lpfc_cmd->nonsg_phys = 0;
+       }
        spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
        return  lpfc_cmd;
 }
@@ -288,13 +292,13 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
 }
 
 static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
 {
        struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
        struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
        struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
        struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
-       uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
+       uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
        uint32_t resp_info = fcprsp->rspStatus2;
        uint32_t scsi_status = fcprsp->rspStatus3;
        uint32_t *lp;
@@ -355,6 +359,24 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
                                be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
                                fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
 
+               /*
+                * If there is an under run check if under run reported by
+                * storage array is same as the under run reported by HBA.
+                * If this is not same, there is a dropped frame.
+                */
+               if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
+                       fcpi_parm &&
+                       (cmnd->resid != fcpi_parm)) {
+                       lpfc_printf_log(phba, KERN_WARNING,
+                               LOG_FCP | LOG_FCP_ERROR,
+                               "%d:0735 FCP Read Check Error and Underrun "
+                               "Data: x%x x%x x%x x%x\n", phba->brd_no,
+                               be32_to_cpu(fcpcmd->fcpDl),
+                               cmnd->resid,
+                               fcpi_parm, cmnd->cmnd[0]);
+                       cmnd->resid = cmnd->request_bufflen;
+                       host_status = DID_ERROR;
+               }
                /*
                 * The cmnd->underflow is the minimum number of bytes that must
                 * be transfered for this command.  Provided a sense condition
@@ -435,7 +457,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                switch (lpfc_cmd->status) {
                case IOSTAT_FCP_RSP_ERROR:
                        /* Call FCP RSP handler to determine result */
-                       lpfc_handle_fcp_err(lpfc_cmd);
+                       lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
                        break;
                case IOSTAT_NPORT_BSY:
                case IOSTAT_FABRIC_BSY:
@@ -466,10 +488,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 
        result = cmd->result;
        sdev = cmd->device;
+       lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
        cmd->scsi_done(cmd);
 
        if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
-               lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
                lpfc_release_scsi_buf(phba, lpfc_cmd);
                return;
        }
@@ -527,7 +549,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
                }
        }
 
-       lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
        lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -670,6 +691,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
        return (1);
 }
 
+static void
+lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
+                       struct lpfc_iocbq *cmdiocbq,
+                       struct lpfc_iocbq *rspiocbq)
+{
+       struct lpfc_scsi_buf *lpfc_cmd =
+               (struct lpfc_scsi_buf *) cmdiocbq->context1;
+       if (lpfc_cmd)
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+       return;
+}
+
 static int
 lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
                    unsigned  tgt_id, unsigned int lun,
@@ -706,8 +739,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
                                       &phba->sli.ring[phba->sli.fcp_ring],
                                       iocbq, iocbqrsp, lpfc_cmd->timeout);
        if (ret != IOCB_SUCCESS) {
+               if (ret == IOCB_TIMEDOUT)
+                       iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
                lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
-               ret = FAILED;
        } else {
                ret = SUCCESS;
                lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
@@ -974,7 +1008,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 }
 
 static int
-lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
+lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -984,6 +1018,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
        struct lpfc_nodelist *pnode = rdata->pnode;
        uint32_t cmd_result = 0, cmd_status = 0;
        int ret = FAILED;
+       int iocb_status = IOCB_SUCCESS;
        int cnt, loopcnt;
 
        lpfc_block_error_handler(cmnd);
@@ -995,7 +1030,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
         */
        while ( 1 ) {
                if (!pnode)
-                       return FAILED;
+                       goto out;
 
                if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
                        spin_unlock_irq(phba->host->host_lock);
@@ -1013,7 +1048,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
                        }
                        pnode = rdata->pnode;
                        if (!pnode)
-                               return FAILED;
+                               goto out;
                }
                if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
                        break;
@@ -1028,7 +1063,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
        lpfc_cmd->rdata = rdata;
 
        ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
-                                          FCP_LUN_RESET);
+                                          FCP_TARGET_RESET);
        if (!ret)
                goto out_free_scsi_buf;
 
@@ -1040,16 +1075,21 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
                goto out_free_scsi_buf;
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-                       "%d:0703 Issue LUN Reset to TGT %d LUN %d "
-                       "Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
+                       "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
+                       "nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
                        cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
 
-       ret = lpfc_sli_issue_iocb_wait(phba,
+       iocb_status = lpfc_sli_issue_iocb_wait(phba,
                                       &phba->sli.ring[phba->sli.fcp_ring],
                                       iocbq, iocbqrsp, lpfc_cmd->timeout);
-       if (ret == IOCB_SUCCESS)
-               ret = SUCCESS;
 
+       if (iocb_status == IOCB_TIMEDOUT)
+               iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+
+       if (iocb_status == IOCB_SUCCESS)
+               ret = SUCCESS;
+       else
+               ret = iocb_status;
 
        cmd_result = iocbqrsp->iocb.un.ulpWord[4];
        cmd_status = iocbqrsp->iocb.ulpStatus;
@@ -1087,18 +1127,19 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
 
        if (cnt) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-                       "%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
+                       "%d:0719 device reset I/O flush failure: cnt x%x\n",
                        phba->brd_no, cnt);
                ret = FAILED;
        }
 
 out_free_scsi_buf:
-       lpfc_release_scsi_buf(phba, lpfc_cmd);
-
+       if (iocb_status != IOCB_TIMEDOUT) {
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+       }
        lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-                       "%d:0713 SCSI layer issued LUN reset (%d, %d) "
-                       "Data: x%x x%x x%x\n",
-                       phba->brd_no, cmnd->device->id,cmnd->device->lun,
+                       "%d:0713 SCSI layer issued device reset (%d, %d) "
+                       "return x%x status x%x result x%x\n",
+                       phba->brd_no, cmnd->device->id, cmnd->device->lun,
                        ret, cmd_status, cmd_result);
 
 out:
@@ -1107,7 +1148,7 @@ out:
 }
 
 static int
-lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -1134,10 +1175,12 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
         * fail, this routine returns failure to the midlayer.
         */
        for (i = 0; i < LPFC_MAX_TARGET; i++) {
-               /* Search the mapped list for this target ID */
+               /* Search for mapped node by target ID */
                match = 0;
-               list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
-                       if ((i == ndlp->nlp_sid) && ndlp->rport) {
+               list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+                       if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+                           i == ndlp->nlp_sid &&
+                           ndlp->rport) {
                                match = 1;
                                break;
                        }
@@ -1152,13 +1195,17 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
                                "%d:0700 Bus Reset on target %d failed\n",
                                phba->brd_no, i);
                        err_count++;
+                       break;
                }
        }
 
+       if (ret != IOCB_TIMEDOUT)
+               lpfc_release_scsi_buf(phba, lpfc_cmd);
+
        if (err_count == 0)
                ret = SUCCESS;
-
-       lpfc_release_scsi_buf(phba, lpfc_cmd);
+       else
+               ret = FAILED;
 
        /*
         * All outstanding txcmplq I/Os should have been aborted by
@@ -1299,11 +1346,13 @@ struct scsi_host_template lpfc_template = {
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
        .eh_abort_handler       = lpfc_abort_handler,
-       .eh_device_reset_handler= lpfc_reset_lun_handler,
-       .eh_bus_reset_handler   = lpfc_reset_bus_handler,
+       .eh_device_reset_handler= lpfc_device_reset_handler,
+       .eh_bus_reset_handler   = lpfc_bus_reset_handler,
        .slave_alloc            = lpfc_slave_alloc,
        .slave_configure        = lpfc_slave_configure,
        .slave_destroy          = lpfc_slave_destroy,
+       .scan_finished          = lpfc_scan_finished,
+       .scan_start             = lpfc_scan_start,
        .this_id                = -1,
        .sg_tablesize           = LPFC_SG_SEG_CNT,
        .cmd_per_lun            = LPFC_CMD_PER_LUN,
index 9fb6960a8adaca023b7faad67187f5c378c50e00..a1e721459e2b21a1734bff082c33e4f3c7df2bc7 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -528,6 +528,7 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
         * If pdone_q is empty, the driver thread gave up waiting and
         * continued running.
         */
+       pmboxq->mbox_flag |= LPFC_MBX_WAKE;
        pdone_q = (wait_queue_head_t *) pmboxq->context1;
        if (pdone_q)
                wake_up_interruptible(pdone_q);
@@ -538,11 +539,32 @@ void
 lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
        struct lpfc_dmabuf *mp;
+       uint16_t rpi;
+       int rc;
+
        mp = (struct lpfc_dmabuf *) (pmb->context1);
+
        if (mp) {
                lpfc_mbuf_free(phba, mp->virt, mp->phys);
                kfree(mp);
        }
+
+       /*
+        * If a REG_LOGIN succeeded  after node is destroyed or node
+        * is in re-discovery driver need to cleanup the RPI.
+        */
+       if (!(phba->fc_flag & FC_UNLOADING) &&
+               (pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+               (!pmb->mb.mbxStatus)) {
+
+               rpi = pmb->mb.un.varWords[0];
+               lpfc_unreg_login(phba, rpi, pmb);
+               pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+               if (rc != MBX_NOT_FINISHED)
+                       return;
+       }
+
        mempool_free( pmb, phba->mbox_mem_pool);
        return;
 }
@@ -693,25 +715,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
                } else {
                        spin_unlock_irq(phba->host->host_lock);
                        /* Turn on IOCB processing */
-                       for (i = 0; i < phba->sli.num_rings; i++) {
+                       for (i = 0; i < phba->sli.num_rings; i++)
                                lpfc_sli_turn_on_ring(phba, i);
-                       }
-
-                       /* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */
-                       while (!list_empty(&phba->freebufList)) {
-                               struct lpfc_dmabuf *mp;
-
-                               mp = NULL;
-                               list_remove_head((&phba->freebufList),
-                                                mp,
-                                                struct lpfc_dmabuf,
-                                                list);
-                               if (mp) {
-                                       lpfc_mbuf_free(phba, mp->virt,
-                                                      mp->phys);
-                                       kfree(mp);
-                               }
-                       }
                }
 
        } while (process_next);
@@ -833,6 +838,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
                         * All other are passed to the completion callback.
                         */
                        if (pring->ringno == LPFC_ELS_RING) {
+                               if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+                                       cmdiocbp->iocb_flag &=
+                                               ~LPFC_DRIVER_ABORTED;
+                                       saveq->iocb.ulpStatus =
+                                               IOSTAT_LOCAL_REJECT;
+                                       saveq->iocb.un.ulpWord[4] =
+                                               IOERR_SLI_ABORTED;
+                               }
                                spin_unlock_irqrestore(phba->host->host_lock,
                                                       iflag);
                                (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1464,8 +1477,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
 int
 lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
+       LIST_HEAD(completions);
        struct lpfc_iocbq *iocb, *next_iocb;
-       IOCB_t *icmd = NULL, *cmd = NULL;
+       IOCB_t *cmd = NULL;
        int errcnt;
 
        errcnt = 0;
@@ -1474,46 +1488,28 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
         * First do the txq.
         */
        spin_lock_irq(phba->host->host_lock);
-       list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-               list_del_init(&iocb->list);
-               if (iocb->iocb_cmpl) {
-                       icmd = &iocb->iocb;
-                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                       spin_unlock_irq(phba->host->host_lock);
-                       (iocb->iocb_cmpl) (phba, iocb, iocb);
-                       spin_lock_irq(phba->host->host_lock);
-               } else
-                       lpfc_sli_release_iocbq(phba, iocb);
-       }
+       list_splice_init(&pring->txq, &completions);
        pring->txq_cnt = 0;
-       INIT_LIST_HEAD(&(pring->txq));
 
        /* Next issue ABTS for everything on the txcmplq */
-       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
-               cmd = &iocb->iocb;
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+               lpfc_sli_issue_abort_iotag(phba, pring, iocb);
 
-               /*
-                * Imediate abort of IOCB, deque and call compl
-                */
+       spin_unlock_irq(phba->host->host_lock);
 
-               list_del_init(&iocb->list);
-               pring->txcmplq_cnt--;
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
 
                if (iocb->iocb_cmpl) {
                        cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
                        cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-                       spin_unlock_irq(phba->host->host_lock);
                        (iocb->iocb_cmpl) (phba, iocb, iocb);
-                       spin_lock_irq(phba->host->host_lock);
                } else
                        lpfc_sli_release_iocbq(phba, iocb);
        }
 
-       INIT_LIST_HEAD(&pring->txcmplq);
-       pring->txcmplq_cnt = 0;
-       spin_unlock_irq(phba->host->host_lock);
-
        return errcnt;
 }
 
@@ -1588,6 +1584,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
        hc_copy = readl(phba->HCregaddr);
        writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
 
        if (readl(phba->HAregaddr) & HA_ERATT) {
                /* Clear Chip error bit */
@@ -1630,6 +1627,7 @@ clear_errat:
        }
 
 restore_hc:
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        writel(hc_copy, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
 }
@@ -1665,6 +1663,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        status &= ~HC_ERINT_ENA;
        writel(status, phba->HCregaddr);
        readl(phba->HCregaddr); /* flush */
+       phba->fc_flag |= FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        lpfc_kill_board(phba, pmb);
@@ -1674,6 +1673,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        if (retval != MBX_SUCCESS) {
                if (retval != MBX_BUSY)
                        mempool_free(pmb, phba->mbox_mem_pool);
+               spin_lock_irq(phba->host->host_lock);
+               phba->fc_flag &= ~FC_IGNORE_ERATT;
+               spin_unlock_irq(phba->host->host_lock);
                return 1;
        }
 
@@ -1700,6 +1702,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
        }
        spin_lock_irq(phba->host->host_lock);
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+       phba->fc_flag &= ~FC_IGNORE_ERATT;
        spin_unlock_irq(phba->host->host_lock);
 
        psli->mbox_active = NULL;
@@ -1985,42 +1988,6 @@ lpfc_sli_hba_setup_exit:
        return rc;
 }
 
-static void
-lpfc_mbox_abort(struct lpfc_hba * phba)
-{
-       LPFC_MBOXQ_t *pmbox;
-       MAILBOX_t *mb;
-
-       if (phba->sli.mbox_active) {
-               del_timer_sync(&phba->sli.mbox_tmo);
-               phba->work_hba_events &= ~WORKER_MBOX_TMO;
-               pmbox = phba->sli.mbox_active;
-               mb = &pmbox->mb;
-               phba->sli.mbox_active = NULL;
-               if (pmbox->mbox_cmpl) {
-                       mb->mbxStatus = MBX_NOT_FINISHED;
-                       (pmbox->mbox_cmpl) (phba, pmbox);
-               }
-               phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-       }
-
-       /* Abort all the non active mailbox commands. */
-       spin_lock_irq(phba->host->host_lock);
-       pmbox = lpfc_mbox_get(phba);
-       while (pmbox) {
-               mb = &pmbox->mb;
-               if (pmbox->mbox_cmpl) {
-                       mb->mbxStatus = MBX_NOT_FINISHED;
-                       spin_unlock_irq(phba->host->host_lock);
-                       (pmbox->mbox_cmpl) (phba, pmbox);
-                       spin_lock_irq(phba->host->host_lock);
-               }
-               pmbox = lpfc_mbox_get(phba);
-       }
-       spin_unlock_irq(phba->host->host_lock);
-       return;
-}
-
 /*! lpfc_mbox_timeout
  *
  * \pre
@@ -2055,6 +2022,8 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 {
        LPFC_MBOXQ_t *pmbox;
        MAILBOX_t *mb;
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring;
 
        spin_lock_irq(phba->host->host_lock);
        if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
@@ -2062,8 +2031,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
                return;
        }
 
-       phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
        pmbox = phba->sli.mbox_active;
        mb = &pmbox->mb;
 
@@ -2078,17 +2045,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
                phba->sli.sli_flag,
                phba->sli.mbox_active);
 
-       phba->sli.mbox_active = NULL;
-       if (pmbox->mbox_cmpl) {
-               mb->mbxStatus = MBX_NOT_FINISHED;
-               spin_unlock_irq(phba->host->host_lock);
-               (pmbox->mbox_cmpl) (phba, pmbox);
-               spin_lock_irq(phba->host->host_lock);
-       }
-       phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
+       /* Setting state unknown so lpfc_sli_abort_iocb_ring
+        * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
+        * it to fail all oustanding SCSI IO.
+        */
+       phba->hba_state = LPFC_STATE_UNKNOWN;
+       phba->work_hba_events &= ~WORKER_MBOX_TMO;
+       phba->fc_flag |= FC_ESTABLISH_LINK;
+       psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
        spin_unlock_irq(phba->host->host_lock);
-       lpfc_mbox_abort(phba);
+
+       pring = &psli->ring[psli->fcp_ring];
+       lpfc_sli_abort_iocb_ring(phba, pring);
+
+       lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+                       "%d:0316 Resetting board due to mailbox timeout\n",
+                       phba->brd_no);
+       /*
+        * lpfc_offline calls lpfc_sli_hba_down which will clean up
+        * on oustanding mailbox commands.
+        */
+       lpfc_offline_prep(phba);
+       lpfc_offline(phba);
+       lpfc_sli_brdrestart(phba);
+       if (lpfc_online(phba) == 0)             /* Initialize the HBA */
+               mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+       lpfc_unblock_mgmt_io(phba);
        return;
 }
 
@@ -2320,9 +2302,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
                        spin_unlock_irqrestore(phba->host->host_lock,
                                               drvr_flag);
 
-                       /* Can be in interrupt context, do not sleep */
-                       /* (or might be called with interrupts disabled) */
-                       mdelay(1);
+                       msleep(1);
 
                        spin_lock_irqsave(phba->host->host_lock, drvr_flag);
 
@@ -2430,7 +2410,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
                /*
-                * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+                * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
                 * can be issued if the link is not up.
                 */
                switch (piocb->iocb.ulpCommand) {
@@ -2444,6 +2424,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                piocb->iocb_cmpl = NULL;
                        /*FALLTHROUGH*/
                case CMD_CREATE_XRI_CR:
+               case CMD_CLOSE_XRI_CN:
+               case CMD_CLOSE_XRI_CX:
                        break;
                default:
                        goto iocb_busy;
@@ -2637,11 +2619,12 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
 int
 lpfc_sli_hba_down(struct lpfc_hba * phba)
 {
+       LIST_HEAD(completions);
        struct lpfc_sli *psli;
        struct lpfc_sli_ring *pring;
        LPFC_MBOXQ_t *pmb;
-       struct lpfc_iocbq *iocb, *next_iocb;
-       IOCB_t *icmd = NULL;
+       struct lpfc_iocbq *iocb;
+       IOCB_t *cmd = NULL;
        int i;
        unsigned long flags = 0;
 
@@ -2649,7 +2632,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
        lpfc_hba_down_prep(phba);
 
        spin_lock_irqsave(phba->host->host_lock, flags);
-
        for (i = 0; i < psli->num_rings; i++) {
                pring = &psli->ring[i];
                pring->flag |= LPFC_DEFERRED_RING_EVENT;
@@ -2658,28 +2640,25 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
                 * Error everything on the txq since these iocbs have not been
                 * given to the FW yet.
                 */
+               list_splice_init(&pring->txq, &completions);
                pring->txq_cnt = 0;
 
-               list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-                       list_del_init(&iocb->list);
-                       if (iocb->iocb_cmpl) {
-                               icmd = &iocb->iocb;
-                               icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-                               icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
-                               spin_unlock_irqrestore(phba->host->host_lock,
-                                                      flags);
-                               (iocb->iocb_cmpl) (phba, iocb, iocb);
-                               spin_lock_irqsave(phba->host->host_lock, flags);
-                       } else
-                               lpfc_sli_release_iocbq(phba, iocb);
-               }
+       }
+       spin_unlock_irqrestore(phba->host->host_lock, flags);
 
-               INIT_LIST_HEAD(&(pring->txq));
+       while (!list_empty(&completions)) {
+               iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+               cmd = &iocb->iocb;
+               list_del(&iocb->list);
 
+               if (iocb->iocb_cmpl) {
+                       cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+                       (iocb->iocb_cmpl) (phba, iocb, iocb);
+               } else
+                       lpfc_sli_release_iocbq(phba, iocb);
        }
 
-       spin_unlock_irqrestore(phba->host->host_lock, flags);
-
        /* Return any active mbox cmds */
        del_timer_sync(&psli->mbox_tmo);
        spin_lock_irqsave(phba->host->host_lock, flags);
@@ -2768,85 +2747,138 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 }
 
 static void
-lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
-                          struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                       struct lpfc_iocbq * rspiocb)
 {
-       struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
-       /* Free the resources associated with the ELS_REQUEST64 IOCB the driver
-        * just aborted.
-        * In this case, context2  = cmd,  context2->next = rsp, context3 = bpl
-        */
-       if (cmdiocb->context2) {
-               buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
-
-               /* Free the response IOCB before completing the abort
-                  command.  */
-               buf_ptr = NULL;
-               list_remove_head((&buf_ptr1->list), buf_ptr,
-                                struct lpfc_dmabuf, list);
-               if (buf_ptr) {
-                       lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-                       kfree(buf_ptr);
-               }
-               lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-               kfree(buf_ptr1);
-       }
+       IOCB_t *irsp;
+       uint16_t abort_iotag, abort_context;
+       struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+       struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+
+       abort_iocb = NULL;
+       irsp = &rspiocb->iocb;
+
+       spin_lock_irq(phba->host->host_lock);
 
-       if (cmdiocb->context3) {
-               buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
-               lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-               kfree(buf_ptr);
+       if (irsp->ulpStatus) {
+               abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
+               abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+
+               if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
+                       abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+
+               lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+                               "%d:0327 Cannot abort els iocb %p"
+                               " with tag %x context %x\n",
+                               phba->brd_no, abort_iocb,
+                               abort_iotag, abort_context);
+
+               /*
+                * make sure we have the right iocbq before taking it
+                * off the txcmplq and try to call completion routine.
+                */
+               if (abort_iocb &&
+                   abort_iocb->iocb.ulpContext == abort_context &&
+                   abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
+                       list_del(&abort_iocb->list);
+                       pring->txcmplq_cnt--;
+
+                       rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
+                       if (rsp_ab_iocb == NULL)
+                               lpfc_sli_release_iocbq(phba, abort_iocb);
+                       else {
+                               abort_iocb->iocb_flag &=
+                                       ~LPFC_DRIVER_ABORTED;
+                               rsp_ab_iocb->iocb.ulpStatus =
+                                       IOSTAT_LOCAL_REJECT;
+                               rsp_ab_iocb->iocb.un.ulpWord[4] =
+                                       IOERR_SLI_ABORTED;
+                               spin_unlock_irq(phba->host->host_lock);
+                               (abort_iocb->iocb_cmpl)
+                                       (phba, abort_iocb, rsp_ab_iocb);
+                               spin_lock_irq(phba->host->host_lock);
+                               lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
+                       }
+               }
        }
 
        lpfc_sli_release_iocbq(phba, cmdiocb);
+       spin_unlock_irq(phba->host->host_lock);
        return;
 }
 
 int
-lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
-                            struct lpfc_sli_ring * pring,
-                            struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
+                          struct lpfc_sli_ring * pring,
+                          struct lpfc_iocbq * cmdiocb)
 {
        struct lpfc_iocbq *abtsiocbp;
        IOCB_t *icmd = NULL;
        IOCB_t *iabt = NULL;
+       int retval = IOCB_ERROR;
+
+       /* There are certain command types we don't want
+        * to abort.
+        */
+       icmd = &cmdiocb->iocb;
+       if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
+           (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+               return 0;
+
+       /* If we're unloading, interrupts are disabled so we
+        * need to cleanup the iocb here.
+        */
+       if (phba->fc_flag & FC_UNLOADING)
+               goto abort_iotag_exit;
 
        /* issue ABTS for this IOCB based on iotag */
        abtsiocbp = lpfc_sli_get_iocbq(phba);
        if (abtsiocbp == NULL)
                return 0;
 
+       /* This signals the response to set the correct status
+        * before calling the completion handler.
+        */
+       cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
+
        iabt = &abtsiocbp->iocb;
-       icmd = &cmdiocb->iocb;
-       switch (icmd->ulpCommand) {
-       case CMD_ELS_REQUEST64_CR:
-               /* Even though we abort the ELS command, the firmware may access
-                * the BPL or other resources before it processes our
-                * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
-                * resources till the actual abort request completes.
-                */
-               abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
-               abtsiocbp->context2 = cmdiocb->context2;
-               abtsiocbp->context3 = cmdiocb->context3;
-               cmdiocb->context2 = NULL;
-               cmdiocb->context3 = NULL;
-               abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
-               break;
-       default:
-               lpfc_sli_release_iocbq(phba, abtsiocbp);
-               return 0;
-       }
+       iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
+       iabt->un.acxri.abortContextTag = icmd->ulpContext;
+       iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
+       iabt->ulpLe = 1;
+       iabt->ulpClass = icmd->ulpClass;
 
-       iabt->un.amxri.abortType = ABORT_TYPE_ABTS;
-       iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32;
+       if (phba->hba_state >= LPFC_LINK_UP)
+               iabt->ulpCommand = CMD_ABORT_XRI_CN;
+       else
+               iabt->ulpCommand = CMD_CLOSE_XRI_CN;
 
-       iabt->ulpLe = 1;
-       iabt->ulpClass = CLASS3;
-       iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
+       abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
 
-       if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
-               lpfc_sli_release_iocbq(phba, abtsiocbp);
-               return 0;
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "%d:0339 Abort xri x%x, original iotag x%x, abort "
+                       "cmd iotag x%x\n",
+                       phba->brd_no, iabt->un.acxri.abortContextTag,
+                       iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+       retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+
+abort_iotag_exit:
+
+       /* If we could not issue an abort dequeue the iocb and handle
+        * the completion here.
+        */
+       if (retval == IOCB_ERROR) {
+               list_del(&cmdiocb->list);
+               pring->txcmplq_cnt--;
+
+               if (cmdiocb->iocb_cmpl) {
+                       icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+                       icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       spin_unlock_irq(phba->host->host_lock);
+                       (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
+                       spin_lock_irq(phba->host->host_lock);
+               } else
+                       lpfc_sli_release_iocbq(phba, cmdiocb);
        }
 
        return 1;
@@ -2918,9 +2950,11 @@ void
 lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                           struct lpfc_iocbq * rspiocb)
 {
-       spin_lock_irq(phba->host->host_lock);
+       unsigned long iflags;
+
+       spin_lock_irqsave(phba->host->host_lock, iflags);
        lpfc_sli_release_iocbq(phba, cmdiocb);
-       spin_unlock_irq(phba->host->host_lock);
+       spin_unlock_irqrestore(phba->host->host_lock, iflags);
        return;
 }
 
@@ -3043,22 +3077,22 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
                                timeout_req);
                spin_lock_irq(phba->host->host_lock);
 
-               if (timeleft == 0) {
+               if (piocb->iocb_flag & LPFC_IO_WAKE) {
+                       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                                       "%d:0331 IOCB wake signaled\n",
+                                       phba->brd_no);
+               } else if (timeleft == 0) {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "%d:0338 IOCB wait timeout error - no "
                                        "wake response Data x%x\n",
                                        phba->brd_no, timeout);
                        retval = IOCB_TIMEDOUT;
-               } else if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
+               } else {
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "%d:0330 IOCB wake NOT set, "
                                        "Data x%x x%lx\n", phba->brd_no,
                                        timeout, (timeleft / jiffies));
                        retval = IOCB_TIMEDOUT;
-               } else {
-                       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-                                       "%d:0331 IOCB wake signaled\n",
-                                       phba->brd_no);
                }
        } else {
                lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3087,8 +3121,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
                         uint32_t timeout)
 {
        DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
-       DECLARE_WAITQUEUE(wq_entry, current);
-       uint32_t timeleft = 0;
        int retval;
 
        /* The caller must leave context1 empty. */
@@ -3101,27 +3133,25 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
        /* setup context field to pass wait_queue pointer to wake function  */
        pmboxq->context1 = &done_q;
 
-       /* start to sleep before we wait, to avoid races */
-       set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(&done_q, &wq_entry);
-
        /* now issue the command */
        retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 
        if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
-               timeleft = schedule_timeout(timeout * HZ);
+               wait_event_interruptible_timeout(done_q,
+                               pmboxq->mbox_flag & LPFC_MBX_WAKE,
+                               timeout * HZ);
+
                pmboxq->context1 = NULL;
-               /* if schedule_timeout returns 0, we timed out and were not
-                  woken up */
-               if ((timeleft == 0) || signal_pending(current))
-                       retval = MBX_TIMEOUT;
-               else
+               /*
+                * if LPFC_MBX_WAKE flag is set the mailbox is completed
+                * else do not free the resources.
+                */
+               if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
                        retval = MBX_SUCCESS;
+               else
+                       retval = MBX_TIMEOUT;
        }
 
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&done_q, &wq_entry);
        return retval;
 }
 
@@ -3184,6 +3214,11 @@ lpfc_intr_handler(int irq, void *dev_id)
         */
        spin_lock(phba->host->host_lock);
        ha_copy = readl(phba->HAregaddr);
+       /* If somebody is waiting to handle an eratt don't process it
+        * here.  The brdkill function will do this.
+        */
+       if (phba->fc_flag & FC_IGNORE_ERATT)
+               ha_copy &= ~HA_ERATT;
        writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
        readl(phba->HAregaddr); /* flush */
        spin_unlock(phba->host->host_lock);
index a43549959dc7bb45bd9ebabcd8121afdcf201a00..41c38d324ab005ce43efd90f27d7be2fd93c5db2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -39,9 +39,10 @@ struct lpfc_iocbq {
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
        uint8_t iocb_flag;
-#define LPFC_IO_LIBDFC 1       /* libdfc iocb */
-#define LPFC_IO_WAKE   2       /* High Priority Queue signal flag */
-#define LPFC_IO_FCP    4       /* FCP command -- iocbq in scsi_buf */
+#define LPFC_IO_LIBDFC         1       /* libdfc iocb */
+#define LPFC_IO_WAKE           2       /* High Priority Queue signal flag */
+#define LPFC_IO_FCP            4       /* FCP command -- iocbq in scsi_buf */
+#define LPFC_DRIVER_ABORTED    8       /* driver aborted this request */
 
        uint8_t abort_count;
        uint8_t rsvd2;
@@ -67,6 +68,8 @@ struct lpfc_iocbq {
 #define IOCB_ERROR          2
 #define IOCB_TIMEDOUT       3
 
+#define LPFC_MBX_WAKE  1
+
 typedef struct lpfcMboxq {
        /* MBOXQs are used in single linked lists */
        struct list_head list;  /* ptr to next mailbox command */
@@ -75,6 +78,7 @@ typedef struct lpfcMboxq {
        void *context2;         /* caller context information */
 
        void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
+       uint8_t mbox_flag;
 
 } LPFC_MBOXQ_t;
 
index a61ef3d1e7f1b08090403de95e4547246c65420f..92a9107019d2c6de3b87a5ec7c899df256d6c063 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.11"
+#define LPFC_DRIVER_VERSION "8.1.12"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
                LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2006 Emulex.  All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
 
 #define DFC_API_VERSION "0.0.0"
index 7fc6e06ea7e19e2780f8c1fd9b608115ab71f0a9..3cce75d70263a4fd5b315e53241548f3b23a8012 100644 (file)
@@ -1754,7 +1754,8 @@ __mega_busywait_mbox (adapter_t *adapter)
        for (counter = 0; counter < 10000; counter++) {
                if (!mbox->m_in.busy)
                        return 0;
-               udelay(100); yield();
+               udelay(100);
+               cond_resched();
        }
        return -1;              /* give up after 1 second */
 }
@@ -3177,7 +3178,10 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
 
        return len;
 }
-
+#else
+static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+}
 #endif
 
 
@@ -4342,7 +4346,7 @@ mega_support_cluster(adapter_t *adapter)
        return 0;
 }
 
-
+#ifdef CONFIG_PROC_FS
 /**
  * mega_adapinq()
  * @adapter - pointer to our soft state
@@ -4447,7 +4451,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
 
        return rval;
 }
-
+#endif
 
 /**
  * mega_internal_command()
@@ -4965,7 +4969,6 @@ megaraid_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
        adapter_t *adapter = (adapter_t *)host->hostdata;
-       char    buf[12] = { 0 };
 
        scsi_remove_host(host);
 
@@ -5011,8 +5014,11 @@ megaraid_remove_one(struct pci_dev *pdev)
                remove_proc_entry("raiddrives-30-39",
                                adapter->controller_proc_dir_entry);
 #endif
-               sprintf(buf, "hba%d", adapter->host->host_no);
-               remove_proc_entry(buf, mega_proc_dir_entry);
+               {
+                       char    buf[12] = { 0 };
+                       sprintf(buf, "hba%d", adapter->host->host_no);
+                       remove_proc_entry(buf, mega_proc_dir_entry);
+               }
        }
 #endif
 
index c6e74643abe29be7f7d52ad29b7fd8634c548c4d..ee70bd4ae4badc0f2f7a82eb0a523d5702c796f4 100644 (file)
@@ -1002,7 +1002,6 @@ static int megaraid_reset(Scsi_Cmnd *);
 static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
 static int megaraid_biosparam(struct scsi_device *, struct block_device *,
                sector_t, int []);
-static int mega_print_inquiry(char *, char *);
 
 static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
                              u32 *buffer, u32 *length);
@@ -1024,6 +1023,7 @@ static int mega_init_scb (adapter_t *);
 static int mega_is_bios_enabled (adapter_t *);
 
 #ifdef CONFIG_PROC_FS
+static int mega_print_inquiry(char *, char *);
 static void mega_create_proc_entry(int, struct proc_dir_entry *);
 static int proc_read_config(char *, char **, off_t, int, int *, void *);
 static int proc_read_stat(char *, char **, off_t, int, int *, void *);
@@ -1040,10 +1040,10 @@ static int proc_rdrv_20(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
 static int proc_rdrv(adapter_t *, char *, int, int);
-#endif
 
 static int mega_adapinq(adapter_t *, dma_addr_t);
 static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
+#endif
 
 static int mega_support_ext_cdb(adapter_t *);
 static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *,
index f33a678f0897d749788ec7e2ed35e742019f1c18..e075a52ac104e06fcf94bf1ca35a816d4bfdf079 100644 (file)
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(mraid_mm_unregister_adp);
 EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
 
 static int majorno;
-static uint32_t drvr_ver       = 0x02200206;
+static uint32_t drvr_ver       = 0x02200207;
 
 static int adapters_count_g;
 static struct list_head adapters_list_g;
index cf3666d7d97aa8750eb12aee5715fd839379670e..e64d1a19d8d7e0f771fb235cc11bb7dbcdb42359 100644 (file)
@@ -185,7 +185,7 @@ struct mesh_state {
  * Driver is too messy, we need a few prototypes...
  */
 static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id);
+static void mesh_interrupt(struct mesh_state *ms);
 static void cmd_complete(struct mesh_state *ms);
 static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
 static void halt_dma(struct mesh_state *ms);
@@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                                dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
                                     MKWORD(mr->interrupt, mr->exception,
                                            mr->error, mr->fifo_count));
-                               mesh_interrupt(0, (void *)ms);
+                               mesh_interrupt(ms);
                                if (ms->phase != arbitrating)
                                        return;
                        }
@@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
                dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
                     MKWORD(mr->interrupt, mr->exception,
                            mr->error, mr->fifo_count));
-               mesh_interrupt(0, (void *)ms);
+               mesh_interrupt(ms);
                if (ms->phase != arbitrating)
                        return;
                dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1018,10 +1018,11 @@ static void handle_reset(struct mesh_state *ms)
 static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
 {
        unsigned long flags;
-       struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+       struct mesh_state *ms = dev_id;
+       struct Scsi_Host *dev = ms->host;
        
        spin_lock_irqsave(dev->host_lock, flags);
-       mesh_interrupt(irq, dev_id);
+       mesh_interrupt(ms);
        spin_unlock_irqrestore(dev->host_lock, flags);
        return IRQ_HANDLED;
 }
@@ -1661,9 +1662,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
  * handler (do_mesh_interrupt) or by other functions in
  * exceptional circumstances
  */
-static void mesh_interrupt(int irq, void *dev_id)
+static void mesh_interrupt(struct mesh_state *ms)
 {
-       struct mesh_state *ms = (struct mesh_state *) dev_id;
        volatile struct mesh_regs __iomem *mr = ms->mesh;
        int intr;
 
index 6777e8a69153a9a7c6eabc671ac4ea8a7ae2d642..54d8bdf86852b7541542298b05ce1f20b0c55c9e 100644 (file)
@@ -4293,7 +4293,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->devnum = devnum;    /* specifies microcode load address */
 
 #ifdef QLA_64BIT_PTR
-       if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
+       if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
                if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
                        printk(KERN_WARNING "scsi(%li): Unable to set a "
                               "suitable DMA mask - aborting\n", ha->host_no);
index 3e296ab845b653a454efc4f05a70f444eed4a67d..2a45aec4ff29e6499a36456d24f6f496caf9ff4a 100644 (file)
@@ -13,7 +13,6 @@
 
 #ifdef CONFIG_SPARC
 #include <asm/prom.h>
-#include <asm/pbm.h>
 #endif
 
 /* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
@@ -130,18 +129,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t w, mwi;
+       int ret;
+       uint16_t w;
        uint32_t d;
        unsigned long flags;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
        pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        /* Reset expansion ROM address decode enable */
@@ -166,22 +164,22 @@ qla2100_pci_config(scsi_qla_host_t *ha)
 int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t        w, mwi;
+       int             ret;
+       uint16_t        w;
        uint32_t        d;
        unsigned long   flags = 0;
        uint32_t        cnt;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
 
        if (IS_QLA2322(ha) || IS_QLA6322(ha))
                w &= ~PCI_COMMAND_INTX_DISABLE;
+       pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        /*
         * If this is a 2300 card and not 2312, reset the
@@ -210,7 +208,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
                ha->fb_rev = RD_FB_CMD_REG(ha, reg);
 
                if (ha->fb_rev == FPM_2300)
-                       w &= ~PCI_COMMAND_INVALIDATE;
+                       pci_clear_mwi(ha->pdev);
 
                /* Deselect FPM registers. */
                WRT_REG_WORD(&reg->ctrl_status, 0x0);
@@ -227,7 +225,6 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
        }
-       pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
        pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
@@ -253,19 +250,18 @@ qla2300_pci_config(scsi_qla_host_t *ha)
 int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
-       uint16_t w, mwi;
+       int ret;
+       uint16_t w;
        uint32_t d;
        unsigned long flags = 0;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
        int pcix_cmd_reg, pcie_dctl_reg;
 
        pci_set_master(ha->pdev);
-       mwi = 0;
-       if (pci_set_mwi(ha->pdev))
-               mwi = PCI_COMMAND_INVALIDATE;
+       ret = pci_set_mwi(ha->pdev);
 
        pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
-       w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+       w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
        w &= ~PCI_COMMAND_INTX_DISABLE;
        pci_write_config_word(ha->pdev, PCI_COMMAND, w);
 
@@ -1400,9 +1396,8 @@ static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
 {
 #ifdef CONFIG_SPARC
        struct pci_dev *pdev = ha->pdev;
-       struct pcidev_cookie *pcp = pdev->sysdata;
-       struct device_node *dp = pcp->prom_node;
-       u8 *val;
+       struct device_node *dp = pci_device_to_OF_node(pdev);
+       const u8 *val;
        int len;
 
        val = of_get_property(dp, "port-wwn", &len);
@@ -3373,9 +3368,8 @@ static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *n
 {
 #ifdef CONFIG_SPARC
        struct pci_dev *pdev = ha->pdev;
-       struct pcidev_cookie *pcp = pdev->sysdata;
-       struct device_node *dp = pcp->prom_node;
-       u8 *val;
+       struct device_node *dp = pci_device_to_OF_node(pdev);
+       const u8 *val;
        int len;
 
        val = of_get_property(dp, "port-wwn", &len);
@@ -3931,6 +3925,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 
        if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
                return;
+       if (!ha->fw_major_version)
+               return;
 
        ret = qla2x00_stop_firmware(ha);
        for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
index d4885616cd39c19077e72b2f083f563ec5cb2ad9..ca463469063d56358e2a1c91235f824175e2e738 100644 (file)
@@ -1726,6 +1726,17 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
        qla_printk(KERN_WARNING, ha,
            "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
+
+       if (!IS_QLA24XX(ha))
+               goto skip_msi;
+
+       ret = pci_enable_msi(ha->pdev);
+       if (!ret) {
+               DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+               ha->flags.msi_enabled = 1;
+       }
+skip_msi:
+
        ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
            IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
        if (!ret) {
@@ -1746,6 +1757,8 @@ qla2x00_free_irqs(scsi_qla_host_t *ha)
 
        if (ha->flags.msix_enabled)
                qla24xx_disable_msix(ha);
-       else if (ha->flags.inta_enabled)
+       else if (ha->flags.inta_enabled) {
                free_irq(ha->host->irq, ha);
+               pci_disable_msi(ha->pdev);
+       }
 }
index b78919a318e2b2ee87dc9170c676e2f64de2b6a1..dd076da86a465d668d6b251512492176a65e81be 100644 (file)
@@ -36,7 +36,7 @@ module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
                "Login timeout value in seconds.");
 
-int qlport_down_retry = 30;
+int qlport_down_retry;
 module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(qlport_down_retry,
                "Maximum number of command retries to a port that returns "
@@ -1577,9 +1577,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                goto probe_failed;
        }
 
-       if (qla2x00_initialize_adapter(ha) &&
-           !(ha->device_flags & DFLG_NO_CABLE)) {
-
+       if (qla2x00_initialize_adapter(ha)) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to initialize adapter\n");
 
index dc85495c337f856ecb220abd63166717308df227..c375a4efbc71b5cbe9372787db0bd9a14498e4b1 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.07-k6"
+#define QLA2XXX_VERSION      "8.01.07-k7"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   1
index 7b4e077a39c18c770bbd42a80c7696ea83066e8e..6437d024b0dd725b84a58d097be601a154df6917 100644 (file)
@@ -8,6 +8,8 @@
 #include "ql4_def.h"
 #include <scsi/scsi_dbg.h>
 
+#if 0
+
 static void qla4xxx_print_srb_info(struct srb * srb)
 {
        printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
@@ -195,3 +197,5 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
        if (cnt % 16)
                printk(KERN_DEBUG "\n");
 }
+
+#endif  /*  0  */
index e021eb5db2b2c6c7eb858c2092ce7c56903a47fb..5b00cb04e7c07d82b946e7426d0e968348b735a0 100644 (file)
@@ -43,8 +43,6 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
                            uint16_t *tcp_source_port_num,
                            uint16_t *connection_id);
 
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
-                                    uint32_t fw_ddb_index);
 int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
                          dma_addr_t fw_ddb_entry_dma);
 
@@ -55,18 +53,11 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
 struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
 int qla4xxx_add_sess(struct ddb_entry *);
 void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
-                                  uint16_t fw_ddb_index,
-                                  uint16_t connection_id,
-                                  uint16_t option);
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
-                                uint16_t fw_ddb_index);
 int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
 int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
 void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
                                       uint32_t intr_status);
 int qla4xxx_init_rings(struct scsi_qla_host * ha);
-void qla4xxx_dump_buffer(void *b, uint32_t size);
 struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
 void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
 int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
index b907b06d72ab4b30bd8541fa6fc1a4955b251284..6365df26861271a711d31d957b1bd9b1f52b7489 100644 (file)
@@ -7,9 +7,8 @@
 
 #include "ql4_def.h"
 
-/*
- * QLogic ISP4xxx Hardware Support Function Prototypes.
- */
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+                                           uint32_t fw_ddb_index);
 
 static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
 {
@@ -48,7 +47,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
  * This routine deallocates and unlinks the specified ddb_entry from the
  * adapter's
  **/
-void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
+static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+                            struct ddb_entry *ddb_entry)
 {
        /* Remove device entry from list */
        list_del_init(&ddb_entry->list);
@@ -370,9 +370,9 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
  * must be initialized prior to        calling this routine
  *
  **/
-int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
-                            struct ddb_entry *ddb_entry,
-                            uint32_t fw_ddb_index)
+static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+                                   struct ddb_entry *ddb_entry,
+                                   uint32_t fw_ddb_index)
 {
        struct dev_db_entry *fw_ddb_entry = NULL;
        dma_addr_t fw_ddb_entry_dma;
@@ -450,8 +450,8 @@ int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
  * This routine allocates a ddb_entry, ititializes some values, and
  * inserts it into the ddb list.
  **/
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
-                                    uint32_t fw_ddb_index)
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+                                           uint32_t fw_ddb_index)
 {
        struct ddb_entry *ddb_entry;
 
index d41ce380eedcbd298185a15db290cb15c946b00a..a216a1781afbbc92a179595ad45893ae9f376903 100644 (file)
@@ -19,8 +19,8 @@
  *     - advances the request_in pointer
  *     - checks for queue full
  **/
-int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
-                       struct queue_entry **queue_entry)
+static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+                              struct queue_entry **queue_entry)
 {
        uint16_t request_in;
        uint8_t status = QLA_SUCCESS;
@@ -62,8 +62,8 @@ int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
  *
  * This routine issues a marker IOCB.
  **/
-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
-                            struct ddb_entry *ddb_entry, int lun)
+static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+                                   struct ddb_entry *ddb_entry, int lun)
 {
        struct marker_entry *marker_entry;
        unsigned long flags = 0;
@@ -96,7 +96,7 @@ exit_send_marker:
        return status;
 }
 
-struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
        struct scsi_qla_host *ha)
 {
        struct continuation_t1_entry *cont_entry;
@@ -120,7 +120,7 @@ struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
        return cont_entry;
 }
 
-uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+static uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
 {
        uint16_t iocbs;
 
@@ -133,9 +133,9 @@ uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
        return iocbs;
 }
 
-void qla4xxx_build_scsi_iocbs(struct srb *srb,
-                             struct command_t3_entry *cmd_entry,
-                             uint16_t tot_dsds)
+static void qla4xxx_build_scsi_iocbs(struct srb *srb,
+                                    struct command_t3_entry *cmd_entry,
+                                    uint16_t tot_dsds)
 {
        struct scsi_qla_host *ha;
        uint16_t avail_dsds;
index 7f28657eef3f1d60e74827d7084408299042eea3..f116ff9172374bc3a07a6f10e58cf18bf84d02d7 100644 (file)
@@ -20,9 +20,9 @@
  * If outCount is 0, this routine completes successfully WITHOUT waiting
  * for the mailbox command to complete.
  **/
-int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
-                           uint8_t outCount, uint32_t *mbx_cmd,
-                           uint32_t *mbx_sts)
+static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+                                  uint8_t outCount, uint32_t *mbx_cmd,
+                                  uint32_t *mbx_sts)
 {
        int status = QLA_ERROR;
        uint8_t i;
@@ -170,6 +170,8 @@ mbox_exit:
 }
 
 
+#if 0
+
 /**
  * qla4xxx_issue_iocb - issue mailbox iocb command
  * @ha: adapter state pointer.
@@ -243,6 +245,8 @@ int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
        return QLA_SUCCESS;
 }
 
+#endif  /*  0  */
+
 /**
  * qla4xxx_initialize_fw_cb - initializes firmware control block.
  * @ha: Pointer to host adapter structure.
@@ -570,6 +574,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
        return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
 }
 
+#if 0
 int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
                                    uint16_t fw_ddb_index)
 {
@@ -594,6 +599,7 @@ int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
 
                return status;
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_get_crash_record - retrieves crash record.
@@ -649,6 +655,7 @@ exit_get_crash_record:
                                  crash_record, crash_record_dma);
 }
 
+#if 0
 /**
  * qla4xxx_get_conn_event_log - retrieves connection event log
  * @ha: Pointer to host adapter structure.
@@ -738,6 +745,7 @@ exit_get_event_log:
                dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
                                  event_log_dma);
 }
+#endif  /*  0  */
 
 /**
  * qla4xxx_reset_lun - issues LUN Reset
@@ -834,7 +842,8 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
        return QLA_SUCCESS;
 }
 
-int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
+static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+                                  dma_addr_t dma_addr)
 {
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -855,7 +864,7 @@ int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
        return QLA_SUCCESS;
 }
 
-int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
 {
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
index 0bfddf893ed0eba06e1362e0a4f06016eafcf86c..da21f5fbbf87cbb6f6c2c8502fbdd41a97551d59 100644 (file)
@@ -14,7 +14,7 @@
 /*
  * Driver version
  */
-char qla4xxx_version_str[40];
+static char qla4xxx_version_str[40];
 
 /*
  * SRB allocation cache
@@ -45,8 +45,7 @@ int ql4_mod_unload = 0;
 /*
  * SCSI host template entry points
  */
-
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
 
 /*
  * iSCSI template entry points
@@ -1352,7 +1351,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
  * At exit, the @ha's flags.enable_64bit_addressing set to indicated
  * supported addressing method.
  */
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
 {
        int retval;
 
@@ -1627,7 +1626,7 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
 
-struct pci_driver qla4xxx_pci_driver = {
+static struct pci_driver qla4xxx_pci_driver = {
        .name           = DRIVER_NAME,
        .id_table       = qla4xxx_pci_tbl,
        .probe          = qla4xxx_probe_adapter,
index 3963e7013bd90eca80df51c268427a4f3107af32..e8350c562d24c0a4598d7a4c0e4066c1b4911d35 100644 (file)
@@ -38,7 +38,6 @@
 #include "scsi_logging.h"
 
 #define SENSE_TIMEOUT          (10*HZ)
-#define START_UNIT_TIMEOUT     (30*HZ)
 
 /*
  * These should *probably* be handled by the host itself.
@@ -936,7 +935,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 
                for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
                        rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
-                                               START_UNIT_TIMEOUT, 0);
+                                               scmd->device->timeout, 0);
 
                if (rtn == SUCCESS)
                        return 0;
index 61fbcdcbb009e93ae5d59ef11fb95d6a416cf82c..1f5a07bf2a7535e439300b4daa51f898983973ef 100644 (file)
@@ -173,7 +173,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  * @retries:   number of times to retry request
  * @flags:     or into request flags;
  *
- * returns the req->errors value which is the the scsi_cmnd result
+ * returns the req->errors value which is the scsi_cmnd result
  * field.
  **/
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
index 14c4f065b2b8091c88c853bd7cbc732e027f160d..b4d1ece46f789d92e6cc94acdb38410625852233 100644 (file)
@@ -1718,31 +1718,12 @@ fc_starget_delete(struct work_struct *work)
        struct fc_rport *rport =
                container_of(work, struct fc_rport, stgt_delete_work);
        struct Scsi_Host *shost = rport_to_shost(rport);
-       unsigned long flags;
        struct fc_internal *i = to_fc_internal(shost->transportt);
 
-       /*
-        * Involve the LLDD if possible. All io on the rport is to
-        * be terminated, either as part of the dev_loss_tmo callback
-        * processing, or via the terminate_rport_io function.
-        */
-       if (i->f->dev_loss_tmo_callbk)
-               i->f->dev_loss_tmo_callbk(rport);
-       else if (i->f->terminate_rport_io)
+       /* Involve the LLDD if possible to terminate all io on the rport. */
+       if (i->f->terminate_rport_io)
                i->f->terminate_rport_io(rport);
 
-       spin_lock_irqsave(shost->host_lock, flags);
-       if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               if (!cancel_delayed_work(&rport->fail_io_work))
-                       fc_flush_devloss(shost);
-               if (!cancel_delayed_work(&rport->dev_loss_work))
-                       fc_flush_devloss(shost);
-               spin_lock_irqsave(shost->host_lock, flags);
-               rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
-       }
-       spin_unlock_irqrestore(shost->host_lock, flags);
-
        scsi_remove_target(&rport->dev);
 }
 
@@ -1760,6 +1741,7 @@ fc_rport_final_delete(struct work_struct *work)
        struct device *dev = &rport->dev;
        struct Scsi_Host *shost = rport_to_shost(rport);
        struct fc_internal *i = to_fc_internal(shost->transportt);
+       unsigned long flags;
 
        /*
         * if a scan is pending, flush the SCSI Host work_q so that 
@@ -1768,13 +1750,37 @@ fc_rport_final_delete(struct work_struct *work)
        if (rport->flags & FC_RPORT_SCAN_PENDING)
                scsi_flush_work(shost);
 
+       /* involve the LLDD to terminate all pending i/o */
+       if (i->f->terminate_rport_io)
+               i->f->terminate_rport_io(rport);
+
+       /*
+        * Cancel any outstanding timers. These should really exist
+        * only when rmmod'ing the LLDD and we're asking for
+        * immediate termination of the rports
+        */
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
+               spin_unlock_irqrestore(shost->host_lock, flags);
+               if (!cancel_delayed_work(&rport->fail_io_work))
+                       fc_flush_devloss(shost);
+               if (!cancel_delayed_work(&rport->dev_loss_work))
+                       fc_flush_devloss(shost);
+               spin_lock_irqsave(shost->host_lock, flags);
+               rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
+       }
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
        /* Delete SCSI target and sdevs */
        if (rport->scsi_target_id != -1)
                fc_starget_delete(&rport->stgt_delete_work);
-       else if (i->f->dev_loss_tmo_callbk)
+
+       /*
+        * Notify the driver that the rport is now dead. The LLDD will
+        * also guarantee that any communication to the rport is terminated
+        */
+       if (i->f->dev_loss_tmo_callbk)
                i->f->dev_loss_tmo_callbk(rport);
-       else if (i->f->terminate_rport_io)
-               i->f->terminate_rport_io(rport);
 
        transport_remove_device(dev);
        device_del(dev);
@@ -1963,8 +1969,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
                        }
 
                        if (match) {
-                               struct delayed_work *work =
-                                                       &rport->dev_loss_work;
 
                                memcpy(&rport->node_name, &ids->node_name,
                                        sizeof(rport->node_name));
@@ -1982,46 +1986,61 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
                                                fci->f->dd_fcrport_size);
 
                                /*
-                                * If we were blocked, we were a target.
-                                * If no longer a target, we leave the timer
-                                * running in case the port changes roles
-                                * prior to the timer expiring. If the timer
-                                * fires, the target will be torn down.
+                                * If we were not a target, cancel the
+                                * io terminate and rport timers, and
+                                * we're done.
+                                *
+                                * If we were a target, but our new role
+                                * doesn't indicate a target, leave the
+                                * timers running expecting the role to
+                                * change as the target fully logs in. If
+                                * it doesn't, the target will be torn down.
+                                *
+                                * If we were a target, and our role shows
+                                * we're still a target, cancel the timers
+                                * and kick off a scan.
                                 */
-                               if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))
-                                       return rport;
 
-                               /* restart the target */
+                               /* was a target, not in roles */
+                               if ((rport->scsi_target_id != -1) &&
+                                   (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
+                                       return rport;
 
                                /*
-                                * Stop the target timers first. Take no action
-                                * on the del_timer failure as the state
-                                * machine state change will validate the
-                                * transaction.
+                                * Stop the fail io and dev_loss timers.
+                                * If they flush, the port_state will
+                                * be checked and will NOOP the function.
                                 */
                                if (!cancel_delayed_work(&rport->fail_io_work))
                                        fc_flush_devloss(shost);
-                               if (!cancel_delayed_work(work))
+                               if (!cancel_delayed_work(&rport->dev_loss_work))
                                        fc_flush_devloss(shost);
 
                                spin_lock_irqsave(shost->host_lock, flags);
 
                                rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
-                               /* initiate a scan of the target */
-                               rport->flags |= FC_RPORT_SCAN_PENDING;
-                               scsi_queue_work(shost, &rport->scan_work);
-
-                               spin_unlock_irqrestore(shost->host_lock, flags);
-
-                               scsi_target_unblock(&rport->dev);
+                               /* if target, initiate a scan */
+                               if (rport->scsi_target_id != -1) {
+                                       rport->flags |= FC_RPORT_SCAN_PENDING;
+                                       scsi_queue_work(shost,
+                                                       &rport->scan_work);
+                                       spin_unlock_irqrestore(shost->host_lock,
+                                                       flags);
+                                       scsi_target_unblock(&rport->dev);
+                               } else
+                                       spin_unlock_irqrestore(shost->host_lock,
+                                                       flags);
 
                                return rport;
                        }
                }
        }
 
-       /* Search the bindings array */
+       /*
+        * Search the bindings array
+        * Note: if never a FCP target, you won't be on this list
+        */
        if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
 
                /* search for a matching consistent binding */
@@ -2158,15 +2177,24 @@ fc_remote_port_delete(struct fc_rport  *rport)
 
        spin_lock_irqsave(shost->host_lock, flags);
 
-       /* If no scsi target id mapping, delete it */
-       if (rport->scsi_target_id == -1) {
-               list_del(&rport->peers);
-               rport->port_state = FC_PORTSTATE_DELETED;
-               fc_queue_work(shost, &rport->rport_delete_work);
+       if (rport->port_state != FC_PORTSTATE_ONLINE) {
                spin_unlock_irqrestore(shost->host_lock, flags);
                return;
        }
 
+       /*
+        * In the past, we if this was not an FCP-Target, we would
+        * unconditionally just jump to deleting the rport.
+        * However, rports can be used as node containers by the LLDD,
+        * and its not appropriate to just terminate the rport at the
+        * first sign of a loss in connectivity. The LLDD may want to
+        * send ELS traffic to re-validate the login. If the rport is
+        * immediately deleted, it makes it inappropriate for a node
+        * container.
+        * So... we now unconditionally wait dev_loss_tmo before
+        * destroying an rport.
+        */
+
        rport->port_state = FC_PORTSTATE_BLOCKED;
 
        rport->flags |= FC_RPORT_DEVLOSS_PENDING;
@@ -2263,11 +2291,11 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that
- *                       was a SCSI target (thus was blocked), and failed
- *                       to return in the alloted time.
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
+ *                     which we blocked, and has now failed to return
+ *                     in the allotted time.
  * 
- * @work:      rport target that failed to reappear in the alloted time.
+ * @work:      rport target that failed to reappear in the allotted time.
  **/
 static void
 fc_timeout_deleted_rport(struct work_struct *work)
@@ -2283,10 +2311,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
        rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
 
        /*
-        * If the port is ONLINE, then it came back. Validate it's still an
-        * FCP target. If not, tear down the scsi_target on it.
+        * If the port is ONLINE, then it came back. If it was a SCSI
+        * target, validate it still is. If not, tear down the
+        * scsi_target on it.
         */
        if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
+           (rport->scsi_target_id != -1) &&
            !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
                dev_printk(KERN_ERR, &rport->dev,
                        "blocked FC remote port time out: no longer"
@@ -2297,18 +2327,24 @@ fc_timeout_deleted_rport(struct work_struct *work)
                return;
        }
 
+       /* NOOP state - we're flushing workq's */
        if (rport->port_state != FC_PORTSTATE_BLOCKED) {
                spin_unlock_irqrestore(shost->host_lock, flags);
                dev_printk(KERN_ERR, &rport->dev,
-                       "blocked FC remote port time out: leaving target alone\n");
+                       "blocked FC remote port time out: leaving"
+                       " rport%s alone\n",
+                       (rport->scsi_target_id != -1) ?  " and starget" : "");
                return;
        }
 
-       if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
+       if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) ||
+           (rport->scsi_target_id == -1)) {
                list_del(&rport->peers);
                rport->port_state = FC_PORTSTATE_DELETED;
                dev_printk(KERN_ERR, &rport->dev,
-                       "blocked FC remote port time out: removing target\n");
+                       "blocked FC remote port time out: removing"
+                       " rport%s\n",
+                       (rport->scsi_target_id != -1) ?  " and starget" : "");
                fc_queue_work(shost, &rport->rport_delete_work);
                spin_unlock_irqrestore(shost->host_lock, flags);
                return;
index 3158949ffa62206f98c0437462b83a3142f3f215..e7b85e832eb5990d76f45b4b30d255525dae030d 100644 (file)
@@ -351,6 +351,27 @@ static u8  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
  * (DCBs, SRBs, Queueing)
  *
  **********************************************************************/
+static void inline dc390_start_segment(struct dc390_srb* pSRB)
+{
+       struct scatterlist *psgl = pSRB->pSegmentList;
+
+       /* start new sg segment */
+       pSRB->SGBusAddr = sg_dma_address(psgl);
+       pSRB->SGToBeXferLen = sg_dma_len(psgl);
+}
+
+static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue)
+{
+       unsigned long xfer = pSRB->SGToBeXferLen - residue;
+
+       /* xfer more bytes transferred */
+       pSRB->SGBusAddr += xfer;
+       pSRB->TotalXferredLen += xfer;
+       pSRB->SGToBeXferLen = residue;
+
+       return xfer;
+}
+
 static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
 {
    struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
@@ -625,70 +646,6 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
     return 0;
 }
 
-//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
-#define DMA_INT 0
-
-#if DMA_INT
-/* This is similar to AM53C974.c ... */
-static u8 
-dc390_dma_intr (struct dc390_acb* pACB)
-{
-  struct dc390_srb* pSRB;
-  u8 dstate;
-  DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);
-  
-  DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate));
-  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-       { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
-         pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));});
-
-  dstate = DC390_read8 (DMA_Status); 
-
-  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
-  else pSRB  = pACB->pActiveDCB->pActiveSRB;
-  
-  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
-    {
-       printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
-       return dstate;
-    }
-  if (dstate & DMA_XFER_DONE)
-    {
-       u32 residual, xferCnt; int ctr = 6000000;
-       if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
-         {
-           do
-             {
-               DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n"));
-               dstate = DC390_read8 (DMA_Status);
-               residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
-                 DC390_read8 (CtcReg_High) << 16;
-               residual += DC390_read8 (Current_Fifo) & 0x1f;
-             } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-           if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-           /* residual =  ... */
-         }
-       else
-           residual = 0;
-       
-       /* ??? */
-       
-       xferCnt = pSRB->SGToBeXferLen - residual;
-       pSRB->SGBusAddr += xferCnt;
-       pSRB->TotalXferredLen += xferCnt;
-       pSRB->SGToBeXferLen = residual;
-# ifdef DC390_DEBUG0
-       printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
-               (unsigned int)residual, (unsigned int)xferCnt);
-# endif
-       
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    }
-  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-  return dstate;
-}
-#endif
-
 
 static void __inline__
 dc390_InvalidCmd(struct dc390_acb* pACB)
@@ -708,9 +665,6 @@ DC390_Interrupt(void *dev_id)
     u8  phase;
     void   (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
     u8  istate, istatus;
-#if DMA_INT
-    u8  dstatus;
-#endif
 
     sstatus = DC390_read8 (Scsi_Status);
     if( !(sstatus & INTERRUPT) )
@@ -718,22 +672,9 @@ DC390_Interrupt(void *dev_id)
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
 
-#if DMA_INT
-    spin_lock_irq(pACB->pScsiHost->host_lock);
-    dstatus = dc390_dma_intr (pACB);
-    spin_unlock_irq(pACB->pScsiHost->host_lock);
-
-    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
-    if (! (dstatus & SCSI_INTERRUPT))
-      {
-       DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
-       return IRQ_NONE;
-      }
-#else
     //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     //dstatus = DC390_read8 (DMA_Status);
     //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-#endif
 
     spin_lock_irq(pACB->pScsiHost->host_lock);
 
@@ -821,11 +762,10 @@ static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
 }
 
 static void
-dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus;
-    struct scatterlist *psgl;
-    u32    ResidCnt, xferCnt;
+    u32  ResidCnt;
     u8   dstate = 0;
 
     sstatus = *psstatus;
@@ -856,42 +796,35 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
 
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
        }
        else
        {
-           ResidCnt  = (u32) DC390_read8 (Current_Fifo) & 0x1f;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; 
-           ResidCnt += (u32) DC390_read8 (CtcReg_Low);
-
-           xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGBusAddr += xferCnt;
-           pSRB->TotalXferredLen += xferCnt;
-           pSRB->SGToBeXferLen = ResidCnt;
+           ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) +
+                   (((u32) DC390_read8 (CtcReg_High) << 16) |
+                    ((u32) DC390_read8 (CtcReg_Mid) << 8) |
+                    (u32) DC390_read8 (CtcReg_Low));
+
+           dc390_advance_segment(pSRB, ResidCnt);
        }
     }
     if ((*psstatus & 7) != SCSI_DATA_OUT)
     {
-           DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD);
            DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     }      
 }
 
 static void
-dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 {
     u8   sstatus, residual, bval;
-    struct scatterlist *psgl;
-    u32    ResidCnt, i;
+    u32  ResidCnt, i;
     unsigned long   xferCnt;
-    u8      *ptr;
 
     sstatus = *psstatus;
 
@@ -922,19 +855,17 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
            DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \
                + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8)               \
                + ((unsigned long) DC390_read8 (CtcReg_Low)));
-           DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen));
+           DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen));
 
-           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
 
            pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
            pSRB->SGIndex++;
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
 
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
@@ -973,47 +904,45 @@ din_1:
            }
            /* It seems a DMA Blast abort isn't that bad ... */
            if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
-           //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-           dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+           //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
+           dc390_laststatus &= ~0xff000000;
+           dc390_laststatus |= bval << 24;
 
            DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
-           ResidCnt = (u32) DC390_read8 (CtcReg_High);
-           ResidCnt <<= 8;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
-           ResidCnt <<= 8;
-           ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
-
-           xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-           pSRB->SGBusAddr += xferCnt;
-           pSRB->TotalXferredLen += xferCnt;
-           pSRB->SGToBeXferLen = ResidCnt;
-
-           if( residual )
-           {
-               static int feedback_requested;
+           ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) |
+                       ((u32) DC390_read8 (CtcReg_Mid) << 8)) |
+                   (u32) DC390_read8 (CtcReg_Low);
+
+           xferCnt = dc390_advance_segment(pSRB, ResidCnt);
+
+           if (residual) {
+               size_t count = 1;
+               size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList);
+               unsigned long flags;
+               u8 *ptr;
+
                bval = DC390_read8 (ScsiFifo);      /* get one residual byte */
 
-               if (!feedback_requested) {
-                       feedback_requested = 1;
-                       printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
-                              "to help improve support for your system.\n", __FILE__);
+               local_irq_save(flags);
+               ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count);
+               if (likely(ptr)) {
+                       *(ptr + offset) = bval;
+                       scsi_kunmap_atomic_sg(ptr);
                }
+               local_irq_restore(flags);
+               WARN_ON(!ptr);
 
-               ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
-               *ptr = bval;
-               pSRB->SGBusAddr++; xferCnt++;
-               pSRB->TotalXferredLen++;
-               pSRB->SGToBeXferLen--;
+               /* 1 more byte read */
+               xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1);
            }
-           DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+           DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\
                           pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
-
        }
     }
     if ((*psstatus & 7) != SCSI_DATA_IN)
     {
            DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+           DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
     }
 }
 
@@ -1216,7 +1145,7 @@ dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
 
 
 /* handle RESTORE_PTR */
-/* I presume, this command is already mapped, so, have to remap. */
+/* This doesn't look very healthy... to-be-fixed */
 static void 
 dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
 {
@@ -1225,6 +1154,7 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
     pSRB->TotalXferredLen = 0;
     pSRB->SGIndex = 0;
     if (pcmd->use_sg) {
+       size_t saved;
        pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
        psgl = pSRB->pSegmentList;
        //dc390_pci_sync(pSRB);
@@ -1236,15 +1166,16 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
            if( pSRB->SGIndex < pSRB->SGcount )
            {
                pSRB->pSegmentList++;
-               psgl = pSRB->pSegmentList;
-               pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-               pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+
+               dc390_start_segment(pSRB);
            }
            else
                pSRB->SGToBeXferLen = 0;
        }
-       pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
-       pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+
+       saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen;
+       pSRB->SGToBeXferLen -= saved;
+       pSRB->SGBusAddr += saved;
        printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
                pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
 
@@ -1365,7 +1296,6 @@ dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
 static void
 dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
 {
-    struct scatterlist *psgl;
     unsigned long  lval;
     struct dc390_dcb*   pDCB = pACB->pActiveDCB;
 
@@ -1391,12 +1321,11 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
 
     if( pSRB->SGIndex < pSRB->SGcount )
     {
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
        if( !pSRB->SGToBeXferLen )
        {
-           psgl = pSRB->pSegmentList;
-           pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
-           pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+           dc390_start_segment(pSRB);
+
            DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
        }
        lval = pSRB->SGToBeXferLen;
@@ -1410,12 +1339,12 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
        DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
        DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
 
-       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+       //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
        pSRB->SRBState = SRB_DATA_XFER;
 
        DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
-       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
        //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
        //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
        //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
@@ -1436,8 +1365,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
        pSRB->SRBState |= SRB_XFERPAD;
        DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
 /*
-       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
-       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+       DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
+       DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
 */
     }
 }
index 9b66fa8d38d948129df809016c0e81deb87cc900..c3d8c80cfb386182898fd966c4bd1b3d20685074 100644 (file)
 
 #define SEL_TIMEOUT            153     /* 250 ms selection timeout (@ 40 MHz) */
 
-#define pci_dma_lo32(a)                        (a & 0xffffffff)
-
-typedef u8             UCHAR;  /*  8 bits */
-typedef u16            USHORT; /* 16 bits */
-typedef u32            UINT;   /* 32 bits */
-typedef unsigned long  ULONG;  /* 32/64 bits */
-
-
 /*
 ;-----------------------------------------------------------------------
 ; SCSI Request Block
@@ -43,7 +35,9 @@ struct scatterlist    *pSegmentList;
 
 struct scatterlist Segmentx;   /* make a one entry of S/G list table */
 
-unsigned long  SGBusAddr;      /*;a segment starting address as seen by AM53C974A*/
+unsigned long  SGBusAddr;      /*;a segment starting address as seen by AM53C974A
+                                 in CPU endianness. We're only getting 32-bit bus
+                                 addresses by default */
 unsigned long  SGToBeXferLen;  /*; to be xfer length */
 unsigned long  TotalXferredLen;
 unsigned long  SavedTotXLen;
index e8efe938c4e740a64da3bc68627cb9ad8ae2ecaf..a6f5bfbb777b646ae75047c3ba625a677ba3edc3 100644 (file)
@@ -5,6 +5,7 @@
 #
 
 menu "Serial drivers"
+       depends on HAS_IOMEM
 
 #
 # The new 8250/16550 serial drivers
index 69715e55650612ebca86fd7d8b069e6ad4eb03a9..a8f894c7819463cd30b39eafd1bc10032f135965 100644 (file)
@@ -88,7 +88,7 @@ extern struct uart_cpm_port cpm_uart_ports[UART_NR];
 
 /* these are located in their respective files */
 void cpm_line_cr_cmd(int line, int cmd);
-int __init cpm_uart_init_portdesc(void);
+int cpm_uart_init_portdesc(void);
 int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
 void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
 
index f23972bc00c0e7a2552bc9015aebc4965462ee8c..b63ff8dd7304d8efd19d174a4ef9201d652ae6ae 100644 (file)
@@ -482,7 +482,8 @@ static void cpm_uart_shutdown(struct uart_port *port)
 }
 
 static void cpm_uart_set_termios(struct uart_port *port,
-                                struct termios *termios, struct termios *old)
+                                 struct ktermios *termios,
+                                 struct ktermios *old)
 {
        int baud;
        unsigned long flags;
index 925fb607d8c40f7fb37fa1874e28e0f23c2fb175..8c6324ed0202dda2b7568a3478f1e2ca3c948434 100644 (file)
@@ -125,7 +125,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 {
        int dpmemsz, memsz;
        u8 *dp_mem;
-       uint dp_offset;
+       unsigned long dp_offset;
        u8 *mem_addr;
        dma_addr_t dma_addr = 0;
 
@@ -133,7 +133,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 
        dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
        dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_DPERR(dp_offset)) {
+       if (IS_ERR_VALUE(dp_offset)) {
                printk(KERN_ERR
                       "cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
                return -ENOMEM;
@@ -185,7 +185,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
 }
 
 /* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
 {
        pr_debug("CPM uart[-]:init portdesc\n");
 
index fa455996ad8fb30b46004f16bf4feaa2f7a76efc..7b61d805ebe98b317138e3c2a562ee1496c29789 100644 (file)
@@ -222,7 +222,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 {
        int dpmemsz, memsz;
        u8 *dp_mem;
-       uint dp_offset;
+       unsigned long dp_offset;
        u8 *mem_addr;
        dma_addr_t dma_addr = 0;
 
@@ -230,7 +230,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 
        dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
        dp_offset = cpm_dpalloc(dpmemsz, 8);
-       if (IS_DPERR(dp_offset)) {
+       if (IS_ERR_VALUE(dp_offset)) {
                printk(KERN_ERR
                       "cpm_uart_cpm.c: could not allocate buffer descriptors\n");
                return -ENOMEM;
@@ -282,7 +282,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
 }
 
 /* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
 {
 #if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
        u16 *addr;
index da73205e54cded364297a9df504316229e7f7c6c..0985193dc57d1ce9aefbb548b0fb527d88343485 100644 (file)
@@ -92,6 +92,8 @@ struct uart_sunzilog_port {
 #define SUNZILOG_FLAG_REGS_HELD                0x00000040
 #define SUNZILOG_FLAG_TX_STOPPED       0x00000080
 #define SUNZILOG_FLAG_TX_ACTIVE                0x00000100
+#define SUNZILOG_FLAG_ESCC             0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER      0x00000400
 
        unsigned int cflag;
 
@@ -174,9 +176,11 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
 /* This function must only be called when the TX is not busy.  The UART
  * port lock must be held and local interrupts disabled.
  */
-static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
 {
        int i;
+       int escc;
+       unsigned char r15;
 
        /* Let pending transmits finish.  */
        for (i = 0; i < 1000; i++) {
@@ -229,11 +233,25 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
        write_zsreg(channel, R14, regs[R14]);
 
        /* External status interrupt control.  */
-       write_zsreg(channel, R15, regs[R15]);
+       write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+       /* ESCC Extension Register */
+       r15 = read_zsreg(channel, R15);
+       if (r15 & 0x01) {
+               write_zsreg(channel, R7,  regs[R7p]);
+
+               /* External status interrupt and FIFO control.  */
+               write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+               escc = 1;
+       } else {
+                /* Clear FIFO bit case it is an issue */
+               regs[R15] &= ~FIFOEN;
+               escc = 0;
+       }
 
        /* Reset external status interrupts.  */
-       write_zsreg(channel, R0, RES_EXT_INT);
-       write_zsreg(channel, R0, RES_EXT_INT);
+       write_zsreg(channel, R0, RES_EXT_INT); /* First Latch  */
+       write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
 
        /* Rewrite R3/R5, this time without enables masked.  */
        write_zsreg(channel, R3, regs[R3]);
@@ -241,6 +259,8 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
 
        /* Rewrite R1, this time without IRQ enabled masked.  */
        write_zsreg(channel, R1, regs[R1]);
+
+       return escc;
 }
 
 /* Reprogram the Zilog channel HW registers with the copies found in the
@@ -731,7 +751,7 @@ static void sunzilog_enable_ms(struct uart_port *port)
                up->curregs[R15] = new_reg;
 
                /* NOTE: Not subject to 'transmitter active' rule.  */ 
-               write_zsreg(channel, R15, up->curregs[R15]);
+               write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
        }
 }
 
@@ -861,44 +881,44 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag,
        up->curregs[R14] = BRSRC | BRENAB;
 
        /* Character size, stop bits, and parity. */
-       up->curregs[3] &= ~RxN_MASK;
-       up->curregs[5] &= ~TxN_MASK;
+       up->curregs[R3] &= ~RxN_MASK;
+       up->curregs[R5] &= ~TxN_MASK;
        switch (cflag & CSIZE) {
        case CS5:
-               up->curregs[3] |= Rx5;
-               up->curregs[5] |= Tx5;
+               up->curregs[R3] |= Rx5;
+               up->curregs[R5] |= Tx5;
                up->parity_mask = 0x1f;
                break;
        case CS6:
-               up->curregs[3] |= Rx6;
-               up->curregs[5] |= Tx6;
+               up->curregs[R3] |= Rx6;
+               up->curregs[R5] |= Tx6;
                up->parity_mask = 0x3f;
                break;
        case CS7:
-               up->curregs[3] |= Rx7;
-               up->curregs[5] |= Tx7;
+               up->curregs[R3] |= Rx7;
+               up->curregs[R5] |= Tx7;
                up->parity_mask = 0x7f;
                break;
        case CS8:
        default:
-               up->curregs[3] |= Rx8;
-               up->curregs[5] |= Tx8;
+               up->curregs[R3] |= Rx8;
+               up->curregs[R5] |= Tx8;
                up->parity_mask = 0xff;
                break;
        };
-       up->curregs[4] &= ~0x0c;
+       up->curregs[R4] &= ~0x0c;
        if (cflag & CSTOPB)
-               up->curregs[4] |= SB2;
+               up->curregs[R4] |= SB2;
        else
-               up->curregs[4] |= SB1;
+               up->curregs[R4] |= SB1;
        if (cflag & PARENB)
-               up->curregs[4] |= PAR_ENAB;
+               up->curregs[R4] |= PAR_ENAB;
        else
-               up->curregs[4] &= ~PAR_ENAB;
+               up->curregs[R4] &= ~PAR_ENAB;
        if (!(cflag & PARODD))
-               up->curregs[4] |= PAR_EVEN;
+               up->curregs[R4] |= PAR_EVEN;
        else
-               up->curregs[4] &= ~PAR_EVEN;
+               up->curregs[R4] &= ~PAR_EVEN;
 
        up->port.read_status_mask = Rx_OVR;
        if (iflag & INPCK)
@@ -952,7 +972,9 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
 
 static const char *sunzilog_type(struct uart_port *port)
 {
-       return "zs";
+       struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+       return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
 }
 
 /* We do not request/release mappings of the registers here, this
@@ -1170,7 +1192,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
 
        spin_lock_irqsave(&up->port.lock, flags);
 
-       up->curregs[R15] = BRKIE;
+       up->curregs[R15] |= BRKIE;
        sunzilog_convert_to_zs(up, con->cflag, 0, brg);
 
        sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1229,7 +1251,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
                baud = 4800;
        }
 
-       up->curregs[R15] = BRKIE;
+       up->curregs[R15] |= BRKIE;
        brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
        sunzilog_convert_to_zs(up, up->cflag, 0, brg);
        sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1283,8 +1305,18 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
 
        if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
                         SUNZILOG_FLAG_CONS_MOUSE)) {
+               up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+               up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+               up->curregs[R3] = RxENAB | Rx8;
+               up->curregs[R5] = TxENAB | Tx8;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
+               up->curregs[R7p] = 0x00;
                sunzilog_init_kbdms(up, up->port.line);
-               up->curregs[R9] |= (NV | MIE);
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
                write_zsreg(channel, R9, up->curregs[R9]);
        } else {
                /* Normal serial TTY. */
@@ -1293,7 +1325,9 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
                up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
                up->curregs[R3] = RxENAB | Rx8;
                up->curregs[R5] = TxENAB | Tx8;
-               up->curregs[R9] = NV | MIE;
+               up->curregs[R6] = 0x00; /* SDLC Address */
+               up->curregs[R7] = 0x7E; /* SDLC Flag    */
+               up->curregs[R9] = NV;
                up->curregs[R10] = NRZ;
                up->curregs[R11] = TCBR | RCBR;
                baud = 9600;
@@ -1301,7 +1335,14 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
                up->curregs[R12] = (brg & 0xff);
                up->curregs[R13] = (brg >> 8) & 0xff;
                up->curregs[R14] = BRSRC | BRENAB;
-               __load_zsregs(channel, up->curregs);
+               up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+               up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+               if (__load_zsregs(channel, up->curregs)) {
+                       up->flags |= SUNZILOG_FLAG_ESCC;
+               }
+               /* Only enable interrupts if an ISR handler available */
+               if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+                       up->curregs[R9] |= MIE;
                write_zsreg(channel, R9, up->curregs[R9]);
        }
 
@@ -1390,12 +1431,14 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
                        return err;
                }
        } else {
-               printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
-                      "is a zs\n",
-                      op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
-               printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
-                      "is a zs\n",
-                      op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
+               printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+                      "is a %s\n",
+                      op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
+                      sunzilog_type (&up[0].port));
+               printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+                      "is a %s\n",
+                      op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
+                      sunzilog_type (&up[1].port));
        }
 
        dev_set_drvdata(&op->dev, &up[0]);
@@ -1487,10 +1530,23 @@ static int __init sunzilog_init(void)
                goto out_unregister_uart;
 
        if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
                err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
                                  "zs", sunzilog_irq_chain);
                if (err)
                        goto out_unregister_driver;
+
+               /* Enable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       |= SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] |= MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
        }
 
 out:
@@ -1515,6 +1571,20 @@ static void __exit sunzilog_exit(void)
        of_unregister_driver(&zs_driver);
 
        if (zilog_irq != -1) {
+               struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+               /* Disable Interrupts */
+               while (up) {
+                       struct zilog_channel __iomem *channel;
+
+                       /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+                       channel          = ZILOG_CHANNEL_FROM_PORT(&up->port);
+                       up->flags       &= ~SUNZILOG_FLAG_ISR_HANDLER;
+                       up->curregs[R9] &= ~MIE;
+                       write_zsreg(channel, R9, up->curregs[R9]);
+                       up = up->next;
+               }
+
                free_irq(zilog_irq, sunzilog_irq_chain);
                zilog_irq = -1;
        }
index 7939b6d712706d9e20df1aed03ac4e6796e59a25..5dec7b47cc3845ee2fbbe53fe7be1334d14aff8c 100644 (file)
@@ -13,7 +13,8 @@ struct zilog_layout {
        struct zilog_channel channelA;
 };
 
-#define NUM_ZSREGS    16
+#define        NUM_ZSREGS      17
+#define        R7p             16 /* Written as R7 with P15 bit 0 set */
 
 /* Conversion routines to/from brg time constants from/to bits
  * per second.
@@ -127,6 +128,15 @@ struct zilog_layout {
 
 /* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
 
+/* Write Register 7' (ESCC Only) */
+#define        AUTO_TxFLAG     1       /* Automatic Tx SDLC Flag */
+#define        AUTO_EOM_RST    2       /* Automatic EOM Reset */
+#define        AUTOnRTS        4       /* Automatic /RTS pin deactivation */
+#define        RxFIFO_LVL      8       /* Receive FIFO interrupt level */
+#define        nDTRnREQ        0x10    /* /DTR/REQ timing */
+#define        TxFIFO_LVL      0x20    /* Transmit FIFO interrupt level */
+#define        EXT_RD_EN       0x40    /* Extended read register enable */
+
 /* Write Register 8 (transmit buffer) */
 
 /* Write Register 9 (Master interrupt control) */
@@ -135,6 +145,7 @@ struct zilog_layout {
 #define        DLC     4       /* Disable Lower Chain */
 #define        MIE     8       /* Master Interrupt Enable */
 #define        STATHI  0x10    /* Status high */
+#define        SWIACK  0x20    /* Software Interrupt Ack (not on NMOS) */
 #define        NORESET 0       /* No reset on write to R9 */
 #define        CHRB    0x40    /* Reset channel B */
 #define        CHRA    0x80    /* Reset channel A */
@@ -187,7 +198,9 @@ struct zilog_layout {
 #define        SNRZI   0xe0    /* Set NRZI mode */
 
 /* Write Register 15 (external/status interrupt control) */
+#define        WR7pEN  1       /* WR7' Enable (ESCC only) */
 #define        ZCIE    2       /* Zero count IE */
+#define        FIFOEN  4       /* FIFO Enable (ESCC only) */
 #define        DCDIE   8       /* DCD IE */
 #define        SYNCIE  0x10    /* Sync/hunt IE */
 #define        CTSIE   0x20    /* CTS IE */
@@ -241,6 +254,10 @@ struct zilog_layout {
 #define        CHATxIP 0x10            /* Channel A Tx IP */
 #define        CHARxIP 0x20            /* Channel A Rx IP */
 
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
 /* Read Register 8 (receive data register) */
 
 /* Read Register 10  (misc status bits) */
index 07c587ec71be17b42d7900d809199236ffe0f12a..5e3f748f269332a6e2abdf3b0933362782b4a510 100644 (file)
@@ -6,6 +6,7 @@
 # fully appropriate there, so it'd need some thought to do well.
 #
 menu "SPI support"
+       depends on HAS_IOMEM
 
 config SPI
        bool "SPI support"
@@ -106,6 +107,13 @@ config SPI_IMX
          This enables using the Freescale iMX SPI controller in master
          mode.
 
+config SPI_MPC52xx_PSC
+       tristate "Freescale MPC52xx PSC SPI controller"
+       depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+       help
+         This enables using the Freescale MPC52xx Programmable Serial
+         Controller in master SPI mode.
+
 config SPI_MPC83xx
        tristate "Freescale MPC83xx SPI controller"
        depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
index 624b6363f490bf74e7575478e3e0c7732e198449..5788d867de84051735eb10e7fd8c6077bce0cb07 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BUTTERFLY)           += spi_butterfly.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_PXA2XX)               += pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
+obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)              += spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx.o
index 66e7bc985797a0d8acce875c3281e744f7db9849..1d8a2f6bb8ebada212ad8d9617825bd9b96958ab 100644 (file)
 #include <asm/io.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
-
-#ifdef CONFIG_ARCH_AT91
 #include <asm/arch/cpu.h>
-#endif
 
 #include "atmel_spi.h"
 
@@ -552,10 +549,8 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
                goto out_free_buffer;
        as->irq = irq;
        as->clk = clk;
-#ifdef CONFIG_ARCH_AT91
        if (!cpu_is_at91rm9200())
                as->new_1 = 1;
-#endif
 
        ret = request_irq(irq, atmel_spi_interrupt, 0,
                        pdev->dev.bus_id, master);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
new file mode 100644 (file)
index 0000000..052359f
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * MPC52xx SPC in SPI mode driver.
+ *
+ * Maintainer: Dragos Carp
+ *
+ * Copyright (C) 2006 TOPTICA Photonics AG.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+
+#if defined(CONFIG_PPC_MERGE)
+#include <asm/of_platform.h>
+#else
+#include <linux/platform_device.h>
+#endif
+
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#define MCLK 20000000 /* PSC port MClk in hz */
+
+struct mpc52xx_psc_spi {
+       /* fsl_spi_platform data */
+       void (*activate_cs)(u8, u8);
+       void (*deactivate_cs)(u8, u8);
+       u32 sysclk;
+
+       /* driver internal data */
+       struct mpc52xx_psc __iomem *psc;
+       unsigned int irq;
+       u8 bits_per_word;
+       u8 busy;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       struct list_head queue;
+       spinlock_t lock;
+
+       struct completion done;
+};
+
+/* controller state */
+struct mpc52xx_psc_spi_cs {
+       int bits_per_word;
+       int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
+               struct spi_transfer *t)
+{
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+
+       cs->speed_hz = (t && t->speed_hz)
+                       ? t->speed_hz : spi->max_speed_hz;
+       cs->bits_per_word = (t && t->bits_per_word)
+                       ? t->bits_per_word : spi->bits_per_word;
+       cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+       return 0;
+}
+
+static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       u32 sicr;
+       u16 ccr;
+
+       sicr = in_be32(&psc->sicr);
+
+       /* Set clock phase and polarity */
+       if (spi->mode & SPI_CPHA)
+               sicr |= 0x00001000;
+       else
+               sicr &= ~0x00001000;
+       if (spi->mode & SPI_CPOL)
+               sicr |= 0x00002000;
+       else
+               sicr &= ~0x00002000;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               sicr |= 0x10000000;
+       else
+               sicr &= ~0x10000000;
+       out_be32(&psc->sicr, sicr);
+
+       /* Set clock frequency and bits per word
+        * Because psc->ccr is defined as 16bit register instead of 32bit
+        * just set the lower byte of BitClkDiv
+        */
+       ccr = in_be16(&psc->ccr);
+       ccr &= 0xFF00;
+       if (cs->speed_hz)
+               ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
+       else /* by default SPI Clk 1MHz */
+               ccr |= (MCLK / 1000000 - 1) & 0xFF;
+       out_be16(&psc->ccr, ccr);
+       mps->bits_per_word = cs->bits_per_word;
+
+       if (mps->activate_cs)
+               mps->activate_cs(spi->chip_select,
+                               (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+       if (mps->deactivate_cs)
+               mps->deactivate_cs(spi->chip_select,
+                               (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
+/* wake up when 80% fifo full */
+#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
+
+static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
+                                               struct spi_transfer *t)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       unsigned rb = 0;        /* number of bytes receieved */
+       unsigned sb = 0;        /* number of bytes sent */
+       unsigned char *rx_buf = (unsigned char *)t->rx_buf;
+       unsigned char *tx_buf = (unsigned char *)t->tx_buf;
+       unsigned rfalarm;
+       unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
+       unsigned recv_at_once;
+       unsigned bpw = mps->bits_per_word / 8;
+
+       if (!t->tx_buf && !t->rx_buf && t->len)
+               return -EINVAL;
+
+       /* enable transmiter/receiver */
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+       while (rb < t->len) {
+               if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
+                       rfalarm = MPC52xx_PSC_RFALARM;
+               } else {
+                       send_at_once = t->len - sb;
+                       rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
+               }
+
+               dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
+               if (tx_buf) {
+                       for (; send_at_once; sb++, send_at_once--) {
+                               /* set EOF flag */
+                               if (mps->bits_per_word
+                                               && (sb + 1) % bpw == 0)
+                                       out_8(&psc->ircr2, 0x01);
+                               out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
+                       }
+               } else {
+                       for (; send_at_once; sb++, send_at_once--) {
+                               /* set EOF flag */
+                               if (mps->bits_per_word
+                                               && ((sb + 1) % bpw) == 0)
+                                       out_8(&psc->ircr2, 0x01);
+                               out_8(&psc->mpc52xx_psc_buffer_8, 0);
+                       }
+               }
+
+
+               /* enable interupts and wait for wake up
+                * if just one byte is expected the Rx FIFO genererates no
+                * FFULL interrupt, so activate the RxRDY interrupt
+                */
+               out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+               if (t->len - rb == 1) {
+                       out_8(&psc->mode, 0);
+               } else {
+                       out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+                       out_be16(&psc->rfalarm, rfalarm);
+               }
+               out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
+               wait_for_completion(&mps->done);
+               recv_at_once = in_be16(&psc->rfnum);
+               dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
+
+               send_at_once = recv_at_once;
+               if (rx_buf) {
+                       for (; recv_at_once; rb++, recv_at_once--)
+                               rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
+               } else {
+                       for (; recv_at_once; rb++, recv_at_once--)
+                               in_8(&psc->mpc52xx_psc_buffer_8);
+               }
+       }
+       /* disable transmiter/receiver */
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+       return 0;
+}
+
+static void mpc52xx_psc_spi_work(struct work_struct *work)
+{
+       struct mpc52xx_psc_spi *mps =
+               container_of(work, struct mpc52xx_psc_spi, work);
+
+       spin_lock_irq(&mps->lock);
+       mps->busy = 1;
+       while (!list_empty(&mps->queue)) {
+               struct spi_message *m;
+               struct spi_device *spi;
+               struct spi_transfer *t = NULL;
+               unsigned cs_change;
+               int status;
+
+               m = container_of(mps->queue.next, struct spi_message, queue);
+               list_del_init(&m->queue);
+               spin_unlock_irq(&mps->lock);
+
+               spi = m->spi;
+               cs_change = 1;
+               status = 0;
+               list_for_each_entry (t, &m->transfers, transfer_list) {
+                       if (t->bits_per_word || t->speed_hz) {
+                               status = mpc52xx_psc_spi_transfer_setup(spi, t);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       if (cs_change)
+                               mpc52xx_psc_spi_activate_cs(spi);
+                       cs_change = t->cs_change;
+
+                       status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
+                       if (status)
+                               break;
+                       m->actual_length += t->len;
+
+                       if (t->delay_usecs)
+                               udelay(t->delay_usecs);
+
+                       if (cs_change)
+                               mpc52xx_psc_spi_deactivate_cs(spi);
+               }
+
+               m->status = status;
+               m->complete(m->context);
+
+               if (status || !cs_change)
+                       mpc52xx_psc_spi_deactivate_cs(spi);
+
+               mpc52xx_psc_spi_transfer_setup(spi, NULL);
+
+               spin_lock_irq(&mps->lock);
+       }
+       mps->busy = 0;
+       spin_unlock_irq(&mps->lock);
+}
+
+static int mpc52xx_psc_spi_setup(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+       unsigned long flags;
+
+       if (spi->bits_per_word%8)
+               return -EINVAL;
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+
+       cs->bits_per_word = spi->bits_per_word;
+       cs->speed_hz = spi->max_speed_hz;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       if (!mps->busy)
+               mpc52xx_psc_spi_deactivate_cs(spi);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
+               struct spi_message *m)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       list_add_tail(&m->queue, &mps->queue);
+       queue_work(mps->workqueue, &mps->work);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
+{
+       struct mpc52xx_cdm __iomem *cdm;
+       struct mpc52xx_gpio __iomem *gpio;
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       u32 ul;
+       u32 mclken_div;
+       int ret = 0;
+
+#if defined(CONFIG_PPC_MERGE)
+       cdm = mpc52xx_find_and_map("mpc52xx-cdm");
+       gpio = mpc52xx_find_and_map("mpc52xx-gpio");
+#else
+       cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+       gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+#endif
+       if (!cdm || !gpio) {
+               printk(KERN_ERR "Error mapping CDM/GPIO\n");
+               ret = -EFAULT;
+               goto unmap_regs;
+       }
+
+       /* default sysclk is 512MHz */
+       mclken_div = 0x8000 |
+               (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
+
+       switch (psc_id) {
+       case 1:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFFFF8;
+               ul |= 0x00000006;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc1, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000020;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 2:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFFF8F;
+               ul |= 0x00000060;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc2, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000040;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 3:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFF0FF;
+               ul |= 0x00000600;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc3, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000080;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 6:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFF8FFFFF;
+               ul |= 0x00700000;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc6, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000010;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       default:
+               ret = -EINVAL;
+               goto unmap_regs;
+       }
+
+       /* Reset the PSC into a known state */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+       /* Disable interrupts, interrupts are based on alarm level */
+       out_be16(&psc->mpc52xx_psc_imr, 0);
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->rfcntl, 0);
+       out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+
+       /* Configure 8bit codec mode as a SPI master and use EOF flags */
+       /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
+       out_be32(&psc->sicr, 0x0180C800);
+       out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+
+       /* Set 2ms DTL delay */
+       out_8(&psc->ctur, 0x00);
+       out_8(&psc->ctlr, 0x84);
+
+       mps->bits_per_word = 8;
+
+unmap_regs:
+       if (cdm)
+               iounmap(cdm);
+       if (gpio)
+               iounmap(gpio);
+
+       return ret;
+}
+
+static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
+{
+       struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+
+       /* disable interrupt and wake up the work queue */
+       if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
+               out_be16(&psc->mpc52xx_psc_imr, 0);
+               complete(&mps->done);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+                               u32 size, unsigned int irq, s16 bus_num)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc52xx_psc_spi *mps;
+       struct spi_master *master;
+       int ret;
+
+       if (pdata == NULL)
+               return -ENODEV;
+
+       master = spi_alloc_master(dev, sizeof *mps);
+       if (master == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, master);
+       mps = spi_master_get_devdata(master);
+
+       mps->irq = irq;
+       if (pdata == NULL) {
+               dev_warn(dev, "probe called without platform data, no "
+                               "(de)activate_cs function will be called\n");
+               mps->activate_cs = NULL;
+               mps->deactivate_cs = NULL;
+               mps->sysclk = 0;
+               master->bus_num = bus_num;
+               master->num_chipselect = 255;
+       } else {
+               mps->activate_cs = pdata->activate_cs;
+               mps->deactivate_cs = pdata->deactivate_cs;
+               mps->sysclk = pdata->sysclk;
+               master->bus_num = pdata->bus_num;
+               master->num_chipselect = pdata->max_chipselect;
+       }
+       master->setup = mpc52xx_psc_spi_setup;
+       master->transfer = mpc52xx_psc_spi_transfer;
+       master->cleanup = mpc52xx_psc_spi_cleanup;
+
+       mps->psc = ioremap(regaddr, size);
+       if (!mps->psc) {
+               dev_err(dev, "could not ioremap I/O port range\n");
+               ret = -EFAULT;
+               goto free_master;
+       }
+
+       ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
+                               mps);
+       if (ret)
+               goto free_master;
+
+       ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
+       if (ret < 0)
+               goto free_irq;
+
+       spin_lock_init(&mps->lock);
+       init_completion(&mps->done);
+       INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
+       INIT_LIST_HEAD(&mps->queue);
+
+       mps->workqueue = create_singlethread_workqueue(
+               master->cdev.dev->bus_id);
+       if (mps->workqueue == NULL) {
+               ret = -EBUSY;
+               goto free_irq;
+       }
+
+       ret = spi_register_master(master);
+       if (ret < 0)
+               goto unreg_master;
+
+       return ret;
+
+unreg_master:
+       destroy_workqueue(mps->workqueue);
+free_irq:
+       free_irq(mps->irq, mps);
+free_master:
+       if (mps->psc)
+               iounmap(mps->psc);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+       flush_workqueue(mps->workqueue);
+       destroy_workqueue(mps->workqueue);
+       spi_unregister_master(master);
+       free_irq(mps->irq, mps);
+       if (mps->psc)
+               iounmap(mps->psc);
+
+       return 0;
+}
+
+#if !defined(CONFIG_PPC_MERGE)
+static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
+{
+       switch(dev->id) {
+       case 1:
+       case 2:
+       case 3:
+       case 6:
+               return mpc52xx_psc_spi_do_probe(&dev->dev,
+                       MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
+                       MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
+{
+       return mpc52xx_psc_spi_do_remove(&dev->dev);
+}
+
+static struct platform_driver mpc52xx_psc_spi_platform_driver = {
+       .remove = __exit_p(mpc52xx_psc_spi_remove),
+       .driver = {
+               .name = "mpc52xx-psc-spi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+       return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
+                       mpc52xx_psc_spi_probe);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+       platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#else  /* defined(CONFIG_PPC_MERGE) */
+
+static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
+       const struct of_device_id *match)
+{
+       const u32 *regaddr_p;
+       u64 regaddr64, size64;
+       s16 id = -1;
+
+       regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+       if (!regaddr_p) {
+               printk(KERN_ERR "Invalid PSC address\n");
+               return -EINVAL;
+       }
+       regaddr64 = of_translate_address(op->node, regaddr_p);
+
+       if (op->dev.platform_data == NULL) {
+               struct device_node *np;
+               int i = 0;
+
+               for_each_node_by_type(np, "spi") {
+                       if (of_find_device_by_node(np) == op) {
+                               id = i;
+                               break;
+                       }
+                       i++;
+               }
+       }
+
+       return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
+                                       irq_of_parse_and_map(op->node, 0), id);
+}
+
+static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
+{
+       return mpc52xx_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+       { .type = "spi", .compatible = "mpc52xx-psc-spi", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
+
+static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
+       .owner = THIS_MODULE,
+       .name = "mpc52xx-psc-spi",
+       .match_table = mpc52xx_psc_spi_of_match,
+       .probe = mpc52xx_psc_spi_of_probe,
+       .remove = __exit_p(mpc52xx_psc_spi_of_remove),
+       .driver = {
+               .name = "mpc52xx-psc-spi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+       return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+       of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#endif /* defined(CONFIG_PPC_MERGE) */
+
+MODULE_AUTHOR("Dragos Carp");
+MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
+MODULE_LICENSE("GPL");
index 7625b1816baf96a5c560c4a4457bea8fc3152743..dd1d6a53f3c084f0b5a2cc49d27ee27da3fafb0c 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Telephony Support"
+       depends on HAS_IOMEM
 
 config PHONE
        tristate "Linux telephony support"
index b847bbc8b0e1a5730bb493ed5644d2a2a278cfe0..15499b7e33f4855b1f6bb8f440d06672a8388c86 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "USB support"
+       depends on HAS_IOMEM
 
 # Host-side USB depends on having a host controller
 # NOTE:  dummy_hcd is always an option, but it's ignored here ...
@@ -87,8 +88,6 @@ source "drivers/usb/storage/Kconfig"
 
 source "drivers/usb/image/Kconfig"
 
-source "drivers/usb/net/Kconfig"
-
 source "drivers/usb/mon/Kconfig"
 
 comment "USB port drivers"
index 0ef090b1b37c31f761520c1c25fbfad7ac68e0b7..72464b586990cdaab565bbb1958cd5212a1629ec 100644 (file)
@@ -23,13 +23,6 @@ obj-$(CONFIG_USB_PRINTER)    += class/
 obj-$(CONFIG_USB_STORAGE)      += storage/
 obj-$(CONFIG_USB)              += storage/
 
-obj-$(CONFIG_USB_CATC)         += net/
-obj-$(CONFIG_USB_KAWETH)       += net/
-obj-$(CONFIG_USB_PEGASUS)      += net/
-obj-$(CONFIG_USB_RTL8150)      += net/
-obj-$(CONFIG_USB_USBNET)       += net/
-obj-$(CONFIG_USB_ZD1201)       += net/
-
 obj-$(CONFIG_USB_MDC800)       += image/
 obj-$(CONFIG_USB_MICROTEK)     += image/
 
index b082d95bbbaae87f1a42c607ac67f75e33f34152..11e9b15ca45a35fb7c37e84fef91e07c54b2b507 100644 (file)
@@ -1033,7 +1033,7 @@ static int usbatm_do_heavy_init(void *arg)
 
 static int usbatm_heavy_init(struct usbatm_data *instance)
 {
-       int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+       int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
 
        if (ret < 0) {
                usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
index b5332e679c4644f86ed1ab0a45459ebf9810b04c..88fb56d5db8f8c2b22a21ceaa51602d72b86827f 100644 (file)
@@ -1307,7 +1307,7 @@ static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp)
 }
 
 
-/* remove a service from the the device
+/* remove a service from the device
    scp->id must be set! */
 static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
 {
index ba5d1dc030369c9a3b3d4b7d29281786da0d4778..3efe67092f15b85c1db4c4a145b83a79270789e6 100644 (file)
@@ -558,7 +558,7 @@ config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
        depends on USB_SERIAL
        help
-         Say Y here if you have a USB debugging device used to recieve
+         Say Y here if you have a USB debugging device used to receive
          debugging data from another machine.  The most common of these
          devices is the NetChip TurboCONNECT device.
 
index b675735bfbee559718a5fb650bf6dfe814a23a5d..fbc8c27d5d994763b842a718d8df2406a62881e7 100644 (file)
@@ -9,7 +9,7 @@
  * The device works as an standard CDC device, it has 2 interfaces, the first
  * one is for firmware access and the second is the serial one.
  * The protocol is very simply, there are two posibilities reading or writing.
- * When writting the first urb must have a Header that starts with 0x20 0x29 the
+ * When writing the first urb must have a Header that starts with 0x20 0x29 the
  * next two bytes must say how much data will be sended.
  * When reading the process is almost equal except that the header starts with
  * 0x00 0x20.
@@ -18,7 +18,7 @@
  * buffer: The First and Second byte is used for a Header, the Third and Fourth
  * tells the  device the amount of information the package holds.
  * Packages are 60 bytes long Header Stuff.
- * When writting to the device the first two bytes of the header are 0x20 0x29
+ * When writing to the device the first two bytes of the header are 0x20 0x29
  * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
  * situation, when too much data arrives to the device because it sends the data
  * but with out the header. I will use a simply hack to override this situation,
index 18f74ac7656565ff1ba3607a5ce0155a08ea729f..4807f960150bd389c58127323e3b5fc350dac62f 100644 (file)
@@ -2465,7 +2465,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
            ((edge_serial->is_epic) &&
             (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
             (regNum == MCR))) {
-               dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+               dbg("SendCmdWriteUartReg - Not writing to MCR Register");
                return 0;
        }
 
@@ -2473,7 +2473,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
            ((edge_serial->is_epic) &&
             (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
             (regNum == LCR))) {
-               dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+               dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
                return 0;
        }
 
index 1132ba5ff391d6f19e2aefbd45dfe15861883a46..eebcb708cff19fcdcbc99ce8758eb4c7edcd6d7c 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "Graphics support"
+       depends on HAS_IOMEM
 
 source "drivers/video/backlight/Kconfig"
 source "drivers/video/display/Kconfig"
@@ -747,6 +748,22 @@ config FB_S1D13XXX
          working with S1D13806). Product specs at
          <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_ATMEL
+       tristate "AT91/AT32 LCD Controller support"
+       depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       help
+         This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+       bool "Frame Buffer in internal SRAM"
+       depends on FB_ATMEL && ARCH_AT91SAM9261
+       help
+         Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+         to let frame buffer in external SDRAM.
+
 config FB_NVIDIA
        tristate "nVidia Framebuffer Support"
        depends on FB && PCI
@@ -779,6 +796,15 @@ config FB_NVIDIA_I2C
          independently validate video mode parameters, you should say Y
          here.
 
+config FB_NVIDIA_DEBUG
+       bool "Lots of debug output"
+       depends on FB_NVIDIA
+       default n
+       help
+         Say Y here if you want the nVidia driver to output all sorts
+         of debugging information to provide to the maintainer when
+         something goes wrong.
+
 config FB_NVIDIA_BACKLIGHT
        bool "Support for backlight control"
        depends on FB_NVIDIA
@@ -818,7 +844,7 @@ config FB_RIVA_I2C
          here.
 
 config FB_RIVA_DEBUG
-       bool "Lots of debug output from Riva(nVidia) driver"
+       bool "Lots of debug output"
        depends on FB_RIVA
        default n
        help
@@ -1348,6 +1374,20 @@ config FB_VOODOO1
          Please read the <file:Documentation/fb/README-sstfb.txt> for supported
          options and other important info  support.
 
+config FB_VT8623
+       tristate "VIA VT8623 support"
+       depends on FB && PCI
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB_TILEBLITTING
+       select FB_SVGALIB
+       select VGASTATE
+       select FONT_8x16 if FRAMEBUFFER_CONSOLE
+       ---help---
+         Driver for CastleRock integrated graphics core in the
+         VIA VT8623 [Apollo CLE266] chipset.
+
 config FB_CYBLA
        tristate "Cyberblade/i1 support"
        depends on FB && PCI && X86_32 && !64BIT
@@ -1401,9 +1441,26 @@ config FB_TRIDENT_ACCEL
        This will compile the Trident frame buffer device with
        acceleration functions.
 
+config FB_ARK
+       tristate "ARK 2000PV support"
+       depends on FB && PCI
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB_TILEBLITTING
+       select FB_SVGALIB
+       select VGASTATE
+       select FONT_8x16 if FRAMEBUFFER_CONSOLE
+       ---help---
+         Driver for PCI graphics boards with ARK 2000PV chip
+         and ICS 5342 RAMDAC.
+
 config FB_PM3
-       tristate "Permedia3 support"
-       depends on FB && PCI && BROKEN
+       tristate "Permedia3 support (EXPERIMENTAL)"
+       depends on FB && PCI && EXPERIMENTAL
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          This is the frame buffer device driver for the 3DLabs Permedia3
          chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
index a916c204274f7bf796267316222d44540eebe4e2..bd8b05229500cd18521e99364d4bea5881fd0639 100644 (file)
@@ -54,10 +54,12 @@ obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
 obj-$(CONFIG_FB_CT65550)          += chipsfb.o
 obj-$(CONFIG_FB_IMSTT)            += imsttfb.o
 obj-$(CONFIG_FB_FM2)              += fm2fb.o
+obj-$(CONFIG_FB_VT8623)           += vt8623fb.o
 obj-$(CONFIG_FB_CYBLA)            += cyblafb.o
 obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o
 obj-$(CONFIG_FB_LE80578)          += vermilion/
 obj-$(CONFIG_FB_S3)               += s3fb.o
+obj-$(CONFIG_FB_ARK)              += arkfb.o
 obj-$(CONFIG_FB_STI)              += stifb.o
 obj-$(CONFIG_FB_FFB)              += ffb.o sbuslib.o
 obj-$(CONFIG_FB_CG6)              += cg6.o sbuslib.o
@@ -85,6 +87,7 @@ obj-$(CONFIG_FB_G364)             += g364fb.o
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_EPSON1355)       += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL)           += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)         += amba-clcd.o
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
new file mode 100644 (file)
index 0000000..ba6fede
--- /dev/null
@@ -0,0 +1,1200 @@
+/*
+ *  linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV
+ *  with ICS 5342 dac (it is easy to add support for different dacs).
+ *
+ *  Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ *  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.
+ *
+ *  Code is based on s3fb
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct arkfb_info {
+       int mclk_freq;
+       int mtrr_reg;
+
+       struct dac_info *dac;
+       struct vgastate state;
+       struct mutex open_lock;
+       unsigned int ref_count;
+       u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static const struct svga_fb_format arkfb_formats[] = {
+       { 0,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4,   FB_VISUAL_PSEUDOCOLOR, 8, 8},
+       { 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_PSEUDOCOLOR, 8, 16},
+       { 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 1,
+               FB_TYPE_INTERLEAVED_PLANES, 1,          FB_VISUAL_PSEUDOCOLOR, 8, 16},
+       { 8,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_PSEUDOCOLOR, 8, 8},
+       {16,  {10, 5, 0}, {5, 5, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 4, 4},
+       {16,  {11, 5, 0}, {5, 6, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 4, 4},
+       {24,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 8, 8},
+       {32,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 2, 2},
+       SVGA_FORMAT_END
+};
+
+
+/* CRT timing register sets */
+
+static const struct vga_regset ark_h_total_regs[]        = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_h_display_regs[]      = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_start_regs[]  = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_end_regs[]    = {{0x03, 0, 4}, {0x05, 7, 7  }, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_start_regs[]   = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_end_regs[]     = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset ark_v_total_regs[]        = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_display_regs[]      = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_start_regs[]  = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
+// const struct vga_regset ark_v_blank_end_regs[]    = {{0x16, 0, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_end_regs[]    = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_start_regs[]   = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_end_regs[]     = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset ark_line_compare_regs[]   = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_start_address_regs[]  = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
+static const struct vga_regset ark_offset_regs[]         = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
+
+static const struct svga_timing_regs ark_timing_regs     = {
+       ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
+       ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
+       ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
+       ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+static int threshold = 4;
+
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "FIFO threshold");
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+       const u8 *font = map->data;
+       u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+       int i, c;
+
+       if ((map->width != 8) || (map->height != 16) ||
+           (map->depth != 1) || (map->length != 256)) {
+               printk(KERN_ERR "fb%d: unsupported font parameters: width %d, "
+                      "height %d, depth %d, length %d\n", info->node,
+                      map->width, map->height, map->depth, map->length);
+               return;
+       }
+
+       fb += 2;
+       for (c = 0; c < map->length; c++) {
+               for (i = 0; i < map->height; i++) {
+                       fb_writeb(font[i], &fb[i * 4]);
+                       fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
+               }
+               fb += 128;
+
+               if ((c % 8) == 7)
+                       fb += 128*8;
+
+               font += map->height;
+       }
+}
+
+static struct fb_tile_ops arkfb_tile_ops = {
+       .fb_settile     = arkfb_settile,
+       .fb_tilecopy    = svga_tilecopy,
+       .fb_tilefill    = svga_tilefill,
+       .fb_tileblit    = svga_tileblit,
+       .fb_tilecursor  = svga_tilecursor,
+       .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+       return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       u32 fg = expand_color(image->fg_color);
+       u32 bg = expand_color(image->bg_color);
+       const u8 *src1, *src;
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       u32 val;
+       int x, y;
+
+       src1 = image->data;
+       dst1 = info->screen_base + (image->dy * info->fix.line_length)
+                + ((image->dx / 8) * 4);
+
+       for (y = 0; y < image->height; y++) {
+               src = src1;
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < image->width; x += 8) {
+                       val = *(src++) * 0x01010101;
+                       val = (val & fg) | (~val & bg);
+                       fb_writel(val, dst++);
+               }
+               src1 += image->width / 8;
+               dst1 += info->fix.line_length;
+       }
+
+}
+
+/* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       u32 fg = expand_color(rect->color);
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       int x, y;
+
+       dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+                + ((rect->dx / 8) * 4);
+
+       for (y = 0; y < rect->height; y++) {
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < rect->width; x += 8) {
+                       fb_writel(fg, dst++);
+               }
+               dst1 += info->fix.line_length;
+       }
+
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+       return (((c &  1) << 24) | ((c &  2) << 27) | ((c &  4) << 14) | ((c &   8) << 17) |
+               ((c & 16) <<  4) | ((c & 32) <<  7) | ((c & 64) >>  6) | ((c & 128) >>  3)) * 0xF;
+}
+
+/* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       u32 fg = image->fg_color * 0x11111111;
+       u32 bg = image->bg_color * 0x11111111;
+       const u8 *src1, *src;
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       u32 val;
+       int x, y;
+
+       src1 = image->data;
+       dst1 = info->screen_base + (image->dy * info->fix.line_length)
+                + ((image->dx / 8) * 4);
+
+       for (y = 0; y < image->height; y++) {
+               src = src1;
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < image->width; x += 8) {
+                       val = expand_pixel(*(src++));
+                       val = (val & fg) | (~val & bg);
+                       fb_writel(val, dst++);
+               }
+               src1 += image->width / 8;
+               dst1 += info->fix.line_length;
+       }
+
+}
+
+static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+           && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+               if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+                       arkfb_iplan_imageblit(info, image);
+               else
+                       arkfb_cfb4_imageblit(info, image);
+       } else
+               cfb_imageblit(info, image);
+}
+
+static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       if ((info->var.bits_per_pixel == 4)
+           && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+           && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+               arkfb_iplan_fillrect(info, rect);
+        else
+               cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+enum
+{
+       DAC_PSEUDO8_8,
+       DAC_RGB1555_8,
+       DAC_RGB0565_8,
+       DAC_RGB0888_8,
+       DAC_RGB8888_8,
+       DAC_PSEUDO8_16,
+       DAC_RGB1555_16,
+       DAC_RGB0565_16,
+       DAC_RGB0888_16,
+       DAC_RGB8888_16,
+       DAC_MAX
+};
+
+struct dac_ops {
+       int (*dac_get_mode)(struct dac_info *info);
+       int (*dac_set_mode)(struct dac_info *info, int mode);
+       int (*dac_get_freq)(struct dac_info *info, int channel);
+       int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
+       void (*dac_release)(struct dac_info *info);
+};
+
+typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
+typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
+
+struct dac_info
+{
+       struct dac_ops *dacops;
+       dac_read_regs_t dac_read_regs;
+       dac_write_regs_t dac_write_regs;
+       void *data;
+};
+
+
+static inline u8 dac_read_reg(struct dac_info *info, u8 reg)
+{
+       u8 code[2] = {reg, 0};
+       info->dac_read_regs(info->data, code, 1);
+       return code[1];
+}
+
+static inline void dac_read_regs(struct dac_info *info, u8 *code, int count)
+{
+       info->dac_read_regs(info->data, code, count);
+}
+
+static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val)
+{
+       u8 code[2] = {reg, val};
+       info->dac_write_regs(info->data, code, 1);
+}
+
+static inline void dac_write_regs(struct dac_info *info, u8 *code, int count)
+{
+       info->dac_write_regs(info->data, code, count);
+}
+
+static inline int dac_set_mode(struct dac_info *info, int mode)
+{
+       return info->dacops->dac_set_mode(info, mode);
+}
+
+static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+       return info->dacops->dac_set_freq(info, channel, freq);
+}
+
+static inline void dac_release(struct dac_info *info)
+{
+       info->dacops->dac_release(info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ICS5342 DAC */
+
+struct ics5342_info
+{
+       struct dac_info dac;
+       u8 mode;
+};
+
+#define DAC_PAR(info) ((struct ics5342_info *) info)
+
+/* LSB is set to distinguish unused slots */
+static const u8 ics5342_mode_table[DAC_MAX] = {
+       [DAC_PSEUDO8_8]  = 0x01, [DAC_RGB1555_8]  = 0x21, [DAC_RGB0565_8]  = 0x61,
+       [DAC_RGB0888_8]  = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31,
+       [DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71
+};
+
+static int ics5342_set_mode(struct dac_info *info, int mode)
+{
+       u8 code;
+
+       if (mode >= DAC_MAX)
+               return -EINVAL;
+
+       code = ics5342_mode_table[mode];
+
+       if (! code)
+               return -EINVAL;
+
+       dac_write_reg(info, 6, code & 0xF0);
+       DAC_PAR(info)->mode = mode;
+
+       return 0;
+}
+
+static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3,
+       60000, 250000, 14318};
+
+/* pd4 - allow only posdivider 4 (r=2) */
+static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2,
+       60000, 335000, 14318};
+
+/* 270 MHz should be upper bound for VCO clock according to specs,
+   but that is too restrictive in pd4 case */
+
+static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+       u16 m, n, r;
+
+       /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */
+       int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16)
+                                 ? &ics5342_pll_pd4 : &ics5342_pll,
+                                 freq, &m, &n, &r, 0);
+
+       if (rv < 0) {
+               return -EINVAL;
+       } else {
+               u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)};
+               dac_write_regs(info, code, 3);
+               return 0;
+       }
+}
+
+static void ics5342_release(struct dac_info *info)
+{
+       ics5342_set_mode(info, DAC_PSEUDO8_8);
+       kfree(info);
+}
+
+static struct dac_ops ics5342_ops = {
+       .dac_set_mode   = ics5342_set_mode,
+       .dac_set_freq   = ics5342_set_freq,
+       .dac_release    = ics5342_release
+};
+
+
+static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data)
+{
+       struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL);
+
+       if (! info)
+               return NULL;
+
+       info->dacops = &ics5342_ops;
+       info->dac_read_regs = drr;
+       info->dac_write_regs = dwr;
+       info->data = data;
+       DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */
+       return info;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
+
+static void ark_dac_read_regs(void *data, u8 *code, int count)
+{
+       u8 regval = vga_rseq(NULL, 0x1C);
+
+       while (count != 0)
+       {
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+               count--;
+               code += 2;
+       }
+
+       vga_wseq(NULL, 0x1C, regval);
+}
+
+static void ark_dac_write_regs(void *data, u8 *code, int count)
+{
+       u8 regval = vga_rseq(NULL, 0x1C);
+
+       while (count != 0)
+       {
+               vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+               vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+               count--;
+               code += 2;
+       }
+
+       vga_wseq(NULL, 0x1C, regval);
+}
+
+
+static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+       struct arkfb_info *par = info->par;
+       u8 regval;
+
+       int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
+       if (rv < 0) {
+               printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+               return;
+       }
+
+       /* Set VGA misc register  */
+       regval = vga_r(NULL, VGA_MIS_R);
+       vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+}
+
+
+/* Open framebuffer */
+
+static int arkfb_open(struct fb_info *info, int user)
+{
+       struct arkfb_info *par = info->par;
+
+       mutex_lock(&(par->open_lock));
+       if (par->ref_count == 0) {
+               memset(&(par->state), 0, sizeof(struct vgastate));
+               par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+               par->state.num_crtc = 0x60;
+               par->state.num_seq = 0x30;
+               save_vga(&(par->state));
+       }
+
+       par->ref_count++;
+       mutex_unlock(&(par->open_lock));
+
+       return 0;
+}
+
+/* Close framebuffer */
+
+static int arkfb_release(struct fb_info *info, int user)
+{
+       struct arkfb_info *par = info->par;
+
+       mutex_lock(&(par->open_lock));
+       if (par->ref_count == 0) {
+               mutex_unlock(&(par->open_lock));
+               return -EINVAL;
+       }
+
+       if (par->ref_count == 1) {
+               restore_vga(&(par->state));
+               dac_set_mode(par->dac, DAC_PSEUDO8_8);
+       }
+
+       par->ref_count--;
+       mutex_unlock(&(par->open_lock));
+
+       return 0;
+}
+
+/* Validate passed in var */
+
+static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       int rv, mem, step;
+
+       /* Find appropriate format */
+       rv = svga_match_format (arkfb_formats, var, NULL);
+       if (rv < 0)
+       {
+               printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+               return rv;
+       }
+
+       /* Do not allow to have real resoulution larger than virtual */
+       if (var->xres > var->xres_virtual)
+               var->xres_virtual = var->xres;
+
+       if (var->yres > var->yres_virtual)
+               var->yres_virtual = var->yres;
+
+       /* Round up xres_virtual to have proper alignment of lines */
+       step = arkfb_formats[rv].xresstep - 1;
+       var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+
+       /* Check whether have enough memory */
+       mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+       if (mem > info->screen_size)
+       {
+               printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+               return -EINVAL;
+       }
+
+       rv = svga_check_timings (&ark_timing_regs, var, info->node);
+       if (rv < 0)
+       {
+               printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+               return rv;
+       }
+
+       /* Interlaced mode is broken */
+       if (var->vmode & FB_VMODE_INTERLACED)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Set video mode from par */
+
+static int arkfb_set_par(struct fb_info *info)
+{
+       struct arkfb_info *par = info->par;
+       u32 value, mode, hmul, hdiv, offset_value, screen_size;
+       u32 bpp = info->var.bits_per_pixel;
+       u8 regval;
+
+       if (bpp != 0) {
+               info->fix.ypanstep = 1;
+               info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+               info->flags &= ~FBINFO_MISC_TILEBLITTING;
+               info->tileops = NULL;
+
+               /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+               info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+               info->pixmap.blit_y = ~(u32)0;
+
+               offset_value = (info->var.xres_virtual * bpp) / 64;
+               screen_size = info->var.yres_virtual * info->fix.line_length;
+       } else {
+               info->fix.ypanstep = 16;
+               info->fix.line_length = 0;
+
+               info->flags |= FBINFO_MISC_TILEBLITTING;
+               info->tileops = &arkfb_tile_ops;
+
+               /* supports 8x16 tiles only */
+               info->pixmap.blit_x = 1 << (8 - 1);
+               info->pixmap.blit_y = 1 << (16 - 1);
+
+               offset_value = info->var.xres_virtual / 16;
+               screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+       }
+
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+
+       /* Unlock registers */
+       svga_wcrt_mask(0x11, 0x00, 0x80);
+
+       /* Blank screen and turn off sync */
+       svga_wseq_mask(0x01, 0x20, 0x20);
+       svga_wcrt_mask(0x17, 0x00, 0x80);
+
+       /* Set default values */
+       svga_set_default_gfx_regs();
+       svga_set_default_atc_regs();
+       svga_set_default_seq_regs();
+       svga_set_default_crt_regs();
+       svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
+       svga_wcrt_multi(ark_start_address_regs, 0);
+
+       /* ARK specific initialization */
+       svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+       svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+
+       vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
+       vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
+       vga_wseq(NULL, 0x15, 0);
+       vga_wseq(NULL, 0x16, 0);
+
+       /* Set the FIFO threshold register */
+       /* It is fascinating way to store 5-bit value in 8-bit register */
+       regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
+       vga_wseq(NULL, 0x18, regval);
+
+       /* Set the offset register */
+       pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
+       svga_wcrt_multi(ark_offset_regs, offset_value);
+
+       /* fix for hi-res textmode */
+       svga_wcrt_mask(0x40, 0x08, 0x08);
+
+       if (info->var.vmode & FB_VMODE_DOUBLE)
+               svga_wcrt_mask(0x09, 0x80, 0x80);
+       else
+               svga_wcrt_mask(0x09, 0x00, 0x80);
+
+       if (info->var.vmode & FB_VMODE_INTERLACED)
+               svga_wcrt_mask(0x44, 0x04, 0x04);
+       else
+               svga_wcrt_mask(0x44, 0x00, 0x04);
+
+       hmul = 1;
+       hdiv = 1;
+       mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix));
+
+       /* Set mode-specific register values */
+       switch (mode) {
+       case 0:
+               pr_debug("fb%d: text mode\n", info->node);
+               svga_set_textmode_vga_regs();
+
+               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               dac_set_mode(par->dac, DAC_PSEUDO8_8);
+
+               break;
+       case 1:
+               pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+               vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               dac_set_mode(par->dac, DAC_PSEUDO8_8);
+               break;
+       case 2:
+               pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+               svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+               dac_set_mode(par->dac, DAC_PSEUDO8_8);
+               break;
+       case 3:
+               pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+
+               if (info->var.pixclock > 20000) {
+                       pr_debug("fb%d: not using multiplex\n", info->node);
+                       svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+                       dac_set_mode(par->dac, DAC_PSEUDO8_8);
+               } else {
+                       pr_debug("fb%d: using multiplex\n", info->node);
+                       svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+                       dac_set_mode(par->dac, DAC_PSEUDO8_16);
+                       hdiv = 2;
+               }
+               break;
+       case 4:
+               pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               dac_set_mode(par->dac, DAC_RGB1555_16);
+               break;
+       case 5:
+               pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               dac_set_mode(par->dac, DAC_RGB0565_16);
+               break;
+       case 6:
+               pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
+               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               dac_set_mode(par->dac, DAC_RGB0888_16);
+               hmul = 3;
+               hdiv = 2;
+               break;
+       case 7:
+               pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+
+               vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
+               svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+               dac_set_mode(par->dac, DAC_RGB8888_16);
+               hmul = 2;
+               break;
+       default:
+               printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+               return -EINVAL;
+       }
+
+       ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
+       svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+                        (info->var.vmode & FB_VMODE_DOUBLE)     ? 2 : 1,
+                        (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+                         hmul, info->node);
+
+       /* Set interlaced mode start/end register */
+       value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+       value = ((value * hmul / hdiv) / 8) - 5;
+       vga_wcrt(NULL, 0x42, (value + 1) / 2);
+
+       memset_io(info->screen_base, 0x00, screen_size);
+       /* Device and screen back on */
+       svga_wcrt_mask(0x17, 0x80, 0x80);
+       svga_wseq_mask(0x01, 0x00, 0x20);
+
+       return 0;
+}
+
+/* Set a colour register */
+
+static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                               u_int transp, struct fb_info *fb)
+{
+       switch (fb->var.bits_per_pixel) {
+       case 0:
+       case 4:
+               if (regno >= 16)
+                       return -EINVAL;
+
+               if ((fb->var.bits_per_pixel == 4) &&
+                   (fb->var.nonstd == 0)) {
+                       outb(0xF0, VGA_PEL_MSK);
+                       outb(regno*16, VGA_PEL_IW);
+               } else {
+                       outb(0x0F, VGA_PEL_MSK);
+                       outb(regno, VGA_PEL_IW);
+               }
+               outb(red >> 10, VGA_PEL_D);
+               outb(green >> 10, VGA_PEL_D);
+               outb(blue >> 10, VGA_PEL_D);
+               break;
+       case 8:
+               if (regno >= 256)
+                       return -EINVAL;
+
+               outb(0xFF, VGA_PEL_MSK);
+               outb(regno, VGA_PEL_IW);
+               outb(red >> 10, VGA_PEL_D);
+               outb(green >> 10, VGA_PEL_D);
+               outb(blue >> 10, VGA_PEL_D);
+               break;
+       case 16:
+               if (regno >= 16)
+                       return 0;
+
+               if (fb->var.green.length == 5)
+                       ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+                               ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+               else if (fb->var.green.length == 6)
+                       ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+                               ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+               else
+                       return -EINVAL;
+               break;
+       case 24:
+       case 32:
+               if (regno >= 16)
+                       return 0;
+
+               ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+                       (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Set the display blanking state */
+
+static int arkfb_blank(int blank_mode, struct fb_info *info)
+{
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               pr_debug("fb%d: unblank\n", info->node);
+               svga_wseq_mask(0x01, 0x00, 0x20);
+               svga_wcrt_mask(0x17, 0x80, 0x80);
+               break;
+       case FB_BLANK_NORMAL:
+               pr_debug("fb%d: blank\n", info->node);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(0x17, 0x80, 0x80);
+               break;
+       case FB_BLANK_POWERDOWN:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_VSYNC_SUSPEND:
+               pr_debug("fb%d: sync down\n", info->node);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               svga_wcrt_mask(0x17, 0x00, 0x80);
+               break;
+       }
+       return 0;
+}
+
+
+/* Pan the display */
+
+static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       unsigned int offset;
+
+       /* Calculate the offset */
+       if (var->bits_per_pixel == 0) {
+               offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+               offset = offset >> 2;
+       } else {
+               offset = (var->yoffset * info->fix.line_length) +
+                        (var->xoffset * var->bits_per_pixel / 8);
+               offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+       }
+
+       /* Set the offset */
+       svga_wcrt_multi(ark_start_address_regs, offset);
+
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops arkfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = arkfb_open,
+       .fb_release     = arkfb_release,
+       .fb_check_var   = arkfb_check_var,
+       .fb_set_par     = arkfb_set_par,
+       .fb_setcolreg   = arkfb_setcolreg,
+       .fb_blank       = arkfb_blank,
+       .fb_pan_display = arkfb_pan_display,
+       .fb_fillrect    = arkfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = arkfb_imageblit,
+       .fb_get_caps    = svga_get_caps,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* PCI probe */
+static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct fb_info *info;
+       struct arkfb_info *par;
+       int rc;
+       u8 regval;
+
+       /* Ignore secondary VGA device because there is no VGA arbitration */
+       if (! svga_primary_device(dev)) {
+               dev_info(&(dev->dev), "ignoring secondary device\n");
+               return -ENODEV;
+       }
+
+       /* Allocate and fill driver data structure */
+       info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+       if (! info) {
+               dev_err(&(dev->dev), "cannot allocate memory\n");
+               return -ENOMEM;
+       }
+
+       par = info->par;
+       mutex_init(&par->open_lock);
+
+       info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+       info->fbops = &arkfb_ops;
+
+       /* Prepare PCI device */
+       rc = pci_enable_device(dev);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot enable PCI device\n");
+               goto err_enable_device;
+       }
+
+       rc = pci_request_regions(dev, "arkfb");
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+               goto err_request_regions;
+       }
+
+       par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
+       if (! par->dac) {
+               rc = -ENOMEM;
+               dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+               goto err_dac;
+       }
+
+       info->fix.smem_start = pci_resource_start(dev, 0);
+       info->fix.smem_len = pci_resource_len(dev, 0);
+
+       /* Map physical IO memory address into kernel space */
+       info->screen_base = pci_iomap(dev, 0, 0);
+       if (! info->screen_base) {
+               rc = -ENOMEM;
+               dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+               goto err_iomap;
+       }
+
+       /* FIXME get memsize */
+       regval = vga_rseq(NULL, 0x10);
+       info->screen_size = (1 << (regval >> 6)) << 20;
+       info->fix.smem_len = info->screen_size;
+
+       strcpy(info->fix.id, "ARK 2000PV");
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       info->fix.ypanstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->pseudo_palette = (void*) (par->pseudo_palette);
+
+       /* Prepare startup mode */
+       rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+       if (! ((rc == 1) || (rc == 2))) {
+               rc = -EINVAL;
+               dev_err(&(dev->dev), "mode %s not found\n", mode);
+               goto err_find_mode;
+       }
+
+       rc = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot allocate colormap\n");
+               goto err_alloc_cmap;
+       }
+
+       rc = register_framebuffer(info);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot register framebugger\n");
+               goto err_reg_fb;
+       }
+
+       printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+                pci_name(dev), info->fix.smem_len >> 20);
+
+       /* Record a reference to the driver data */
+       pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+       if (mtrr) {
+               par->mtrr_reg = -1;
+               par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+       }
+#endif
+
+       return 0;
+
+       /* Error handling */
+err_reg_fb:
+       fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+       pci_iounmap(dev, info->screen_base);
+err_iomap:
+       dac_release(par->dac);
+err_dac:
+       pci_release_regions(dev);
+err_request_regions:
+/*     pci_disable_device(dev); */
+err_enable_device:
+       framebuffer_release(info);
+       return rc;
+}
+
+/* PCI remove */
+
+static void __devexit ark_pci_remove(struct pci_dev *dev)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct arkfb_info *par = info->par;
+
+       if (info) {
+#ifdef CONFIG_MTRR
+               if (par->mtrr_reg >= 0) {
+                       mtrr_del(par->mtrr_reg, 0, 0);
+                       par->mtrr_reg = -1;
+               }
+#endif
+
+               dac_release(par->dac);
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+
+               pci_iounmap(dev, info->screen_base);
+               pci_release_regions(dev);
+/*             pci_disable_device(dev); */
+
+               pci_set_drvdata(dev, NULL);
+               framebuffer_release(info);
+       }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct arkfb_info *par = info->par;
+
+       dev_info(&(dev->dev), "suspend\n");
+
+       acquire_console_sem();
+       mutex_lock(&(par->open_lock));
+
+       if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+               mutex_unlock(&(par->open_lock));
+               release_console_sem();
+               return 0;
+       }
+
+       fb_set_suspend(info, 1);
+
+       pci_save_state(dev);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+
+       mutex_unlock(&(par->open_lock));
+       release_console_sem();
+
+       return 0;
+}
+
+
+/* PCI resume */
+
+static int ark_pci_resume (struct pci_dev* dev)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct arkfb_info *par = info->par;
+
+       dev_info(&(dev->dev), "resume\n");
+
+       acquire_console_sem();
+       mutex_lock(&(par->open_lock));
+
+       if (par->ref_count == 0) {
+               mutex_unlock(&(par->open_lock));
+               release_console_sem();
+               return 0;
+       }
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       if (pci_enable_device(dev))
+               goto fail;
+
+       pci_set_master(dev);
+
+       arkfb_set_par(info);
+       fb_set_suspend(info, 0);
+
+       mutex_unlock(&(par->open_lock));
+fail:
+       release_console_sem();
+       return 0;
+}
+#else
+#define ark_pci_suspend NULL
+#define ark_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id ark_devices[] __devinitdata = {
+       {PCI_DEVICE(0xEDD8, 0xA099)},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, ark_devices);
+
+static struct pci_driver arkfb_pci_driver = {
+       .name           = "arkfb",
+       .id_table       = ark_devices,
+       .probe          = ark_pci_probe,
+       .remove         = __devexit_p(ark_pci_remove),
+       .suspend        = ark_pci_suspend,
+       .resume         = ark_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit arkfb_cleanup(void)
+{
+       pr_debug("arkfb: cleaning up\n");
+       pci_unregister_driver(&arkfb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init arkfb_init(void)
+{
+
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("arkfb", &option))
+               return -ENODEV;
+
+       if (option && *option)
+               mode = option;
+#endif
+
+       pr_debug("arkfb: initializing\n");
+       return pci_register_driver(&arkfb_pci_driver);
+}
+
+module_init(arkfb_init);
+module_exit(arkfb_cleanup);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644 (file)
index 0000000..e1d5bd0
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ *  Driver for AT91/AT32 LCD Controller
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg)         __raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)   __raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT                0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN       8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE           2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE           512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define        ATMEL_LCDFB_FBINFO_DEFAULT      FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+                                       struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define        ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
+                                       | FBINFO_PARTIAL_PAN_OK \
+                                       | FBINFO_HWACCEL_XPAN \
+                                       | FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+                                    struct fb_var_screeninfo *var)
+{
+       u32 dma2dcfg;
+       u32 pixeloff;
+
+       pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+       dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+       dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+       lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+       /* Update configuration */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+                   lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+                   | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+       .type           = FB_TYPE_PACKED_PIXELS,
+       .visual         = FB_VISUAL_TRUECOLOR,
+       .xpanstep       = 0,
+       .ypanstep       = 0,
+       .ywrapstep      = 0,
+       .accel          = FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+                              struct fb_var_screeninfo *var)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       struct fb_fix_screeninfo *fix = &info->fix;
+       unsigned long dma_addr;
+
+       dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+                   + var->xoffset * var->bits_per_pixel / 8);
+
+       dma_addr &= ~3UL;
+
+       /* Set framebuffer DMA base address and pixel offset */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+       atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+
+       dma_free_writecombine(info->device, info->fix.smem_len,
+                               info->screen_base, info->fix.smem_start);
+}
+
+/**
+ *     atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ *     @sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+       struct fb_var_screeninfo *var = &info->var;
+
+       info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+                           * ((var->bits_per_pixel + 7) / 8));
+
+       info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+                                       (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+       if (!info->screen_base) {
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ *      atmel_lcdfb_check_var - Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *     Checks to see if the hardware supports the state requested by
+ *     var passed in. This function does not alter the hardware
+ *     state!!!  This means the data stored in struct fb_info and
+ *     struct atmel_lcdfb_info do not change. This includes the var
+ *     inside of struct fb_info.  Do NOT change these. This function
+ *     can be called on its own if we intent to only test a mode and
+ *     not actually set it. The stuff in modedb.c is a example of
+ *     this. If the var passed in is slightly off by what the
+ *     hardware can support then we alter the var PASSED in to what
+ *     we can do. If the hardware doesn't support mode change a
+ *     -EINVAL will be returned by the upper layers. You don't need
+ *     to implement this function then. If you hardware doesn't
+ *     support changing the resolution then this function is not
+ *     needed. In this case the driver would just provide a var that
+ *     represents the static state the screen is in.
+ *
+ *     Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct device *dev = info->device;
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned long clk_value_khz;
+
+       clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+       dev_dbg(dev, "%s:\n", __func__);
+       dev_dbg(dev, "  resolution: %ux%u\n", var->xres, var->yres);
+       dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(var->pixclock));
+       dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
+       dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+       if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+               dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+               return -EINVAL;
+       }
+
+       /* Force same alignment for each line */
+       var->xres = (var->xres + 3) & ~3UL;
+       var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+       var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
+       var->transp.offset = var->transp.length = 0;
+       var->xoffset = var->yoffset = 0;
+
+       switch (var->bits_per_pixel) {
+       case 2:
+       case 4:
+       case 8:
+               var->red.offset = var->green.offset = var->blue.offset = 0;
+               var->red.length = var->green.length = var->blue.length
+                       = var->bits_per_pixel;
+               break;
+       case 15:
+       case 16:
+               var->red.offset = 0;
+               var->green.offset = 5;
+               var->blue.offset = 10;
+               var->red.length = var->green.length = var->blue.length = 5;
+               break;
+       case 24:
+       case 32:
+               var->red.offset = 0;
+               var->green.offset = 8;
+               var->blue.offset = 16;
+               var->red.length = var->green.length = var->blue.length = 8;
+               break;
+       default:
+               dev_err(dev, "color depth %d not supported\n",
+                                       var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ *      atmel_lcdfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *     Using the fb_var_screeninfo in fb_info we set the resolution
+ *     of the this particular framebuffer. This function alters the
+ *     par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ *     not alter var in fb_info since we are using that data. This
+ *     means we depend on the data in var inside fb_info to be
+ *     supported by the hardware.  atmel_lcdfb_check_var is always called
+ *     before atmel_lcdfb_set_par to ensure this.  Again if you can't
+ *     change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned long value;
+       unsigned long clk_value_khz;
+
+       dev_dbg(info->device, "%s:\n", __func__);
+       dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
+                info->var.xres, info->var.yres,
+                info->var.xres_virtual, info->var.yres_virtual);
+
+       /* Turn off the LCD controller and the DMA controller */
+       lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+       if (info->var.bits_per_pixel <= 8)
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+       info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+       /* Re-initialize the DMA engine... */
+       dev_dbg(info->device, "  * update DMA engine\n");
+       atmel_lcdfb_update_dma(info, &info->var);
+
+       /* ...set frame size and burst length = 8 words (?) */
+       value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+       value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+       lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+       /* Now, the LCDC core... */
+
+       /* Set pixel clock */
+       clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+       value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+       if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+               value++;
+
+       value = (value / 2) - 1;
+
+       if (value <= 0) {
+               dev_notice(info->device, "Bypassing pixel clock divider\n");
+               lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+       } else
+               lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+       /* Initialize control register 2 */
+       value = sinfo->default_lcdcon2;
+
+       if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+               value |= ATMEL_LCDC_INVLINE_INVERTED;
+       if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+               value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+       switch (info->var.bits_per_pixel) {
+               case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+               case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+               case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+               case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+               case 15: /* fall through */
+               case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+               case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+               case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+               default: BUG(); break;
+       }
+       dev_dbg(info->device, "  * LCDCON2 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+       /* Vertical timing */
+       value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+       value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+       value |= info->var.lower_margin;
+       dev_dbg(info->device, "  * LCDTIM1 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+       /* Horizontal timing */
+       value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+       value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+       value |= (info->var.left_margin - 1);
+       dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+       /* Display size */
+       value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+       value |= info->var.yres - 1;
+       lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+       /* FIFO Threshold: Use formula from data sheet */
+       value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+       lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+       /* Toggle LCD_MODE every frame */
+       lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+       /* Disable all interrupts */
+       lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+       /* Set contrast */
+       value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+       /* ...wait for DMA engine to become idle... */
+       while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+               msleep(10);
+
+       dev_dbg(info->device, "  * re-enable DMA engine\n");
+       /* ...and enable it with updated configuration */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+       dev_dbg(info->device, "  * re-enable LCDC core\n");
+       lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+               (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+       dev_dbg(info->device, "  * DONE\n");
+
+       return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+/**
+ *     atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *     @green: The green value which can be up to 16 bits wide
+ *     @blue:  The blue value which can be up to 16 bits wide.
+ *     @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *     Set a single color register. The values supplied have a 16 bit
+ *     magnitude which needs to be scaled in this function for the hardware.
+ *     Things to take into consideration are how many color registers, if
+ *     any, are supported with the current color visual. With truecolor mode
+ *     no color palettes are supported. Here a psuedo palette is created
+ *     which we store the value in pseudo_palette in struct fb_info. For
+ *     pseudocolor mode we have a limited color palette. To deal with this
+ *     we can program what color is displayed for a particular pixel value.
+ *     DirectColor is similar in that we can program each color field. If
+ *     we have a static colormap we don't need to implement this function.
+ *
+ *     Returns negative errno on error, or zero on success. In an
+ *     ideal world, this would have been the case, but as it turns
+ *     out, the other drivers return 1 on failure, so that's what
+ *     we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+                            unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned int val;
+       u32 *pal;
+       int ret = 1;
+
+       if (info->var.grayscale)
+               red = green = blue = (19595 * red + 38470 * green
+                                     + 7471 * blue) >> 16;
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               if (regno < 16) {
+                       pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red, &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue, &info->var.blue);
+
+                       pal[regno] = val;
+                       ret = 0;
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               if (regno < 256) {
+                       val  = ((red   >> 11) & 0x001f);
+                       val |= ((green >>  6) & 0x03e0);
+                       val |= ((blue  >>  1) & 0x7c00);
+
+                       /*
+                        * TODO: intensity bit. Maybe something like
+                        *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+                        */
+
+                       lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+                       ret = 0;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       dev_dbg(info->device, "%s\n", __func__);
+
+       atmel_lcdfb_update_dma(info, var);
+
+       return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = atmel_lcdfb_check_var,
+       .fb_set_par     = atmel_lcdfb_set_par,
+       .fb_setcolreg   = atmel_lcdfb_setcolreg,
+       .fb_pan_display = atmel_lcdfb_pan_display,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+       struct fb_info *info = dev_id;
+       struct atmel_lcdfb_info *sinfo = info->par;
+       u32 status;
+
+       status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+       lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+       return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+       int ret = 0;
+
+       memset_io(info->screen_base, 0, info->fix.smem_len);
+       info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+       dev_info(info->device,
+              "%luKiB frame buffer at %08lx (mapped at %p)\n",
+              (unsigned long)info->fix.smem_len / 1024,
+              (unsigned long)info->fix.smem_start,
+              info->screen_base);
+
+       /* Allocate colormap */
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret < 0)
+               dev_err(info->device, "Alloc color map failed\n");
+
+       return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->bus_clk)
+               clk_enable(sinfo->bus_clk);
+       clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->bus_clk)
+               clk_disable(sinfo->bus_clk);
+       clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fb_info *info;
+       struct atmel_lcdfb_info *sinfo;
+       struct atmel_lcdfb_info *pdata_sinfo;
+       struct resource *regs = NULL;
+       struct resource *map = NULL;
+       int ret;
+
+       dev_dbg(dev, "%s BEGIN\n", __func__);
+
+       ret = -ENOMEM;
+       info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+       if (!info) {
+               dev_err(dev, "cannot allocate memory\n");
+               goto out;
+       }
+
+       sinfo = info->par;
+
+       if (dev->platform_data) {
+               pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+               sinfo->default_bpp = pdata_sinfo->default_bpp;
+               sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+               sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+               sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+               sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+               sinfo->guard_time = pdata_sinfo->guard_time;
+       } else {
+               dev_err(dev, "cannot get default configuration\n");
+               goto free_info;
+       }
+       sinfo->info = info;
+       sinfo->pdev = pdev;
+
+       strcpy(info->fix.id, sinfo->pdev->name);
+       info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+       info->pseudo_palette = sinfo->pseudo_palette;
+       info->fbops = &atmel_lcdfb_ops;
+
+       memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+       info->fix = atmel_lcdfb_fix;
+
+       /* Enable LCDC Clocks */
+       if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+               sinfo->bus_clk = clk_get(dev, "hck1");
+               if (IS_ERR(sinfo->bus_clk)) {
+                       ret = PTR_ERR(sinfo->bus_clk);
+                       goto free_info;
+               }
+       }
+       sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+       if (IS_ERR(sinfo->lcdc_clk)) {
+               ret = PTR_ERR(sinfo->lcdc_clk);
+               goto put_bus_clk;
+       }
+       atmel_lcdfb_start_clock(sinfo);
+
+       ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+                       info->monspecs.modedb_len, info->monspecs.modedb,
+                       sinfo->default_bpp);
+       if (!ret) {
+               dev_err(dev, "no suitable video mode found\n");
+               goto stop_clk;
+       }
+
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_err(dev, "resources unusable\n");
+               ret = -ENXIO;
+               goto stop_clk;
+       }
+
+       sinfo->irq_base = platform_get_irq(pdev, 0);
+       if (sinfo->irq_base < 0) {
+               dev_err(dev, "unable to get irq\n");
+               ret = sinfo->irq_base;
+               goto stop_clk;
+       }
+
+       /* Initialize video memory */
+       map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (map) {
+               /* use a pre-allocated memory buffer */
+               info->fix.smem_start = map->start;
+               info->fix.smem_len = map->end - map->start + 1;
+               if (!request_mem_region(info->fix.smem_start,
+                                       info->fix.smem_len, pdev->name)) {
+                       ret = -EBUSY;
+                       goto stop_clk;
+               }
+
+               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+               if (!info->screen_base)
+                       goto release_intmem;
+       } else {
+               /* alocate memory buffer */
+               ret = atmel_lcdfb_alloc_video_memory(sinfo);
+               if (ret < 0) {
+                       dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+                       goto stop_clk;
+               }
+       }
+
+       /* LCDC registers */
+       info->fix.mmio_start = regs->start;
+       info->fix.mmio_len = regs->end - regs->start + 1;
+
+       if (!request_mem_region(info->fix.mmio_start,
+                               info->fix.mmio_len, pdev->name)) {
+               ret = -EBUSY;
+               goto free_fb;
+       }
+
+       sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+       if (!sinfo->mmio) {
+               dev_err(dev, "cannot map LCDC registers\n");
+               goto release_mem;
+       }
+
+       /* interrupt */
+       ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+       if (ret) {
+               dev_err(dev, "request_irq failed: %d\n", ret);
+               goto unmap_mmio;
+       }
+
+       ret = atmel_lcdfb_init_fbinfo(sinfo);
+       if (ret < 0) {
+               dev_err(dev, "init fbinfo failed: %d\n", ret);
+               goto unregister_irqs;
+       }
+
+       /*
+        * This makes sure that our colour bitfield
+        * descriptors are correctly initialised.
+        */
+       atmel_lcdfb_check_var(&info->var, info);
+
+       ret = fb_set_var(info, &info->var);
+       if (ret) {
+               dev_warn(dev, "unable to set display parameters\n");
+               goto free_cmap;
+       }
+
+       dev_set_drvdata(dev, info);
+
+       /*
+        * Tell the world that we're ready to go
+        */
+       ret = register_framebuffer(info);
+       if (ret < 0) {
+               dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+               goto free_cmap;
+       }
+
+       /* Power up the LCDC screen */
+       if (sinfo->atmel_lcdfb_power_control)
+               sinfo->atmel_lcdfb_power_control(1);
+
+       dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+                      info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+       return 0;
+
+
+free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+       free_irq(sinfo->irq_base, info);
+unmap_mmio:
+       iounmap(sinfo->mmio);
+release_mem:
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+       if (map)
+               iounmap(info->screen_base);
+       else
+               atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+       if (map)
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+       atmel_lcdfb_stop_clock(sinfo);
+       clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+       if (sinfo->bus_clk)
+               clk_put(sinfo->bus_clk);
+free_info:
+       framebuffer_release(info);
+out:
+       dev_dbg(dev, "%s FAILED\n", __func__);
+       return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct atmel_lcdfb_info *sinfo = info->par;
+
+       if (!sinfo)
+               return 0;
+
+       if (sinfo->atmel_lcdfb_power_control)
+               sinfo->atmel_lcdfb_power_control(0);
+       unregister_framebuffer(info);
+       atmel_lcdfb_stop_clock(sinfo);
+       clk_put(sinfo->lcdc_clk);
+       if (sinfo->bus_clk)
+               clk_put(sinfo->bus_clk);
+       fb_dealloc_cmap(&info->cmap);
+       free_irq(sinfo->irq_base, info);
+       iounmap(sinfo->mmio);
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+       if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+               iounmap(info->screen_base);
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
+       } else {
+               atmel_lcdfb_free_video_memory(sinfo);
+       }
+
+       dev_set_drvdata(dev, NULL);
+       framebuffer_release(info);
+
+       return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+       .remove         = __exit_p(atmel_lcdfb_remove),
+       .driver         = {
+               .name   = "atmel_lcdfb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+       return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+       platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
index ea67dd902d4ea32654bd17efae35630a1ebdfcaa..8d3455da663aa6261545e6368e5fab78f8edd081 100644 (file)
@@ -80,8 +80,9 @@
 #include "../macmodes.h"
 #endif
 #ifdef __sparc__
-#include <asm/pbm.h>
 #include <asm/fbio.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
 #endif
 
 #ifdef CONFIG_ADB_PMU
index 2a7f381c330feb102bc17e0a4332e52205fc0ae3..fe2c6ad01a8d1ffaeb096262b70baafac86eede1 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/uaccess.h>
 
 #ifdef __sparc__
-#include <asm/pbm.h>
 #include <asm/fbio.h>
 #endif
 
index aa3935df852ad6f9f04f1fce4c53091c8f0f8511..63b85bf81a651d808ab486ebb37b2bc3703c423c 100644 (file)
@@ -19,13 +19,6 @@ config VGA_CONSOLE
 
          Say Y.
 
-#      if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
-#         bool '   Allow VGA on any bus?' CONFIG_VGA_HOSE
-#         if [ "$CONFIG_VGA_HOSE" = "y" ]; then
-#            define_bool CONFIG_DUMMY_CONSOLE y
-#         fi
-#      fi
-
 config VGACON_SOFT_SCROLLBACK
        bool "Enable Scrollback Buffer in System RAM"
        depends on VGA_CONSOLE
index f577bd80e020ee832c28657629128d57cd7a73f7..03cfb7ac5733fd19af0d287d03d003d41f081c05 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/video/softcursor.c
+ * linux/drivers/video/console/softcursor.c
  *
  * Generic software cursor for frame buffer devices
  *
index 08d4e11d9121dc88ef3fba254e848c96f3c4c74b..38c2e2558f5e34ac8285ca91253b204e9ae4cc51 100644 (file)
@@ -1236,6 +1236,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
        pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
 #elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+       vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+                                     & ~_PAGE_CACHABLE)
+                                    | (_PAGE_BUFFER | _PAGE_DIRTY));
 #elif defined(__ia64__)
        if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
                vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
index 7e760197cf29a9932e6533641da3919fc597ca51..1a7d7789d8772f600c6bb3100b86b50b68a45dab 100644 (file)
@@ -1717,7 +1717,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
  * @info: pointer to device specific info structure
  *
  * DESCRIPTION:
- * Sets the the user monitor's horizontal and vertical
+ * Sets the user monitor's horizontal and vertical
  * frequency limits
  */
 static void __devinit i810_init_monspecs(struct fb_info *info)
index a5690a5f29d585f69f069c43e7b783af8f494475..9445cdb759b1f090d21ffa6bb1a30bde8dccfbe5 100644 (file)
@@ -72,7 +72,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *              FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
index a5c825d994661090c990e6423fb6245a063902b1..c57aaadf410c9d5a6cfe030282315311aecbb585 100644 (file)
@@ -70,7 +70,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *              FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
index cb2aa402ddfd93eb0b180f9a05c74909c2be859a..c8559a756b75ff5bbe017c43cea941160d002168 100644 (file)
@@ -93,7 +93,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *              FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
index 18886b629cb1bb3c8fcea5cb9a0f4132f0fdb20c..5948e54b9ef9ceb68e2914a30f7600667c771569 100644 (file)
@@ -78,7 +78,7 @@
  *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
  *
  * (following author is not in any relation with this code, but his ideas
- *  were used when writting this driver)
+ *  were used when writing this driver)
  *
  *              FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
  *
index f297c7b14a412117b2de672e68e47de9f96fb252..aff11bbf59a74c3f309e8dd0848b5c55e307afa8 100644 (file)
@@ -150,7 +150,8 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
                M = pll & 0xFF;
                N = (pll >> 8) & 0xFF;
                if (((par->Chipset & 0xfff0) == 0x0290) ||
-                               ((par->Chipset & 0xfff0) == 0x0390)) {
+                       ((par->Chipset & 0xfff0) == 0x0390) ||
+                       ((par->Chipset & 0xfff0) == 0x02E0)) {
                        MB = 1;
                        NB = 1;
                } else {
@@ -963,6 +964,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
 
                if (((par->Chipset & 0xfff0) == 0x0090) ||
                    ((par->Chipset & 0xfff0) == 0x01D0) ||
+                   ((par->Chipset & 0xfff0) == 0x02E0) ||
                    ((par->Chipset & 0xfff0) == 0x0290))
                        regions = 15;
                for(i = 0; i < regions; i++) {
@@ -1275,6 +1277,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
                                                0x00100000);
                                        break;
                                case 0x0090:
+                               case 0x02E0:
                                case 0x0290:
                                        NV_WR32(par->PRAMDAC, 0x0608,
                                                NV_RD32(par->PRAMDAC, 0x0608) |
@@ -1352,6 +1355,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
                        } else {
                                if (((par->Chipset & 0xfff0) == 0x0090) ||
                                    ((par->Chipset & 0xfff0) == 0x01D0) ||
+                                   ((par->Chipset & 0xfff0) == 0x02E0) ||
                                    ((par->Chipset & 0xfff0) == 0x0290)) {
                                        for (i = 0; i < 60; i++) {
                                                NV_WR32(par->PGRAPH,
@@ -1403,6 +1407,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
                                } else {
                                        if ((par->Chipset & 0xfff0) == 0x0090 ||
                                            (par->Chipset & 0xfff0) == 0x01D0 ||
+                                           (par->Chipset & 0xfff0) == 0x02E0 ||
                                            (par->Chipset & 0xfff0) == 0x0290) {
                                                NV_WR32(par->PGRAPH, 0x0DF0,
                                                        NV_RD32(par->PFB, 0x0200));
index 7c36b5fe582eeee8ef80de28bc85b0a20d9eca1e..41f63658572fa7f7ea59b8e65a69950cdb522b78 100644 (file)
@@ -37,7 +37,6 @@
 #include "nv_proto.h"
 #include "nv_dma.h"
 
-#undef CONFIG_FB_NVIDIA_DEBUG
 #ifdef CONFIG_FB_NVIDIA_DEBUG
 #define NVTRACE          printk
 #else
@@ -1243,6 +1242,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
        case 0x0140:            /* GeForce 6600 */
        case 0x0160:            /* GeForce 6200 */
        case 0x01D0:            /* GeForce 7200, 7300, 7400 */
+       case 0x02E0:            /* GeForce 7300 GT */
        case 0x0090:            /* GeForce 7800 */
        case 0x0210:            /* GeForce 6800 */
        case 0x0220:            /* GeForce 6200 */
index 1ac5264bb2c150cdfeee12b5c43203aab6bcc7c1..ab5e66890e4e7f3f60a04e0cfda7acd841c828f8 100644 (file)
@@ -204,17 +204,6 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
 }
 #endif
 
-static void wait_pm2(struct pm2fb_par* par) {
-
-       WAIT_FIFO(par, 1);
-       pm2_WR(par, PM2R_SYNC, 0);
-       mb();
-       do {
-               while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
-               rmb();
-       } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
-}
-
 /*
  * partial products for the supported horizontal resolutions.
  */
@@ -1050,13 +1039,30 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
        return 0;
 }
 
+static int pm2fb_sync(struct fb_info *info)
+{
+       struct pm2fb_par *par = info->par;
+
+       WAIT_FIFO(par, 1);
+       pm2_WR(par, PM2R_SYNC, 0);
+       mb();
+       do {
+               while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
+                       udelay(10);
+               rmb();
+       } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+
+       return 0;
+}
+
 /*
  * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
  */
-static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+static void pm2fb_block_op(struct fb_info* info, int copy,
                                s32 xsrc, s32 ysrc,
                                s32 x, s32 y, s32 w, s32 h,
                                u32 color) {
+       struct pm2fb_par *par = info->par;
 
        if (!w || !h)
                return;
@@ -1076,13 +1082,11 @@ static void pm2fb_block_op(struct pm2fb_par* par, int copy,
                                (x<xsrc ? PM2F_INCREASE_X : 0) |
                                (y<ysrc ? PM2F_INCREASE_Y : 0) |
                                (copy ? 0 : PM2F_RENDER_FASTFILL));
-       wait_pm2(par);
 }
 
 static void pm2fb_fillrect (struct fb_info *info,
                                const struct fb_fillrect *region)
 {
-       struct pm2fb_par *par = info->par;
        struct fb_fillrect modded;
        int vxres, vyres;
        u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
@@ -1116,7 +1120,7 @@ static void pm2fb_fillrect (struct fb_info *info,
                color |= color << 16;
 
        if(info->var.bits_per_pixel != 24)
-               pm2fb_block_op(par, 0, 0, 0,
+               pm2fb_block_op(info, 0, 0, 0,
                                modded.dx, modded.dy,
                                modded.width, modded.height, color);
        else
@@ -1126,7 +1130,6 @@ static void pm2fb_fillrect (struct fb_info *info,
 static void pm2fb_copyarea(struct fb_info *info,
                                const struct fb_copyarea *area)
 {
-       struct pm2fb_par *par = info->par;
        struct fb_copyarea modded;
        u32 vxres, vyres;
 
@@ -1156,7 +1159,7 @@ static void pm2fb_copyarea(struct fb_info *info,
        if(modded.dy + modded.height > vyres)
                modded.height = vyres - modded.dy;
 
-       pm2fb_block_op(par, 1, modded.sx, modded.sy,
+       pm2fb_block_op(info, 1, modded.sx, modded.sy,
                        modded.dx, modded.dy,
                        modded.width, modded.height, 0);
 }
@@ -1177,6 +1180,7 @@ static struct fb_ops pm2fb_ops = {
        .fb_fillrect    = pm2fb_fillrect,
        .fb_copyarea    = pm2fb_copyarea,
        .fb_imageblit   = cfb_imageblit,
+       .fb_sync        = pm2fb_sync,
 };
 
 /*
index bd787e80177d332c29357ab86420337de9a2585e..6c4dfcb0feb9b3008431b6c4be54da6d202297fb 100644 (file)
@@ -1,55 +1,25 @@
 /*
  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
- *  
- *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *
+ *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
+ *
+ *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
+ *     based on pm2fb.c
+ *
  *  Based on code written by:
- *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
- *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
- *           Russell King, <rmk@arm.linux.org.uk>
+ *        Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *        Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ *        Russell King, <rmk@arm.linux.org.uk>
  *  Based on linux/drivers/video/skeletonfb.c:
  *     Copyright (C) 1997 Geert Uytterhoeven
  *  Based on linux/driver/video/pm2fb.c:
- *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ *     Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ *     Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
  *
  *  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.
  *
- *  $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
- *  CHANGELOG:
- *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
- *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
- *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
- *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
- *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
- *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
- *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
- *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
- *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
- *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
- *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
- *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
- *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
- *  Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
- *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
- *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
- *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
- *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
- *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
- *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
- *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
- *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
- *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
- *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
- *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
- *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
- *  Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
- *  Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
- *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
- *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
- *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
  */
 
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/ctype.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#include <video/pm3fb.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <video/pm3fb.h>
 
-#ifdef CONFIG_FB_OF
-#include <asm/prom.h>
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
 #endif
 
-/* ************************************* */
-/* ***** The various "global" data ***** */
-/* ************************************* */
-
-/* those will need a rework for multiple board support */
-/* Driver name */
-static const char permedia3_name[16] = "Permedia3";
-
-/* the fb_par struct, mandatory */
-struct pm3fb_par {
-       u32 pixclock;           /* pixclock in KHz */
-
-       u32 width;              /* width of virtual screen */
-       u32 height;             /* height of virtual screen */
-
-       u32 hsstart;            /* horiz. sync start */
-       u32 hsend;              /* horiz. sync end */
-       u32 hbend;              /* horiz. blank end (also gate end) */
-       u32 htotal;             /* total width (w/ sync & blank) */
-
-       u32 vsstart;            /* vert. sync start */
-       u32 vsend;              /* vert. sync end */
-       u32 vbend;              /* vert. blank end */
-       u32 vtotal;             /* total height (w/ sync & blank) */
-
-       u32 stride;             /* screen stride */
-       u32 base;               /* screen base (xoffset+yoffset) in 128 bits unit */
-       /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
-       u32 depth;              /* screen depth (8, 12, 15, 16 or 32) */
-       u32 video;              /* video control (hsync,vsync) */
-};
-
-/* memory timings */
-struct pm3fb_timings
-{
-       unsigned long caps;
-       unsigned long timings;
-       unsigned long control;
-       unsigned long refresh;
-       unsigned long powerdown;
-};
-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
-#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
-#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
-
-/* the fb_info struct, mandatory */
-struct pm3fb_info {
-       struct fb_info_gen gen;
-       unsigned long board_num; /* internal board number */
-       unsigned long use_current;
-       struct pm3fb_par *current_par;
-       struct pci_dev *dev;    /* PCI device */
-       unsigned long board_type; /* index in the cardbase */
-       unsigned char *fb_base; /* framebuffer memory base */
-       u32 fb_size;            /* framebuffer memory size */
-       unsigned char *p_fb;    /* physical address of frame buffer */
-       unsigned char *v_fb;    /* virtual address of frame buffer */
-       unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
-       unsigned char *vIOBase; /* address of registers after ioremap() */
-       struct {
-               u8 transp;
-               u8 red;
-               u8 green;
-               u8 blue;
-       } palette[256];
-       union {
-#ifdef FBCON_HAS_CFB16
-               u16 cmap12[16]; /* RGBA 4444 */
-               u16 cmap15[16]; /* RGBA 5551 */
-               u16 cmap16[16]; /* RGBA 5650 */
-#endif
-#ifdef FBCON_HAS_CFB32
-               u32 cmap32[16];
+#undef PM3FB_MASTER_DEBUG
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(a,b...)        printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
 #endif
-       } cmap;
-       struct pm3fb_timings memt;
-};
-
-/* regular resolution database*/
-static struct {
-       char name[16];
-       struct pm3fb_par user_mode;
-} mode_base[] __initdata = {
-       {
-               "default-800x600", {
-       49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}}, {
-               "1024x768-74", {
-       78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}}, {
-               "1024x768-74-32", {
-                       78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-                       806, 1024, 0, 32,
-                       PM3VideoControl_ENABLE |
-                       PM3VideoControl_HSYNC_ACTIVE_HIGH
-                       |
-                       PM3VideoControl_VSYNC_ACTIVE_HIGH
-                       | PM3VideoControl_PIXELSIZE_32BIT}},
-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
-       {
-               "SGI1600SW", {
-                       108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
-                       1056, 1600, 0, 8,
-                       PM3VideoControl_ENABLE|
-                       PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
-                       PM3VideoControl_PIXELSIZE_32BIT}}, 
-/* ##### auto-generated mode, by fbtimings2pm3 */
-/* Generated mode : "640x480-60" */
-       {
-               "640x480-60", {
-       25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
-                           525, 640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-72" */
-       {
-               "640x480-72", {
-       31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-75" */
-       {
-               "640x480-75", {
-       31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-90" */
-       {
-               "640x480-90", {
-       39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-100" */
-       {
-               "640x480-100", {
-       44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
-                           531, 640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-48-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "800x600-56" */
-       {
-               "800x600-56", {
-       35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-60" */
-       {
-               "800x600-60", {
-       40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-70" */
-       {
-               "800x600-70", {
-       44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
-                           636, 800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-72" */
-       {
-               "800x600-72", {
-       50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
-                           666, 800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-75" */
-       {
-               "800x600-75", {
-       49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-90" */
-       {
-               "800x600-90", {
-       56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-100", from /etc/fb.modes */
-/* DISABLED, hsstart == 0
-       {
-               "800x600-100", {
-       67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "800x600-100", from ??? */
-       {
-               "800x600-100", {
-                       69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
-                       PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-                       PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1024x768-60" */
-       {
-               "1024x768-60", {
-       64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-70" */
-       {
-               "1024x768-70", {
-       74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-72" */
-       {
-               "1024x768-72", {
-       74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
-                           806, 10224, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-75" */
-       {
-               "1024x768-75", {
-       78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
-                           800, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-90" */
-       {
-               "1024x768-90", {
-       100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
-                           845, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-100", from /etc/fb.modes */
-/* DISABLED, vsstart == 0
-       {
-               "1024x768-100", {
-       109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
-                           1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "1024x768-100", from ??? */
-       {
-               "1024x768-100", {
-                       115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
-                       PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-                       PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-60" */
-       {
-               "1152x864-60", {
-       80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
-                           916, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-70" */
-       {
-               "1152x864-70", {
-       100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
-                           945, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-75" */
-       {
-               "1152x864-75", {
-       109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
-                           1002, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-80" */
-       {
-               "1152x864-80", {
-       109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
-                           958, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-60" */
-       {
-               "1280x1024-60", {
-       107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-70" */
-       {
-               "1280x1024-70", {
-       125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-74" */
-       {
-               "1280x1024-74", {
-       134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
-                           1064, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-75" */
-       {
-               "1280x1024-75", {
-       134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-60" */
-       {
-               "1600x1200-60", {
-       155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
-                           1270, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-66" */
-       {
-               "1600x1200-66", {
-       171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
-                           1253, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-76" */
-       {
-               "1600x1200-76", {
-       197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
-                           1250, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* ##### end of auto-generated mode */
-       {
-       "\0",}
-};
 
-/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
-static struct pm3fb_info fb_info[PM3_MAX_BOARD];
-static struct pm3fb_par current_par[PM3_MAX_BOARD];
-static int current_par_valid[PM3_MAX_BOARD];
-/* to allow explicit filtering of board */
-short bus[PM3_MAX_BOARD];
-short slot[PM3_MAX_BOARD];
-short func[PM3_MAX_BOARD];
-short disable[PM3_MAX_BOARD];
-short noaccel[PM3_MAX_BOARD];
-char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
-short depth[PM3_MAX_BOARD];
-short flatpanel[PM3_MAX_BOARD];
-static struct display disp[PM3_MAX_BOARD];
-static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
-short printtimings = 0;
-short forcesize[PM3_MAX_BOARD];
-
-/* ********************* */
-/* ***** prototype ***** */
-/* ********************* */
-/* card-specific */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
-/* permedia3-specific */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-                                       unsigned long r);
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,        /* In kHz units */
-                                         unsigned long refclock,       /* In kHz units */
-                                         unsigned char *prescale,      /* ClkPreScale */
-                                         unsigned char *feedback,      /* ClkFeedBackScale */
-                                         unsigned char *postscale
-                                         /* ClkPostScale */ );
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-                         unsigned long depth, int v);
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-                           unsigned long depth, int v);
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
-#endif
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
-                           struct pm3fb_par *curpar);
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
-/* accelerated permedia3-specific */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width);
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width);
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
-                            struct display *p,
-                            int sy, int sx, int height, int width);
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
-                                    struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
-                            int sy, int sx,
-                            int dy, int dx, int height, int width);
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
-                           int c, int yy, int xx);
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
-                            const unsigned short *s, int count, int yy,
-                            int xx);
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* pre-init */
-static void pm3fb_mode_setup(char *mode, unsigned long board_num);
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
-static void pm3fb_real_setup(char *options);
-/* fbdev */
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
-                           const void *par, struct fb_info_gen *info);
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
-                           void *par, struct fb_info_gen *info);
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
-                           const void *par, struct fb_info_gen *info);
-static void pm3fb_get_par(void *par, struct fb_info_gen *info);
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
-                           unsigned char regno, unsigned char r,
-                           unsigned char g, unsigned char b);
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-                          unsigned *blue, unsigned *transp,
-                          struct fb_info *info);
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                          unsigned blue, unsigned transp,
-                          struct fb_info *info);
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
-static void pm3fb_set_disp(const void *par, struct display *disp,
-                          struct fb_info_gen *info);
-static void pm3fb_detect(void);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
-                            struct fb_info_gen *info);
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-
-
-/* the struct that hold them together */
-struct fbgen_hwswitch pm3fb_switch = {
-       pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
-       pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
-       pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
+/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
 
-static struct fb_ops pm3fb_ops = {
-       .owner =        THIS_MODULE,
-       .fb_get_fix =   fbgen_get_fix,
-       .fb_get_var =   fbgen_get_var,
-       .fb_set_var =   fbgen_set_var,
-       .fb_get_cmap =  fbgen_get_cmap,
-       .fb_set_cmap =  fbgen_set_cmap,
-       .fb_setcolreg = pm3fb_setcolreg,
-       .fb_pan_display =fbgen_pan_display,
-       .fb_blank =     fbgen_blank,
-       .fb_ioctl =     pm3fb_ioctl,
-};
+/*
+ *  If your driver supports multiple boards, you should make the
+ *  below data types arrays, or allocate them dynamically (using kmalloc()).
+ */
 
-#ifdef PM3FB_USE_ACCEL
-#ifdef FBCON_HAS_CFB32
-static struct display_switch pm3fb_cfb32 = {
-       fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb32_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static struct display_switch pm3fb_cfb16 = {
-       fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb16_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static struct display_switch pm3fb_cfb8 = {
-       fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb8_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB8 */
-#endif /* PM3FB_USE_ACCEL */
-
-/* ****************************** */
-/* ***** card-specific data ***** */
-/* ****************************** */
-struct pm3fb_card_timings {
-       unsigned long memsize; /* 0 for last value (i.e. default) */
-       struct pm3fb_timings memt;
+/*
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to
+ * avoid duplicate work and easy porting of software.
+ */
+struct pm3_par {
+       unsigned char   __iomem *v_regs;/* virtual address of p_regs */
+       u32             video;          /* video flags before blanking */
+       u32             base;           /* screen base (xoffset+yoffset) in 128 bits unit */
+       u32             palette[16];
 };
 
-static struct pm3fb_card_timings t_FormacProFormance3[] = {
-       { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
-       { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well.
+ */
+static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+       .id =           "Permedia3",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_PSEUDOCOLOR,
+       .xpanstep =     1,
+       .ypanstep =     1,
+       .ywrapstep =    0,
+       .accel =        FB_ACCEL_NONE,
 };
 
-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
-       { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
-       { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
-};
+/*
+ * Utility functions
+ */
 
-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
-       { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
-       { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
-};
+static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
+{
+       return fb_readl(par->v_regs + off);
+}
 
-static struct {
-               char cardname[32]; /* recognized card name */
-               u16 subvendor; /* subvendor of the card */
-               u16 subdevice; /* subdevice of the card */
-               u8  func; /* function of the card to which the extra init apply */
-               void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
-       struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
-} cardbase[] = {
-       { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
-       { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
-         t_AppianJeronimo2000
-       },
-       { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
-         t_AppianJeronimo2000
-       },
-       { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
-         t_FormacProFormance3
-       },
-       { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
-         t_3DLabsOxygenVX1
-       },
-       { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
-       { "\0", 0x0, 0x0, 0, NULL, NULL }
-};
+static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
+{
+       fb_writel(v, par->v_regs + off);
+}
 
-/* ********************************** */
-/* ***** card-specific function ***** */
-/* ********************************** */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
-{       /* the appian j2000 require more initialization of the second head */
-       /* l_fb_info must point to the _second_ head of the J2000 */
-       
-       DTRACE;
-
-       l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
-       
-       pm3fb_write_memory_timings(l_fb_info);
+static inline void PM3_WAIT(struct pm3_par *par, u32 n)
+{
+       while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
 }
 
-/* *************************************** */
-/* ***** permedia3-specific function ***** */
-/* *************************************** */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
 {
-       l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
-       l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
-       l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
-       l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
-       l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
-
-       if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
-       {
-               printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
-               return(pm3fb_try_memory_timings(l_fb_info));
+       if (par->v_regs) {
+               mb();
+               PM3_WAIT(par, 1);
+               wmb();
+               PM3_WRITE_REG(par, off, v);
        }
-       return(pm3fb_timing_ok);
 }
 
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index)
 {
-       if (cardbase[l_fb_info->board_type].c_memt)
-       {
-               int i = 0, done = 0;
-               while (!done)
-               {
-                       if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
-                           || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
-                       { /* will use the 0-sized timings by default */
-                               done = 1;
-                               l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
-                               printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
-                                      l_fb_info->board_num,
-                                      cardbase[l_fb_info->board_type].cardname,
-                                      cardbase[l_fb_info->board_type].c_memt[i].memsize);
-                               pm3fb_write_memory_timings(l_fb_info);
-                               return(pm3fb_timing_retry);
-                       }
-                       i++;
-               }
-       } else
-               return(pm3fb_timing_problem);
-       return(pm3fb_timing_ok);
+       PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff);
+       PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff);
 }
 
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
 {
-       unsigned char m, n, p;
-       unsigned long clockused;
-       
-       PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
-       PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
-       PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
-       PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
-       PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
-
-       clockused =
-           pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
-                                &n, &p);
-
-       PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
-       PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
-       PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
-       PM3_WRITE_DAC_REG(PM3RD_KClkControl,
-                         PM3RD_KClkControl_STATE_RUN |
-                         PM3RD_KClkControl_SOURCE_PLL |
-                         PM3RD_KClkControl_ENABLE);
-       PM3_WRITE_DAC_REG(PM3RD_MClkControl,
-                         PM3RD_MClkControl_STATE_RUN |
-                         PM3RD_MClkControl_SOURCE_KCLK |
-                         PM3RD_MClkControl_ENABLE);
-       PM3_WRITE_DAC_REG(PM3RD_SClkControl,
-                         PM3RD_SClkControl_STATE_RUN |
-                         PM3RD_SClkControl_SOURCE_PCLK |
-                         PM3RD_SClkControl_ENABLE);
+       PM3_SET_INDEX(par, r);
+       wmb();
+       PM3_WRITE_REG(par, PM3RD_IndexedData, v);
 }
 
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-                                       unsigned long r)
+static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
+                       unsigned char r, unsigned char g, unsigned char b)
 {
-       DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
-               "l_fb_info->vIOBase mapped in read dac reg\n");
-       PM3_SET_INDEX(r);
-       mb();
-       return (PM3_READ_REG(PM3RD_IndexedData));
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b);
+}
+
+static void pm3fb_clear_colormap(struct pm3_par *par,
+                       unsigned char r, unsigned char g, unsigned char b)
+{
+       int i;
+
+       for (i = 0; i < 256 ; i++) /* fill color map with white */
+               pm3fb_set_color(par, i, r, g, b);
+
 }
 
 /* Calculating various clock parameter */
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,        /* In kHz units */
-                                         unsigned long refclock,       /* In kHz units */
-                                         unsigned char *prescale,      /* ClkPreScale */
-                                         unsigned char *feedback,      /* ClkFeedBackScale */
-                                         unsigned char *postscale
-                                         /* ClkPostScale */ )
+static void pm3fb_calculate_clock(unsigned long reqclock,
+                               unsigned char *prescale,
+                               unsigned char *feedback,
+                               unsigned char *postscale)
 {
        int f, pre, post;
        unsigned long freq;
        long freqerr = 1000;
-       unsigned long actualclock = 0;
-
-       DTRACE;
+       long currerr;
 
        for (f = 1; f < 256; f++) {
                for (pre = 1; pre < 256; pre++) {
                        for (post = 0; post < 5; post++) {
-                               freq =
-                                   ((2 * refclock * f) /
-                                    (pre * (1 << post)));
-                               if ((reqclock > freq - freqerr)
-                                   && (reqclock < freq + freqerr)) {
-                                       freqerr =
-                                           (reqclock >
-                                            freq) ? reqclock -
-                                           freq : freq - reqclock;
+                               freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
+                               currerr = (reqclock > freq)
+                                       ? reqclock - freq
+                                       : freq - reqclock;
+                               if (currerr < freqerr) {
+                                       freqerr = currerr;
                                        *feedback = f;
                                        *prescale = pre;
                                        *postscale = post;
-                                       actualclock = freq;
                                }
                        }
                }
        }
-
-       return (actualclock);
 }
 
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-                         unsigned long depth, int v)
+static inline int pm3fb_shift_bpp(unsigned long depth, int v)
 {
-       DTRACE;
-       
        switch (depth) {
        case 8:
                return (v >> 4);
@@ -918,181 +187,59 @@ static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
        case 32:
                return (v >> 2);
        }
-       DPRINTK(1, "Unsupported depth %ld\n", depth);
-       return (0);
-}
-
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-                           unsigned long depth, int v)
-{
-       DTRACE;
-
-       switch (depth) {
-       case 8:
-               return (v << 4);
-       case 12:        
-       case 15:
-       case 16:
-               return (v << 3);
-       case 32:
-               return (v << 2);
-       }
-       DPRINTK(1, "Unsupported depth %ld\n", depth);
-       return (0);
-}
-
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
-{
-       DTRACE;
-
-       l_fb_info->vIOBase =
-           ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
-       l_fb_info->v_fb =
-           ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
-       DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
-               (unsigned long) l_fb_info->pIOBase,
-               (unsigned long) l_fb_info->vIOBase,
-               (unsigned long) l_fb_info->p_fb,
-               (unsigned long) l_fb_info->v_fb);
-}
-
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
-{
-       DTRACE;
-
-       iounmap(l_fb_info->vIOBase);
-       iounmap(l_fb_info->v_fb);
-       l_fb_info->vIOBase = (unsigned char *) -1;
-       l_fb_info->v_fb = (unsigned char *) -1;
-}
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
-{
-       DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
-       DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
-       DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
-               PM3_READ_REG(PM3ByAperture1Mode));
-       DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
-               PM3_READ_REG(PM3ByAperture2Mode));
-       DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
-       DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
-       DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
-       DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
-       DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
-       DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
-       DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
-       DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
-               PM3_READ_REG(PM3MemBypassWriteMask));
-       DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
-               PM3_READ_REG(PM3RD_IndexControl));
-       DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
-       DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
-               PM3_READ_REG(PM3ScreenStride));
-       DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
-       DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
-       DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
-       DPRINTK(2, "PM3VideoControl: 0x%08x\n",
-               PM3_READ_REG(PM3VideoControl));
-       DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
-       DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
-
-       DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_ColorFormat));
-       DPRINTK(2, "PM3RD_DACControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DACControl));
-       DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
-       DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
-       DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
-       DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_IndexControl));
-       DPRINTK(2, "PM3RD_MiscControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_MiscControl));
-       DPRINTK(2, "PM3RD_PixelSize: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_PixelSize));
-       DPRINTK(2, "PM3RD_SyncControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_SyncControl));
-}
-
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
-{
-       u16 subvendor, subdevice;
-
-       if ((!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
-           &&
-           (!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
-               /* well, nothing... */
-       } else {
-               subvendor = subdevice = (u16)-1;
-       }
-
-       printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
-       printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemCaps));
-       printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemTimings));
-       printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemControl));
-       printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemRefresh));
-       printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemPowerDown));
+       DPRINTK("Unsupported depth %ld\n", depth);
+       return 0;
 }
 
 /* write the mode to registers */
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+static void pm3fb_write_mode(struct fb_info *info)
 {
+       struct pm3_par *par = info->par;
        char tempsync = 0x00, tempmisc = 0x00;
-       DTRACE;
-
-       PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
-       PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
-       PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
-       PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
-
-       PM3_SLOW_WRITE_REG(PM3HTotal,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->htotal -
-                                         1));
-       PM3_SLOW_WRITE_REG(PM3HsEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hsend));
-       PM3_SLOW_WRITE_REG(PM3HsStart,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->
+       const u32 hsstart = info->var.right_margin;
+       const u32 hsend = hsstart + info->var.hsync_len;
+       const u32 hbend = hsend + info->var.left_margin;
+       const u32 xres = (info->var.xres + 31) & ~31;
+       const u32 htotal = xres + hbend;
+       const u32 vsstart = info->var.lower_margin;
+       const u32 vsend = vsstart + info->var.vsync_len;
+       const u32 vbend = vsend + info->var.upper_margin;
+       const u32 vtotal = info->var.yres + vbend;
+       const u32 width = (info->var.xres_virtual + 7) & ~7;
+
+       PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
+       PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000);
+       PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000);
+       PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007);
+
+       PM3_SLOW_WRITE_REG(par, PM3HTotal,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         htotal - 1));
+       PM3_SLOW_WRITE_REG(par, PM3HsEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hsend));
+       PM3_SLOW_WRITE_REG(par, PM3HsStart,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
                                          hsstart));
-       PM3_SLOW_WRITE_REG(PM3HbEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hbend));
-       PM3_SLOW_WRITE_REG(PM3HgEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hbend));
-       PM3_SLOW_WRITE_REG(PM3ScreenStride,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->stride));
-       PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
-       PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
-       PM3_SLOW_WRITE_REG(PM3VsStart,
-                          l_fb_info->current_par->vsstart - 1);
-       PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
-
-       switch (l_fb_info->current_par->depth) {
+       PM3_SLOW_WRITE_REG(par, PM3HbEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hbend));
+       PM3_SLOW_WRITE_REG(par, PM3HgEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hbend));
+       PM3_SLOW_WRITE_REG(par, PM3ScreenStride,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         width));
+       PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend);
+
+       switch (info->var.bits_per_pixel) {
        case 8:
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_8BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_8BIT);
                break;
 
@@ -1100,15 +247,15 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
        case 15:
        case 16:
 #ifndef __BIG_ENDIAN
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT);
 #else
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT |
                                   PM3ByApertureMode_BYTESWAP_BADC);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT |
                                   PM3ByApertureMode_BYTESWAP_BADC);
 #endif /* ! __BIG_ENDIAN */
@@ -1116,23 +263,23 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
 
        case 32:
 #ifndef __BIG_ENDIAN
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT);
 #else
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT |
                                   PM3ByApertureMode_BYTESWAP_DCBA);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT |
                                   PM3ByApertureMode_BYTESWAP_DCBA);
 #endif /* ! __BIG_ENDIAN */
                break;
 
        default:
-               DPRINTK(1, "Unsupported depth %d\n",
-                       l_fb_info->current_par->depth);
+               DPRINTK("Unsupported depth %d\n",
+                       info->var.bits_per_pixel);
                break;
        }
 
@@ -1143,95 +290,86 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
         * sync options in PM3RD_SyncControl.  --rmk
         */
        {
-               unsigned int video = l_fb_info->current_par->video;
+               unsigned int video = par->video;
 
                video &= ~(PM3VideoControl_HSYNC_MASK |
                           PM3VideoControl_VSYNC_MASK);
                video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
                         PM3VideoControl_VSYNC_ACTIVE_HIGH;
-               PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+               PM3_SLOW_WRITE_REG(par, PM3VideoControl, video);
        }
-       PM3_SLOW_WRITE_REG(PM3VClkCtl,
-                          (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
-       PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
-       PM3_SLOW_WRITE_REG(PM3ChipConfig,
-                          (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+       PM3_SLOW_WRITE_REG(par, PM3VClkCtl,
+                          (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
+       PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+       PM3_SLOW_WRITE_REG(par, PM3ChipConfig,
+                          (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
 
        {
-               unsigned char m;        /* ClkPreScale */
-               unsigned char n;        /* ClkFeedBackScale */
-               unsigned char p;        /* ClkPostScale */
-               (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
-
-               DPRINTK(2,
-                       "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
-                       l_fb_info->current_par->pixclock, (int) m, (int) n,
-                       (int) p);
-
-               PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
-               PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
-               PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+               unsigned char uninitialized_var(m);     /* ClkPreScale */
+               unsigned char uninitialized_var(n);     /* ClkFeedBackScale */
+               unsigned char uninitialized_var(p);     /* ClkPostScale */
+               unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
+
+               (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
+
+               DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
+                       pixclock, (int) m, (int) n, (int) p);
+
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
        }
        /*
-          PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+          PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
         */
        /*
-          PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+          PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
         */
-       if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+       if ((par->video & PM3VideoControl_HSYNC_MASK) ==
            PM3VideoControl_HSYNC_ACTIVE_HIGH)
                tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
-       if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+       if ((par->video & PM3VideoControl_VSYNC_MASK) ==
            PM3VideoControl_VSYNC_ACTIVE_HIGH)
                tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
-       
-       PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
-       DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
-       
-       if (flatpanel[l_fb_info->board_num])
-       {
-               PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
-               PM3_WAIT(2);
-               PM3_WRITE_REG(PM3VSConfiguration, 0x06);
-               PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
-               tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
-       }
-       else
-               PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
 
-       switch (l_fb_info->current_par->depth) {
+       PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
+       DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
+
+       PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
+
+       switch (info->var.bits_per_pixel) {
        case 8:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_8_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_CI8_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
                tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
                break;
        case 12:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_16_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_4444_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
                                  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
                tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-               break;          
+               break;
        case 15:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_16_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_5551_FRONT_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
                                  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
                tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-               break;          
+               break;
        case 16:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_16_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_565_FRONT_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
                                  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
@@ -1239,2396 +377,631 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
                break;
        case 32:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_32_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_8888_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
                tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
                break;
        }
-       PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
-       
-       PM3_SHOW_CUR_MODE;
+       PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
 }
 
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
-                           struct pm3fb_par *curpar)
-{
-       unsigned long pixsize1, pixsize2, clockused;
-       unsigned long pre, feedback, post;
-
-       DTRACE;
-
-       clockused = PM3_READ_REG(PM3VClkCtl);
+/*
+ * hardware independent functions
+ */
+int pm3fb_init(void);
+int pm3fb_setup(char*);
 
-       switch (clockused) {
-       case 3:
-               pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
-               feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
-               post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
+static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       u32 lpitch;
 
-               DPRINTK(2,
-                       "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-                       pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-                                                               feedback,
-                                                               post));
+       var->transp.offset = 0;
+       var->transp.length = 0;
+       switch(var->bits_per_pixel) {
+       case 8:
+               var->red.length = var->green.length = var->blue.length = 8;
+               var->red.offset = var->green.offset = var->blue.offset = 0;
                break;
-       case 2:
-               pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
-               feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
-               post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
-
-               DPRINTK(2,
-                       "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-                       pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-                                                               feedback,
-                                                               post));
+       case 12:
+               var->red.offset   = 8;
+               var->red.length   = 4;
+               var->green.offset = 4;
+               var->green.length = 4;
+               var->blue.offset  = 0;
+               var->blue.length  = 4;
+               var->transp.offset = 12;
+               var->transp.length = 4;
+       case 15:
+               var->red.offset   = 10;
+               var->red.length   = 5;
+               var->green.offset = 5;
+               var->green.length = 5;
+               var->blue.offset  = 0;
+               var->blue.length  = 5;
+               var->transp.offset = 15;
+               var->transp.length = 1;
                break;
-       case 1:
-               pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
-               feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
-               post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
-
-               DPRINTK(2,
-                       "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-                       pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-                                                               feedback,
-                                                               post));
+       case 16:
+               var->red.offset   = 11;
+               var->red.length   = 5;
+               var->green.offset = 5;
+               var->green.length = 6;
+               var->blue.offset  = 0;
+               var->blue.length  = 5;
                break;
-       case 0:
-               pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
-               feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
-               post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
-
-               DPRINTK(2,
-                       "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
-                       pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
-                                                               feedback,
-                                                               post));
+       case 32:
+               var->transp.offset = 24;
+               var->transp.length = 8;
+               var->red.offset   = 16;
+               var->green.offset = 8;
+               var->blue.offset  = 0;
+               var->red.length = var->green.length = var->blue.length = 8;
                break;
        default:
-               pre = feedback = post = 0;
-               DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
-               break;
+               DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+               return -EINVAL;
        }
+       var->height = var->width = -1;
 
-       curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
-
-       pixsize1 =
-           PM3ByApertureMode_PIXELSIZE_MASK &
-           (PM3_READ_REG(PM3ByAperture1Mode));
-       pixsize2 =
-           PM3ByApertureMode_PIXELSIZE_MASK &
-           (PM3_READ_REG(PM3ByAperture2Mode));
-
-       DASSERT((pixsize1 == pixsize2),
-               "pixsize the same in both aperture\n");
+       if (var->xres != var->xres_virtual) {
+               DPRINTK("virtual x resolution != physical x resolution not supported\n");
+               return -EINVAL;
+       }
 
-       if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
-               curpar->depth = 32;
-       else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
-       {
-               curpar->depth = 16;
+       if (var->yres > var->yres_virtual) {
+               DPRINTK("virtual y resolution < physical y resolution not possible\n");
+               return -EINVAL;
        }
-       else
-               curpar->depth = 8;
-
-       /* not sure if I need to add one on the next ; it give better result with */
-       curpar->htotal =
-           pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-                            1 + PM3_READ_REG(PM3HTotal));
-       curpar->hsend =
-           pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-                            PM3_READ_REG(PM3HsEnd));
-       curpar->hsstart =
-           pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-                            PM3_READ_REG(PM3HsStart));
-       curpar->hbend =
-           pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-                            PM3_READ_REG(PM3HbEnd));
-
-       curpar->stride =
-           pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
-                            PM3_READ_REG(PM3ScreenStride));
-
-       curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
-       curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
-       curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
-       curpar->vbend = PM3_READ_REG(PM3VbEnd);
-
-       curpar->video = PM3_READ_REG(PM3VideoControl);
-
-       curpar->base = PM3_READ_REG(PM3ScreenBase);
-       curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
-       curpar->height = curpar->vtotal - curpar->vbend;
-
-       DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
-               curpar->width, curpar->height, curpar->pixclock,
-               curpar->stride);
-}
 
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
-{
-       unsigned long memsize = 0, tempBypass, i, temp1, temp2;
-       u16 subvendor, subdevice;
-       pm3fb_timing_result ptr;
-
-       DTRACE;
-
-       l_fb_info->fb_size = 64 * 1024 * 1024;  /* pm3 aperture always 64 MB */
-       pm3fb_mapIO(l_fb_info); /* temporary map IO */
-
-       DASSERT((l_fb_info->vIOBase != NULL),
-               "IO successfully mapped before mem detect\n");
-       DASSERT((l_fb_info->v_fb != NULL),
-               "FB successfully mapped before mem detect\n");
-
-       /* card-specific stuff, *before* accessing *any* FB memory */
-       if ((!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
-           &&
-           (!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
-               i = 0; l_fb_info->board_type = 0;
-               while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
-                       if ((cardbase[i].subvendor == subvendor) &&
-                           (cardbase[i].subdevice == subdevice) &&
-                           (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
-                               DPRINTK(2, "Card #%ld is an %s\n",
-                                       l_fb_info->board_num,
-                                       cardbase[i].cardname);
-                               if (cardbase[i].specific_setup)
-                                       cardbase[i].specific_setup(l_fb_info);
-                               l_fb_info->board_type = i;
-                       }
-                       i++;
-               }
-               if (!l_fb_info->board_type) {
-                       DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
-                               l_fb_info->board_num, subvendor, subdevice);
-               }
-       } else {
-               printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
-                      l_fb_info->board_num);
+       if (var->xoffset) {
+               DPRINTK("xoffset not supported\n");
+               return -EINVAL;
        }
 
-       if (printtimings)
-               pm3fb_show_cur_timing(l_fb_info);
-       
-       /* card-specific setup is done, we preserve the final
-           memory timing for future reference */
-       if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
-               return(0);
+       if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+               DPRINTK("interlace not supported\n");
+               return -EINVAL;
        }
-       
-       tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
 
-       DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+       var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
+       lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
 
-       PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
+       if (var->xres < 200 || var->xres > 2048) {
+               DPRINTK("width not supported: %u\n", var->xres);
+               return -EINVAL;
+       }
 
-       /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
-       for (i = 0; i < 32; i++) {
-               fb_writel(i * 0x00345678,
-                         (l_fb_info->v_fb + (i * 1048576)));
-               mb();
-               temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
+       if (var->yres < 200 || var->yres > 4095) {
+               DPRINTK("height not supported: %u\n", var->yres);
+               return -EINVAL;
+       }
 
-               /* Let's check for wrapover, write will fail at 16MB boundary */
-               if (temp1 == (i * 0x00345678))
-                       memsize = i;
-               else
-                       break;
+       if (lpitch * var->yres_virtual > info->fix.smem_len) {
+               DPRINTK("no memory for screen (%ux%ux%u)\n",
+                       var->xres, var->yres_virtual, var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
+               DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+               return -EINVAL;
        }
 
-       DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
+       var->accel_flags = 0;   /* Can't mmap if this is on */
 
-       if (memsize == i) {
-               for (i = 0; i < 32; i++) {
-                       /* Clear first 32MB ; 0 is 0, no need to byteswap */
-                       writel(0x0000000,
-                              (l_fb_info->v_fb + (i * 1048576)));
-                       mb();
-               }
+       DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+               var->xres, var->yres, var->bits_per_pixel);
+       return 0;
+}
 
-               for (i = 32; i < 64; i++) {
-                       fb_writel(i * 0x00345678,
-                                 (l_fb_info->v_fb + (i * 1048576)));
-                       mb();
-                       temp1 =
-                           fb_readl((l_fb_info->v_fb + (i * 1048576)));
-                       temp2 =
-                           fb_readl((l_fb_info->v_fb +
-                                     ((i - 32) * 1048576)));
-                       if ((temp1 == (i * 0x00345678)) && (temp2 == 0))        /* different value, different RAM... */
-                               memsize = i;
-                       else
-                               break;
-               }
-       }
+static int pm3fb_set_par(struct fb_info *info)
+{
+       struct pm3_par *par = info->par;
+       const u32 xres = (info->var.xres + 31) & ~31;
+       const int depth = (info->var.bits_per_pixel + 7) & ~7;
 
-       DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
+       par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                       (info->var.yoffset * xres)
+                                       + info->var.xoffset);
+       par->video = 0;
 
-       PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
+       if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+               par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
+       else
+               par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
 
-       pm3fb_unmapIO(l_fb_info);
-       memsize = 1048576 * (memsize + 1);
+       if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+               par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
+       else
+               par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
 
-       DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
+       if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+               par->video |= PM3VideoControl_LINE_DOUBLE_ON;
+       else
+               par->video |= PM3VideoControl_LINE_DOUBLE_OFF;
 
-       if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
-       {
-               printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
-               memsize = 1048576 * forcesize[l_fb_info->board_num];
+       if (info->var.activate == FB_ACTIVATE_NOW)
+               par->video |= PM3VideoControl_ENABLE;
+       else {
+               par->video |= PM3VideoControl_DISABLE;
+               DPRINTK("PM3Video disabled\n");
        }
-       
-       l_fb_info->fb_size = memsize;
-       
-       if (ptr == pm3fb_timing_retry)
-       {
-               printk(KERN_WARNING "pm3fb: retrying memory timings check");
-               if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
-                       return(0);
+       switch (depth) {
+       case 8:
+               par->video |= PM3VideoControl_PIXELSIZE_8BIT;
+               break;
+       case 12:
+       case 15:
+       case 16:
+               par->video |= PM3VideoControl_PIXELSIZE_16BIT;
+               break;
+       case 32:
+               par->video |= PM3VideoControl_PIXELSIZE_32BIT;
+               break;
+       default:
+               DPRINTK("Unsupported depth\n");
+               break;
        }
-       
-       return (memsize);
-}
-
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
-{
-       int i;
 
-       DTRACE;
+       info->fix.visual =
+               (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       info->fix.line_length = ((info->var.xres_virtual + 7)  & ~7)
+                                       * depth / 8;
 
-       for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
-       {
-               fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
-       }
+/*     pm3fb_clear_memory(info, 0);*/
+       pm3fb_clear_colormap(par, 0, 0, 0);
+       PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
+                         PM3RD_CursorMode_CURSOR_DISABLE);
+       pm3fb_write_mode(info);
+       return 0;
 }
 
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
+static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp,
+                          struct fb_info *info)
 {
-       int i;
-
-       DTRACE;
+       struct pm3_par *par = info->par;
+
+       if (regno >= 256)  /* no. of hw registers */
+          return -EINVAL;
+
+       /* grayscale works only partially under directcolor */
+       if (info->var.grayscale) {
+          /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+          red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+       }
+
+       /* Directcolor:
+        *   var->{color}.offset contains start of bitfield
+        *   var->{color}.length contains length of bitfield
+        *   {hardwarespecific} contains width of DAC
+        *   pseudo_palette[X] is programmed to (X << red.offset) |
+        *                                    (X << green.offset) |
+        *                                    (X << blue.offset)
+        *   RAMDAC[X] is programmed to (red, green, blue)
+        *   color depth = SUM(var->{color}.length)
+        *
+        * Pseudocolor:
+        *      var->{color}.offset is 0
+        *      var->{color}.length contains width of DAC or the number of unique
+        *                      colors available (color depth)
+        *      pseudo_palette is not used
+        *      RAMDAC[X] is programmed to (red, green, blue)
+        *      color depth = var->{color}.length
+        */
 
-       for (i = 0; i < 256 ; i++) /* fill color map with white */
-               pm3fb_set_color(l_fb_info, i, r, g, b);
+       /*
+        * This is the point where the color is converted to something that
+        * is acceptable by the hardware.
+        */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+       red = CNVT_TOHW(red, info->var.red.length);
+       green = CNVT_TOHW(green, info->var.green.length);
+       blue = CNVT_TOHW(blue, info->var.blue.length);
+       transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+       info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+               u32 v;
+
+               if (regno >= 16)
+                       return -EINVAL;
+
+               v = (red << info->var.red.offset) |
+                       (green << info->var.green.offset) |
+                       (blue << info->var.blue.offset) |
+                       (transp << info->var.transp.offset);
+
+               switch (info->var.bits_per_pixel) {
+               case 8:
+                       break;
+               case 16:
+               case 24:
+               case 32:
+                       ((u32*)(info->pseudo_palette))[regno] = v;
+                       break;
+               }
+               return 0;
+       }
+       else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+               pm3fb_set_color(par, regno, red, green, blue);
 
+       return 0;
 }
 
-/* common initialisation */
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
+static int pm3fb_pan_display(struct fb_var_screeninfo *var,
+                                struct fb_info *info)
 {
-       DTRACE;
+       struct pm3_par *par = info->par;
+       const u32 xres = (var->xres + 31) & ~31;
 
-       DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
-               (unsigned long) l_fb_info);
+       par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+                                       (var->yoffset * xres)
+                                       + var->xoffset);
+       PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+       return 0;
+}
 
-       strcpy(l_fb_info->gen.info.modename, permedia3_name);
-       disp[l_fb_info->board_num].scrollmode = 0;      /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
-       l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
-       l_fb_info->gen.info.changevar = NULL;
-       l_fb_info->gen.info.fbops = &pm3fb_ops;
-       l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
-       if (fontn[l_fb_info->board_num][0])
-               strcpy(l_fb_info->gen.info.fontname,
-                      fontn[l_fb_info->board_num]);
-       l_fb_info->gen.info.switch_con = &fbgen_switch;
-       l_fb_info->gen.info.updatevar = &fbgen_update_var;      /* */
-       l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
+static int pm3fb_blank(int blank_mode, struct fb_info *info)
+{
+       struct pm3_par *par = info->par;
+       u32 video = par->video;
 
-       pm3fb_mapIO(l_fb_info);
-
-       pm3fb_clear_memory(l_fb_info, 0);
-       pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
-
-       (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
-                            &l_fb_info->gen.info);
-
-       if (depth[l_fb_info->board_num]) /* override mode-defined depth */
-       {
-               pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
-               (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
-       }
-
-       (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
-                               &l_fb_info->gen);
-
-       fbgen_set_disp(-1, &l_fb_info->gen);
-
-       do_install_cmap(0, &l_fb_info->gen.info);
-
-       if (register_framebuffer(&l_fb_info->gen.info) < 0) {
-               DPRINTK(1, "Couldn't register framebuffer\n");
-               return;
-       }
-
-       PM3_WRITE_DAC_REG(PM3RD_CursorMode,
-                         PM3RD_CursorMode_CURSOR_DISABLE);
-       
-       PM3_SHOW_CUR_MODE;
-       
-       pm3fb_write_mode(l_fb_info);
-       
-       printk("fb%d: %s, using %uK of video memory (%s)\n",
-              l_fb_info->gen.info.node,
-              permedia3_name, (u32) (l_fb_info->fb_size >> 10),
-              cardbase[l_fb_info->board_type].cardname);
-}
-
-/* **************************************************** */
-/* ***** accelerated permedia3-specific functions ***** */
-/* **************************************************** */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
-{
-       DTRACE;
-
-       PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
-       PM3_SLOW_WRITE_REG(PM3Sync, 0);
-       mb();
-       do {
-               while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
-               rmb();
-       } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
-}
-
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
-{
-       PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
-       PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
-       PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3Window, 0x0);
-
-       PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
-
-       PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
-
-       PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
-       PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
-       PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
-
-       PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
-
-       PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
-                          PM3FBDestReadEnables_E(0xff) |
-                          PM3FBDestReadEnables_R(0xff) |
-                          PM3FBDestReadEnables_ReferenceAlpha(0xff));
-       PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
-                          PM3FBDestReadBufferWidth_Width(l_fb_info->
-                                                         current_par->
-                                                         width));
-
-       PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
-                          PM3FBDestReadMode_ReadEnable |
-                          PM3FBDestReadMode_Enable0);
-       PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
-                          PM3FBSourceReadBufferWidth_Width(l_fb_info->
-                                                           current_par->
-                                                           width));
-       PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
-                          PM3FBSourceReadMode_Blocking |
-                          PM3FBSourceReadMode_ReadEnable);
-
-       {
-               unsigned long rm = 1;
-               switch (l_fb_info->current_par->depth) {
-               case 8:
-                       PM3_SLOW_WRITE_REG(PM3PixelSize,
-                                          PM3PixelSize_GLOBAL_8BIT);
-                       break;
-               case 12:
-               case 15:
-               case 16:
-                       PM3_SLOW_WRITE_REG(PM3PixelSize,
-                                          PM3PixelSize_GLOBAL_16BIT);
-                       break;
-               case 32:
-                       PM3_SLOW_WRITE_REG(PM3PixelSize,
-                                          PM3PixelSize_GLOBAL_32BIT);
-                       break;
-               default:
-                       DPRINTK(1, "Unsupported depth %d\n",
-                               l_fb_info->current_par->depth);
-                       break;
-               }
-               PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
-       }
-
-       PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
-       PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
-       PM3_SLOW_WRITE_REG(PM3FBWriteMode,
-                          PM3FBWriteMode_WriteEnable |
-                          PM3FBWriteMode_OpaqueSpan |
-                          PM3FBWriteMode_Enable0);
-       PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
-       PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
-                          PM3FBWriteBufferWidth_Width(l_fb_info->
-                                                      current_par->
-                                                      width));
-
-       PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
-       {
-               unsigned long sofb = (8UL * l_fb_info->fb_size) /
-                       ((depth2bpp(l_fb_info->current_par->depth))
-                        * l_fb_info->current_par->width);      /* size in lines of FB */
-               if (sofb > 4095)
-                       PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
-               else
-                       PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
-               
-               switch (l_fb_info->current_par->depth) {
-               case 8:
-                       PM3_SLOW_WRITE_REG(PM3DitherMode,
-                                          (1 << 10) | (2 << 3));
-                       break;
-               case 12:
-               case 15:
-               case 16:
-                       PM3_SLOW_WRITE_REG(PM3DitherMode,
-                                          (1 << 10) | (1 << 3));
-                       break;
-               case 32:
-                       PM3_SLOW_WRITE_REG(PM3DitherMode,
-                                          (1 << 10) | (0 << 3));
-                       break;
-               default:
-                       DPRINTK(1, "Unsupported depth %d\n",
-                               l_fb_info->current_par->depth);
-                       break;
-               }
-       }
-
-       PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
-       PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
-       PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
-       PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
-       PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
-       PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
-       PM3_SLOW_WRITE_REG(PM3Count, 0x0);
-       
-/* Disable LocalBuffer. better safe than sorry */
-       PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
-       PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
-       
-       pm3fb_wait_pm3(l_fb_info);
-}
-
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       u32 c;
-
-       DTRACE;
-
-       sx = sx * fontwidth(p);
-       width = width * fontwidth(p);
-       sy = sy * fontheight(p);
-       height = height * fontheight(p);
-       c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
-       /* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
-          we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
-       if ((l_fb_info->current_par->width > 1600) ||
-           (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
-               PM3_WAIT(4);
-
-               PM3_WRITE_REG(PM3Config2D,
-                                         PM3Config2D_UseConstantSource |
-                                         PM3Config2D_ForegroundROPEnable |
-                                         (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                         PM3Config2D_FBWriteEnable);
-
-               PM3_WRITE_REG(PM3ForegroundColor, c);
-
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset(sx)) |
-                             (PM3RectanglePosition_YOffset(sy)));
-
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(width)) |
-                             (PM3Render2D_Height(height)));
-       } else {
-               PM3_WAIT(8);
-
-               PM3_WRITE_REG(PM3FBBlockColor, c);
-
-               PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
-
-               PM3_WRITE_REG(PM3FBWriteBufferWidth0,
-                             PM3FBWriteBufferWidth_Width(l_fb_info->
-                                                         current_par->
-                                                         width << 1));
-
-               PM3_WRITE_REG(PM3Config2D,
-                                         PM3Config2D_UseConstantSource |
-                                         PM3Config2D_ForegroundROPEnable |
-                                         (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                         PM3Config2D_FBWriteEnable);
-
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset(sx << 1)) |
-                             (PM3RectanglePosition_YOffset(sy)));
-
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             (PM3Render2D_Width(width << 1)) |
-                             (PM3Render2D_Height(height)));
-
-               PM3_WRITE_REG(PM3FBWriteBufferWidth0,
-                             PM3FBWriteBufferWidth_Width(l_fb_info->
-                                                         current_par->
-                                                         width));
-
-               PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
-       }
-
-       pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       int sx, sy;
-       u32 c;
-
-       DTRACE;
-
-       sx = conp->vc_cols * fontwidth(p);      /* right margin */
-       sy = conp->vc_rows * fontheight(p);     /* bottom margin */
-       c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
-       if (!bottom_only) {     /* right margin top->bottom */
-               PM3_WAIT(4);
-
-               PM3_WRITE_REG(PM3Config2D,
-                                         PM3Config2D_UseConstantSource |
-                                         PM3Config2D_ForegroundROPEnable |
-                                         (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                         PM3Config2D_FBWriteEnable);
-
-               PM3_WRITE_REG(PM3ForegroundColor, c);
-
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset
-                              (p->var.xoffset +
-                               sx)) | (PM3RectanglePosition_YOffset(p->
-                                                                    var.
-                                                                    yoffset)));
-
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(p->var.xres - sx)) |
-                             (PM3Render2D_Height(p->var.yres)));
-       }
-
-       /* bottom margin left -> right */
-       PM3_WAIT(4);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable);
-
-       PM3_WRITE_REG(PM3ForegroundColor, c);
-
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-                     (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
-       PM3_WRITE_REG(PM3Render2D,
-                     PM3Render2D_XPositive |
-                     PM3Render2D_YPositive |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     (PM3Render2D_Width(p->var.xres)) |
-                     (PM3Render2D_Height(p->var.yres - sy)));
-
-       pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       u32 c;
-
-       DTRACE;
-
-       sx = sx * fontwidth(p);
-       width = width * fontwidth(p);
-       sy = sy * fontheight(p);
-       height = height * fontheight(p);
-       c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-       c = c | (c << 16);
-
-       PM3_WAIT(4);
-
-       if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-               PM3_WRITE_REG(PM3ForegroundColor, c);
-       else
-               PM3_WRITE_REG(PM3FBBlockColor, c);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable);
-
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(sx)) |
-                     (PM3RectanglePosition_YOffset(sy)));
-       
-       if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(width)) |
-                             (PM3Render2D_Height(height)));
-       else
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             (PM3Render2D_Width(width)) |
-                             (PM3Render2D_Height(height)));
-       
-       pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       int sx, sy;
-       u32 c;
-
-       DTRACE;
-
-       sx = conp->vc_cols * fontwidth(p);      /* right margin */
-       sy = conp->vc_rows * fontheight(p);     /* bottom margin */
-       c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-       c = c | (c << 16);
-
-       if (!bottom_only) {     /* right margin top->bottom */
-               PM3_WAIT(4);
-
-               PM3_WRITE_REG(PM3Config2D,
-                                         PM3Config2D_UseConstantSource |
-                                         PM3Config2D_ForegroundROPEnable |
-                                         (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                         PM3Config2D_FBWriteEnable);
-               
-               if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-                       PM3_WRITE_REG(PM3ForegroundColor, c);
-               else
-                       PM3_WRITE_REG(PM3FBBlockColor, c);
-               
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset
-                              (p->var.xoffset +
-                               sx)) | (PM3RectanglePosition_YOffset(p->
-                                                                    var.
-                                                                    yoffset)));
-               if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-                       PM3_WRITE_REG(PM3Render2D,
-                                     PM3Render2D_XPositive |
-                                     PM3Render2D_YPositive |
-                                     PM3Render2D_Operation_Normal |
-                                     PM3Render2D_SpanOperation |
-                                     (PM3Render2D_Width(p->var.xres - sx)) |
-                                     (PM3Render2D_Height(p->var.yres)));
-               else
-                       PM3_WRITE_REG(PM3Render2D,
-                                     PM3Render2D_XPositive |
-                                     PM3Render2D_YPositive |
-                                     PM3Render2D_Operation_Normal |
-                                     (PM3Render2D_Width(p->var.xres - sx)) |
-                                     (PM3Render2D_Height(p->var.yres)));
-       }
-       
-       /* bottom margin left -> right */
-       PM3_WAIT(4);
-       
-       PM3_WRITE_REG(PM3Config2D,
-                     PM3Config2D_UseConstantSource |
-                     PM3Config2D_ForegroundROPEnable |
-                     (PM3Config2D_ForegroundROP(0x3)) |        /* Ox3 is GXcopy */
-                     PM3Config2D_FBWriteEnable);
-       
-       if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-               PM3_WRITE_REG(PM3ForegroundColor, c);
-       else
-               PM3_WRITE_REG(PM3FBBlockColor, c);
-       
-       
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-                     (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-       
-       if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(p->var.xres)) |
-                             (PM3Render2D_Height(p->var.yres - sy)));
-       else
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             (PM3Render2D_Width(p->var.xres)) |
-                             (PM3Render2D_Height(p->var.yres - sy)));
-
-       pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
-                            struct display *p,
-                            int sy, int sx, int height, int width)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       u32 c;
-
-       DTRACE;
-
-       sx = sx * fontwidth(p);
-       width = width * fontwidth(p);
-       sy = sy * fontheight(p);
-       height = height * fontheight(p);
-
-       c = attr_bgcol_ec(p, conp);
-       c |= c << 8;
-       c |= c << 16;
-
-       PM3_WAIT(4);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable);
-
-       PM3_WRITE_REG(PM3ForegroundColor, c);
-
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(sx)) |
-                     (PM3RectanglePosition_YOffset(sy)));
-
-       PM3_WRITE_REG(PM3Render2D,
-                     PM3Render2D_XPositive |
-                     PM3Render2D_YPositive |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     (PM3Render2D_Width(width)) |
-                     (PM3Render2D_Height(height)));
-
-       pm3fb_wait_pm3(l_fb_info);
-}
+       /*
+        * Oxygen VX1 - it appears that setting PM3VideoControl and
+        * then PM3RD_SyncControl to the same SYNC settings undoes
+        * any net change - they seem to xor together.  Only set the
+        * sync options in PM3RD_SyncControl.  --rmk
+        */
+       video &= ~(PM3VideoControl_HSYNC_MASK |
+                  PM3VideoControl_VSYNC_MASK);
+       video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
+                PM3VideoControl_VSYNC_ACTIVE_HIGH;
 
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
-                                    struct display *p, int bottom_only)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       int sx, sy;
-       u32 c;
-
-       DTRACE;
-
-       sx = conp->vc_cols * fontwidth(p);      /* right margin */
-       sy = conp->vc_rows * fontheight(p);     /* bottom margin */
-       c = attr_bgcol_ec(p, conp);
-       c |= c << 8;
-       c |= c << 16;
-
-       if (!bottom_only) {     /* right margin top->bottom */
-               PM3_WAIT(4);
-
-               PM3_WRITE_REG(PM3Config2D,
-                                         PM3Config2D_UseConstantSource |
-                                         PM3Config2D_ForegroundROPEnable |
-                                         (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                         PM3Config2D_FBWriteEnable);
-
-               PM3_WRITE_REG(PM3ForegroundColor, c);
-
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset
-                              (p->var.xoffset +
-                               sx)) | (PM3RectanglePosition_YOffset(p->
-                                                                    var.
-                                                                    yoffset)));
-
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(p->var.xres - sx)) |
-                             (PM3Render2D_Height(p->var.yres)));
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               video = video | PM3VideoControl_ENABLE;
+               break;
+       case FB_BLANK_NORMAL:   /* FIXME */
+               video = video & ~(PM3VideoControl_ENABLE);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               video = video & ~(PM3VideoControl_HSYNC_MASK |
+                                 PM3VideoControl_BLANK_ACTIVE_LOW);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               video = video & ~(PM3VideoControl_VSYNC_MASK |
+                                 PM3VideoControl_BLANK_ACTIVE_LOW);
+               break;
+       case FB_BLANK_POWERDOWN:
+               video = video & ~(PM3VideoControl_HSYNC_MASK |
+                                 PM3VideoControl_VSYNC_MASK |
+                                 PM3VideoControl_BLANK_ACTIVE_LOW);
+               break;
+       default:
+               DPRINTK("Unsupported blanking %d\n", blank_mode);
+               return 1;
        }
 
-       /* bottom margin left -> right */
-       PM3_WAIT(4);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable);
-
-       PM3_WRITE_REG(PM3ForegroundColor, c);
-
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(p->var.xoffset)) |
-                     (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+       PM3_SLOW_WRITE_REG(par,PM3VideoControl, video);
 
-       PM3_WRITE_REG(PM3Render2D,
-                     PM3Render2D_XPositive |
-                     PM3Render2D_YPositive |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     (PM3Render2D_Width(p->var.xres)) |
-                     (PM3Render2D_Height(p->var.yres - sy)));
-
-       pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
-                            int sy, int sx,
-                            int dy, int dx, int height, int width)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       int x_align, o_x, o_y;
-
-       DTRACE;
-
-       sx = sx * fontwidth(p);
-       dx = dx * fontwidth(p);
-       width = width * fontwidth(p);
-       sy = sy * fontheight(p);
-       dy = dy * fontheight(p);
-       height = height * fontheight(p);
-
-       o_x = sx - dx;          /*(sx > dx ) ? (sx - dx) : (dx - sx); */
-       o_y = sy - dy;          /*(sy > dy ) ? (sy - dy) : (dy - sy); */
-
-       x_align = (sx & 0x1f);
-
-       PM3_WAIT(6);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UserScissorEnable |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 PM3Config2D_Blocking |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable);
-
-       PM3_WRITE_REG(PM3ScissorMinXY,
-                     ((dy & 0x0fff) << 16) | (dx & 0x0fff));
-       PM3_WRITE_REG(PM3ScissorMaxXY,
-                                 (((dy + height) & 0x0fff) << 16) |
-                                 ((dx + width) & 0x0fff));
-
-       PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
-                     PM3FBSourceReadBufferOffset_XOffset(o_x) |
-                     PM3FBSourceReadBufferOffset_YOffset(o_y));
-
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(dx - x_align)) |
-                     (PM3RectanglePosition_YOffset(dy)));
-
-       PM3_WRITE_REG(PM3Render2D,
-                     ((sx > dx) ? PM3Render2D_XPositive : 0) |
-                     ((sy > dy) ? PM3Render2D_YPositive : 0) |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     PM3Render2D_FBSourceReadEnable |
-                     (PM3Render2D_Width(width + x_align)) |
-                     (PM3Render2D_Height(height)));
-
-       pm3fb_wait_pm3(l_fb_info);
+       return 0;
 }
 
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
-                           int c, int yy, int xx)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
-       u32 fgx, bgx, ldat;
-       int sx, sy, i;
-
-       DTRACE;
-
-       if (l_fb_info->current_par->depth == 8)
-               fgx = attr_fgcol(p, c);
-       else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-               fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
-       else
-               fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
-
-       PM3_COLOR(fgx);
-
-       if (l_fb_info->current_par->depth == 8)
-               bgx = attr_bgcol(p, c);
-       else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-               bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
-       else
-               bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-
-       PM3_COLOR(bgx);
-
-       PM3_WAIT(4);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
-
-       PM3_WRITE_REG(PM3ForegroundColor, fgx);
-       PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
-       /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
-       /* and 16 bits for fontwidth <= 16 */
-       /* same in _putcs, same for Y and fontheight */
-       if (fontwidth(p) <= 8)
-               asx = 2;
-       else if (fontwidth(p) <= 16)
-               asx = 3;        /* look OK */
-       if (fontheight(p) <= 8)
-               asy = 2;
-       else if (fontheight(p) <= 16)
-               asy = 3;        /* look OK */
-       else if (fontheight(p) <= 32)
-               asy = 4;        /* look OK */
-
-       sx = xx * fontwidth(p);
-       sy = yy * fontheight(p);
-
-       if (fontwidth(p) <= 8)
-               o_x = (8 - (sx & 0x7)) & 0x7;
-       else if (fontwidth(p) <= 16)
-               o_x = (16 - (sx & 0xF)) & 0xF;
-       if (fontheight(p) <= 8)
-               o_y = (8 - (sy & 0x7)) & 0x7;
-       else if (fontheight(p) <= 16)
-               o_y = (16 - (sy & 0xF)) & 0xF;
-       else if (fontheight(p) <= 32)
-               o_y = (32 - (sy & 0x1F)) & 0x1F;
-
-       PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) |    /* x_offset, y_offset in pattern */
-                     (1 << 18) |       /* BE */
-                     1 | (asx << 1) | (asy << 4) |     /* address select x/y */
-                     (1 << 20));       /* OpaqueSpan */
-
-       if (fontwidth(p) <= 8) {
-               cdat = p->fontdata + (c & p->charmask) * fontheight(p);
-       } else {
-               cdat =
-                   p->fontdata +
-                   ((c & p->charmask) * (fontheight(p) << 1));
-       }
-
-       PM3_WAIT(2 + fontheight(p));
-
-       for (i = 0; i < fontheight(p); i++) {   /* assume fontheight <= 32 */
-               if (fontwidth(p) <= 8) {
-                       ldat = *cdat++;
-               } else {        /* assume fontwidth <= 16 ATM */
-
-                       ldat = ((*cdat++) << 8);
-                       ldat |= *cdat++;
-               }
-               PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
-       }
+       /*
+        *  Frame buffer operations
+        */
 
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(sx)) |
-                     (PM3RectanglePosition_YOffset(sy)));
+static struct fb_ops pm3fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = pm3fb_check_var,
+       .fb_set_par     = pm3fb_set_par,
+       .fb_setcolreg   = pm3fb_setcolreg,
+       .fb_pan_display = pm3fb_pan_display,
+       .fb_fillrect    = cfb_fillrect,         /* Needed !!! */
+       .fb_copyarea    = cfb_copyarea,         /* Needed !!! */
+       .fb_imageblit   = cfb_imageblit,        /* Needed !!! */
+       .fb_blank       = pm3fb_blank,
+};
 
-       PM3_WRITE_REG(PM3Render2D,
-                     PM3Render2D_AreaStippleEnable |
-                     PM3Render2D_XPositive |
-                     PM3Render2D_YPositive |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     (PM3Render2D_Width(fontwidth(p))) |
-                     (PM3Render2D_Height(fontheight(p))));
+/* ------------------------------------------------------------------------- */
 
-       pm3fb_wait_pm3(l_fb_info);
-}
+       /*
+        *  Initialization
+        */
 
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
-                            const unsigned short *s, int count, int yy,
-                            int xx)
+/* mmio register are already mapped when this function is called */
+/* the pm3fb_fix.smem_start is also set */
+static unsigned long pm3fb_size_memory(struct pm3_par *par)
 {
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-       u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
-       u32 fgx, bgx, ldat;
-       int sx, sy, i, j;
-       u16 sc;
-
-       DTRACE;
-
-       sc = scr_readw(s);
-       if (l_fb_info->current_par->depth == 8)
-               fgx = attr_fgcol(p, sc);
-       else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-               fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
-       else
-               fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
-       
-       PM3_COLOR(fgx);
-       
-       if (l_fb_info->current_par->depth == 8)
-               bgx = attr_bgcol(p, sc);
-       else if (depth2bpp(l_fb_info->current_par->depth) == 16)
-               bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
-       else
-               bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
-       
-       PM3_COLOR(bgx);
-
-       PM3_WAIT(4);
-
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
-                                 PM3Config2D_FBWriteEnable |
-                                 PM3Config2D_OpaqueSpan);
-
-       PM3_WRITE_REG(PM3ForegroundColor, fgx);
-       PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
-       /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
-       /* and 16 bits for fontwidth <= 16 */
-       /* same in _putc, same for Y and fontheight */
-       if (fontwidth(p) <= 8)
-               asx = 2;
-       else if (fontwidth(p) <= 16)
-               asx = 3;        /* look OK */
-       if (fontheight(p) <= 8)
-               asy = 2;
-       else if (fontheight(p) <= 16)
-               asy = 3;        /* look OK */
-       else if (fontheight(p) <= 32)
-               asy = 4;        /* look OK */
-
-       sy = yy * fontheight(p);
-
-       if (fontheight(p) <= 8)
-               o_y = (8 - (sy & 0x7)) & 0x7;
-       else if (fontheight(p) <= 16)
-               o_y = (16 - (sy & 0xF)) & 0xF;
-       else if (fontheight(p) <= 32)
-               o_y = (32 - (sy & 0x1F)) & 0x1F;
-
-       for (j = 0; j < count; j++) {
-               sc = scr_readw(s + j);
-               if (fontwidth(p) <= 8)
-                       cdat = p->fontdata +
-                               (sc & p->charmask) * fontheight(p);
-               else
-                       cdat = p->fontdata +
-                               ((sc & p->charmask) * fontheight(p) << 1);
-               
-               sx = (xx + j) * fontwidth(p);
-
-               if (fontwidth(p) <= 8)
-                       o_x = (8 - (sx & 0x7)) & 0x7;
-               else if (fontwidth(p) <= 16)
-                       o_x = (16 - (sx & 0xF)) & 0xF;
-
-               PM3_WAIT(3 + fontheight(p));
-
-               PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
-                             (1 << 18) | /* BE */
-                             1 | (asx << 1) | (asy << 4) | /* address select x/y */
-                             (1 << 20)); /* OpaqueSpan */
-
-               for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
-                       if (fontwidth(p) <= 8) {
-                               ldat = *cdat++;
-                       } else { /* assume fontwidth <= 16 ATM */
-                               ldat = ((*cdat++) << 8);
-                               ldat |= *cdat++;
-                       }
-                       PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
-               }
+       unsigned long   memsize = 0, tempBypass, i, temp1, temp2;
+       unsigned char   __iomem *screen_mem;
 
-               PM3_WRITE_REG(PM3RectanglePosition,
-                             (PM3RectanglePosition_XOffset(sx)) |
-                             (PM3RectanglePosition_YOffset(sy)));
-
-               PM3_WRITE_REG(PM3Render2D,
-                             PM3Render2D_AreaStippleEnable |
-                             PM3Render2D_XPositive |
-                             PM3Render2D_YPositive |
-                             PM3Render2D_Operation_Normal |
-                             PM3Render2D_SpanOperation |
-                             (PM3Render2D_Width(fontwidth(p))) |
-                             (PM3Render2D_Height(fontheight(p))));
+       pm3fb_fix.smem_len = 64 * 1024 * 1024; /* request full aperture size */
+       /* Linear frame buffer - request region and map it. */
+       if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+                                "pm3fb smem")) {
+               printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+               return 0;
        }
-       pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-
-       xx = xx * fontwidth(p);
-       yy = yy * fontheight(p);
-
-       if (l_fb_info->current_par->depth == 8)
-       {
-               if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-                       PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
-               else
-                       PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+       screen_mem =
+               ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+       if (!screen_mem) {
+               printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+               release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+               return 0;
        }
 
-       PM3_WAIT(3);
+       /* TODO: card-specific stuff, *before* accessing *any* FB memory */
+       /* For Appian Jeronimo 2000 board second head */
 
-       PM3_WRITE_REG(PM3Config2D,
-                                 PM3Config2D_UseConstantSource |
-                                 PM3Config2D_ForegroundROPEnable |
-                                 (PM3Config2D_ForegroundROP(0xa)) |    /* Oxa is GXinvert */
-                                 PM3Config2D_FBDestReadEnable |
-                                 PM3Config2D_FBWriteEnable);
+       tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
 
-       PM3_WRITE_REG(PM3RectanglePosition,
-                     (PM3RectanglePosition_XOffset(xx)) |
-                     (PM3RectanglePosition_YOffset(yy)));
+       DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
 
-       PM3_WRITE_REG(PM3Render2D,
-                     PM3Render2D_XPositive |
-                     PM3Render2D_YPositive |
-                     PM3Render2D_Operation_Normal |
-                     PM3Render2D_SpanOperation |
-                     (PM3Render2D_Width(fontwidth(p))) |
-                     (PM3Render2D_Height(fontheight(p))));
+       PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
 
-       pm3fb_wait_pm3(l_fb_info);
+       /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+       for (i = 0; i < 32; i++) {
+               fb_writel(i * 0x00345678,
+                         (screen_mem + (i * 1048576)));
+               mb();
+               temp1 = fb_readl((screen_mem + (i * 1048576)));
 
-       if (l_fb_info->current_par->depth == 8)
-       {
-               if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
-                       PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
+               /* Let's check for wrapover, write will fail at 16MB boundary */
+               if (temp1 == (i * 0x00345678))
+                       memsize = i;
                else
-                       PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
+                       break;
        }
-}
 
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* *********************************** */
-/* ***** pre-init board(s) setup ***** */
-/* *********************************** */
+       DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
 
-static void pm3fb_mode_setup(char *mode, unsigned long board_num)
-{
-       struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
-       struct pm3fb_par *l_fb_par = &(current_par[board_num]);
-       unsigned long i = 0;
-
-       current_par_valid[board_num] = 0;
-
-       if (!strncmp(mode, "current", 7)) {
-               l_fb_info->use_current = 1;     /* default w/ OpenFirmware */
-       } else {
-               while ((mode_base[i].name[0])
-                      && (!current_par_valid[board_num])) {
-                       if (!
-                           (strncmp
-                            (mode, mode_base[i].name,
-                             strlen(mode_base[i].name)))) {
-                               memcpy(l_fb_par, &(mode_base[i].user_mode),
-                                      sizeof(struct pm3fb_par));
-                               current_par_valid[board_num] = 1;
-                               DPRINTK(2, "Mode set to %s\n",
-                                       mode_base[i].name);
-                       }
-                       i++;
+       if (memsize + 1 == i) {
+               for (i = 0; i < 32; i++) {
+                       /* Clear first 32MB ; 0 is 0, no need to byteswap */
+                       writel(0x0000000,
+                              (screen_mem + (i * 1048576)));
+                       mb();
                }
-               DASSERT(current_par_valid[board_num],
-                       "Valid mode on command line\n");
-       }
-}
 
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
-{
-       short l_bus = -1, l_slot = -1, l_func = -1;
-       char *next;
-
-       if (pciid) {
-               l_bus = simple_strtoul(pciid, &next, 10);
-               if (next && (next[0] == ':')) {
-                       pciid = next + 1;
-                       l_slot = simple_strtoul(pciid, &next, 10);
-                       if (next && (next[0] == ':')) {
-                               pciid = next + 1;
-                               l_func =
-                                   simple_strtoul(pciid, (char **) NULL,
-                                                  10);
-                       }
+               for (i = 32; i < 64; i++) {
+                       fb_writel(i * 0x00345678,
+                                 (screen_mem + (i * 1048576)));
+                       mb();
+                       temp1 =
+                           fb_readl((screen_mem + (i * 1048576)));
+                       temp2 =
+                           fb_readl((screen_mem + ((i - 32) * 1048576)));
+                       /* different value, different RAM... */
+                       if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
+                               memsize = i;
+                       else
+                               break;
                }
-       } else
-               return;
-
-       if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
-               bus[board_num] = l_bus;
-               slot[board_num] = l_slot;
-               func[board_num] = l_func;
-               DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
-                       board_num, l_bus, l_slot, l_func);
-       } else {
-               DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
-                       l_bus, l_slot, l_func, board_num);
        }
-}
-
-static void pm3fb_font_setup(char *lf, unsigned long board_num)
-{
-       unsigned long lfs = strlen(lf);
-
-       if (lfs > (PM3_FONTNAME_SIZE - 1)) {
-               DPRINTK(1, "Fontname %s too long\n", lf);
-               return;
-       }
-       strlcpy(fontn[board_num], lf, lfs + 1);
-}
+       DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
 
-static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
-{
-       unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+       PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
 
-       if (!(depth_supported(bd))) {
-               printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
-                      bds, board_num);
-               return;
-       }
-       depth[board_num] = bd;
-}
+       iounmap(screen_mem);
+       release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+       memsize = 1048576 * (memsize + 1);
 
-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
-{
-       unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+       DPRINTK("Returning 0x%08lx bytes\n", memsize);
 
-       if (bd > 64) {
-               printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
-                      bds, board_num);
-               return;
-       }
-       forcesize[board_num] = bd;
+       return memsize;
 }
 
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
+static int __devinit pm3fb_probe(struct pci_dev *dev,
+                                 const struct pci_device_id *ent)
 {
-       char *next;
+       struct fb_info *info;
+       struct pm3_par *par;
+       struct device* device = &dev->dev; /* for pci drivers */
+       int err, retval = -ENXIO;
 
-       if (!(isdigit(options[0]))) {
-               (*bn) = 0;
-               return (options);
+       err = pci_enable_device(dev);
+       if (err) {
+               printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
+               return err;
        }
+       /*
+        * Dynamically allocate info and par
+        */
+       info = framebuffer_alloc(sizeof(struct pm3_par), device);
 
-       (*bn) = simple_strtoul(options, &next, 10);
-
-       if (next && (next[0] == ':') && ((*bn) >= 0)
-           && ((*bn) <= PM3_MAX_BOARD)) {
-               DPRINTK(2, "Board_num seen as %ld\n", (*bn));
-               return (next + 1);
-       } else {
-               (*bn) = 0;
-               DPRINTK(2, "Board_num default to %ld\n", (*bn));
-               return (options);
-       }
-}
+       if (!info)
+               return -ENOMEM;
+       par = info->par;
 
-static void pm3fb_real_setup(char *options)
-{
-       char *next;
-       unsigned long i, bn;
-       struct pm3fb_info *l_fb_info;
-
-       DTRACE;
-
-       DPRINTK(2, "Options : %s\n", options);
-
-       for (i = 0; i < PM3_MAX_BOARD; i++) {
-               l_fb_info = &(fb_info[i]);
-               memset(l_fb_info, 0, sizeof(struct pm3fb_info));
-               l_fb_info->gen.fbhw = &pm3fb_switch;
-               l_fb_info->board_num = i;
-               current_par_valid[i] = 0;
-               slot[i] = -1;
-               func[i] = -1;
-               bus[i] = -1;
-               disable[i] = 0;
-               noaccel[i] = 0;
-               fontn[i][0] = '\0';
-               depth[i] = 0;
-               l_fb_info->current_par = &(current_par[i]);
+       /*
+        * Here we set the screen_base to the virtual memory address
+        * for the framebuffer.
+        */
+       pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
+       pm3fb_fix.mmio_len = PM3_REGS_SIZE;
+
+       /* Registers - request region and map it. */
+       if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
+                                "pm3fb regbase")) {
+               printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
+               goto err_exit_neither;
+       }
+       par->v_regs =
+               ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+       if (!par->v_regs) {
+               printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
+                       pm3fb_fix.id);
+               release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+               goto err_exit_neither;
+       }
+
+#if defined(__BIG_ENDIAN)
+       pm3fb_fix.mmio_start += PM3_REGS_SIZE;
+       DPRINTK("Adjusting register base for big-endian.\n");
+#endif
+       /* Linear frame buffer - request region and map it. */
+       pm3fb_fix.smem_start = pci_resource_start(dev, 1);
+       pm3fb_fix.smem_len = pm3fb_size_memory(par);
+       if (!pm3fb_fix.smem_len)
+       {
+               printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
+               goto err_exit_mmio;
        }
-
-       /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
-       if (!strncmp(options, "pm3fb", 5)) {
-               options += 5;
-               while (((*options) == ',') || ((*options) == ':')
-                      || ((*options) == '='))
-                       options++;
+       if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+                                "pm3fb smem")) {
+               printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+               goto err_exit_mmio;
        }
-
-       while (options) {
-               bn = 0;
-               if ((next = strchr(options, ','))) {
-                       (*next) = '\0';
-                       next++;
-               }
-
-               if (!strncmp(options, "mode:", 5)) {
-                       options = pm3fb_boardnum_setup(options + 5, &bn);
-                       DPRINTK(2, "Setting mode for board #%ld\n", bn);
-                       pm3fb_mode_setup(options, bn);
-               } else if (!strncmp(options, "off:", 4)) {
-                       options = pm3fb_boardnum_setup(options + 4, &bn);
-                       DPRINTK(2, "Disabling board #%ld\n", bn);
-                       disable[bn] = 1;
-               } else if (!strncmp(options, "off", 3)) {       /* disable everything */
-                       for (i = 0; i < PM3_MAX_BOARD; i++)
-                               disable[i] = 1;
-               } else if (!strncmp(options, "disable:", 8)) {
-                       options = pm3fb_boardnum_setup(options + 8, &bn);
-                       DPRINTK(2, "Disabling board #%ld\n", bn);
-                       disable[bn] = 1;
-               } else if (!strncmp(options, "pciid:", 6)) {
-                       options = pm3fb_boardnum_setup(options + 6, &bn);
-                       DPRINTK(2, "Setting PciID for board #%ld\n", bn);
-                       pm3fb_pciid_setup(options, bn);
-               } else if (!strncmp(options, "noaccel:", 8)) {
-                       options = pm3fb_boardnum_setup(options + 8, &bn);
-                       noaccel[bn] = 1;
-               } else if (!strncmp(options, "font:", 5)) {
-                       options = pm3fb_boardnum_setup(options + 5, &bn);
-                       pm3fb_font_setup(options, bn);
-               } else if (!strncmp(options, "depth:", 6)) {
-                       options = pm3fb_boardnum_setup(options + 6, &bn);
-                       pm3fb_bootdepth_setup(options, bn);
-               } else if (!strncmp(options, "printtimings", 12)) {
-                       printtimings = 1;
-               } else if (!strncmp(options, "flatpanel:", 10)) {
-                       options = pm3fb_boardnum_setup(options + 10, &bn);
-                       flatpanel[bn] = 1;
-               } else if (!strncmp(options, "forcesize:", 10)) {
-                       options = pm3fb_boardnum_setup(options + 10, &bn);
-                       pm3fb_forcesize_setup(options, bn);
-               }
-               options = next;
+       info->screen_base =
+               ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+       if (!info->screen_base) {
+               printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+               release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+               goto err_exit_mmio;
        }
-}
+       info->screen_size = pm3fb_fix.smem_len;
 
-/* ********************************************** */
-/* ***** framebuffer API standard functions ***** */
-/* ********************************************** */
+       info->fbops = &pm3fb_ops;
 
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
-                           const void *par, struct fb_info_gen *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-       struct pm3fb_par *p = (struct pm3fb_par *) par;
-
-       DTRACE;
-
-       strcpy(fix->id, permedia3_name);
-       fix->smem_start = (unsigned long)l_fb_info->p_fb;
-       fix->smem_len = l_fb_info->fb_size;
-       fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
-       fix->mmio_len = PM3_REGS_SIZE;
-#ifdef PM3FB_USE_ACCEL
-       if (!(noaccel[l_fb_info->board_num]))
-               fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
-       else
-#endif /* PM3FB_USE_ACCEL */
-               fix->accel = FB_ACCEL_NONE;
-       fix->type = FB_TYPE_PACKED_PIXELS;
-       fix->visual =
-           (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-       if (current_par_valid[l_fb_info->board_num])
-               fix->line_length =
-                       l_fb_info->current_par->width *
-                       depth2ByPP(l_fb_info->current_par->depth);
-       else
-               fix->line_length = 0;
-       fix->xpanstep = 64 / depth2bpp(p->depth);
-       fix->ypanstep = 1;
-       fix->ywrapstep = 0;
-       return (0);
-}
-
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
-                           void *par, struct fb_info_gen *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-       struct pm3fb_par *p = (struct pm3fb_par *) par;
-       struct pm3fb_par temp_p;
-       u32 xres;
-
-       DTRACE;
-
-       DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
-       DASSERT((p != NULL), "pm3fb_par* not NULL");
-       DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
-
-       memset(&temp_p, 0, sizeof(struct pm3fb_par));
-       temp_p.width = (var->xres_virtual + 7) & ~7;
-       temp_p.height = var->yres_virtual;
-
-       if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
-               temp_p.depth = depth2bpp(var->bits_per_pixel);
-       else
-               temp_p.depth = var->bits_per_pixel;
+       par->video = PM3_READ_REG(par, PM3VideoControl);
 
-       temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
-       temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
+       info->fix = pm3fb_fix;
+       info->pseudo_palette = par->palette;
+       info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/
 
-       if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
-               temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
-
-       if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
-               temp_p.depth = 12; /* RGBA 4444  is stored as depth 12 */
-
-
-       DPRINTK(2,
-               "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
-               var->xres, var->yres, var->xres_virtual, var->yres_virtual,
-               var->xoffset, var->yoffset);
+       /*
+        * This should give a reasonable default video mode. The following is
+        * done when we can set a video mode.
+        */
+       if (!mode_option)
+               mode_option = "640x480@60";
 
-       xres = (var->xres + 31) & ~31;
-       if (temp_p.width < xres + var->xoffset)
-               temp_p.width = xres + var->xoffset;
-       if (temp_p.height < var->yres + var->yoffset)
-               temp_p.height = var->yres + var->yoffset;
+       retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
 
-       if (temp_p.width > 2048) {
-               DPRINTK(1, "virtual width not supported: %u\n",
-                       temp_p.width);
-               return (-EINVAL);
-       }
-       if (var->yres < 200) {
-               DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
-               return (-EINVAL);
-       }
-       if (temp_p.height < 200 || temp_p.height > 4095) {
-               DPRINTK(1, "virtual height not supported: %u\n",
-                       temp_p.height);
-               return (-EINVAL);
+       if (!retval || retval == 4) {
+               retval = -EINVAL;
+               goto err_exit_both;
        }
-       if (!(depth_supported(temp_p.depth))) {
-               DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
-               return (-EINVAL);
-       }
-       if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
-           l_fb_info->fb_size) {
-               DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
-                       temp_p.width, temp_p.height, temp_p.depth);
-               return (-EINVAL);
-       }
-
-       if ((!var->pixclock) ||
-           (!var->right_margin) ||
-           (!var->hsync_len) ||
-           (!var->left_margin) ||
-           (!var->lower_margin) ||
-           (!var->vsync_len) || (!var->upper_margin)
-           ) {
-               unsigned long i = 0, done = 0;
-               printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
-
-               while ((mode_base[i].user_mode.width) && !done) {
-                       if ((mode_base[i].user_mode.width == temp_p.width)
-                           && (mode_base[i].user_mode.height ==
-                               temp_p.height)) {
-                               printk(KERN_NOTICE "pm3fb: using close match %s\n",
-                                      mode_base[i].name);
-                               temp_p = mode_base[i].user_mode;
-                               done = 1;
-                       }
-                       i++;
-               }
-               if (!done)
-                       return (-EINVAL);
-       } else {
-               temp_p.pixclock = PICOS2KHZ(var->pixclock);
-               if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
-                       DPRINTK(1, "pixclock too high (%uKHz)\n",
-                               temp_p.pixclock);
-                       return (-EINVAL);
-               }
-
-               temp_p.hsstart = var->right_margin;
-               temp_p.hsend = var->right_margin + var->hsync_len;
-               temp_p.hbend =
-                   var->right_margin + var->hsync_len + var->left_margin;
-               temp_p.htotal = xres + temp_p.hbend;
-
-               temp_p.vsstart = var->lower_margin;
-               temp_p.vsend = var->lower_margin + var->vsync_len;
-               temp_p.vbend =
-                   var->lower_margin + var->vsync_len + var->upper_margin;
-               temp_p.vtotal = var->yres + temp_p.vbend;
-
-               temp_p.stride = temp_p.width;
-
-               DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
-                       temp_p.width, temp_p.height, temp_p.pixclock,
-                       temp_p.stride);
-
-               temp_p.base =
-                   pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
-                                  (var->yoffset * xres) + var->xoffset);
-
-               temp_p.video = 0;
-
-               if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-                       temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
-               else
-                       temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
-
-               if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-                       temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
-               else
-                       temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
-
-               if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-                       DPRINTK(1, "Interlaced mode not supported\n\n");
-                       return (-EINVAL);
-               }
-
-               if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
-                       temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
-               else
-                       temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
-
-               if (var->activate == FB_ACTIVATE_NOW)
-                       temp_p.video |= PM3VideoControl_ENABLE;
-               else {
-                       temp_p.video |= PM3VideoControl_DISABLE;
-                       DPRINTK(2, "PM3Video disabled\n");
-               }
 
-               switch (temp_p.depth) {
-               case 8:
-                       temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
-                       break;
-               case 12:
-               case 15:
-               case 16:
-                       temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
-                       break;
-               case 32:
-                       temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
-                       break;
-               default:
-                       DPRINTK(1, "Unsupported depth\n");
-                       break;
-               }
+       /* This has to been done !!! */
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+               retval = -ENOMEM;
+               goto err_exit_both;
        }
-       (*p) = temp_p;
 
-#ifdef PM3FB_USE_ACCEL
-       if (var->accel_flags & FB_ACCELF_TEXT)
-               noaccel[l_fb_info->board_num] = 0;
-       else
-               noaccel[l_fb_info->board_num] = 1;
-#endif /* PM3FB_USE_ACCEL */
-
-       return (0);
-}
-
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
-{
-       switch (d) {
-       case 8:
-               var->red.length = var->green.length = var->blue.length = 8;
-               var->red.offset = var->green.offset = var->blue.offset = 0;
-               var->transp.offset = var->transp.length = 0;
-               break;
-
-       case 12:
-               var->red.offset = 8;
-               var->red.length = 4;
-               var->green.offset = 4;
-               var->green.length = 4;
-               var->blue.offset = 0;
-               var->blue.length = 4;
-               var->transp.offset = 12;
-               var->transp.length = 4;
-               break;
-
-       case 15:
-               var->red.offset = 10;
-               var->red.length = 5;
-               var->green.offset = 5;
-               var->green.length = 5;
-               var->blue.offset = 0;
-               var->blue.length = 5;
-               var->transp.offset = 15;
-               var->transp.length = 1;
-               break;
-
-       case 16:
-               var->red.offset = 11;
-               var->red.length = 5;
-               var->green.offset = 5;
-               var->green.length = 6;
-               var->blue.offset = 0;
-               var->blue.length = 5;
-               var->transp.offset = var->transp.length = 0;
-               break;
-
-       case 32:
-               var->transp.offset = 24;
-               var->red.offset = 16;
-               var->green.offset = 8;
-               var->blue.offset = 0;
-               var->red.length = var->green.length =
-                       var->blue.length = var->transp.length = 8;
-               break;
+       /*
+        * For drivers that can...
+        */
+       pm3fb_check_var(&info->var, info);
 
-       default:
-               DPRINTK(1, "Unsupported depth %ld\n", d);
-               break;
+       if (register_framebuffer(info) < 0) {
+               retval = -EINVAL;
+               goto err_exit_all;
        }
-}
-
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
-                           const void *par, struct fb_info_gen *info)
-{
-       struct pm3fb_par *p = (struct pm3fb_par *) par;
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-       u32 base;
-
-       DTRACE;
-
-       DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
-       DASSERT((p != NULL), "pm3fb_par* not NULL");
-       DASSERT((info != NULL), "fb_info_gen* not NULL");
-
-       memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-#ifdef PM3FB_USE_ACCEL
-       if (!(noaccel[l_fb_info->board_num]))
-               var->accel_flags |= FB_ACCELF_TEXT;
-#endif /* PM3FB_USE_ACCEL */
-
-       var->xres_virtual = p->width;
-       var->yres_virtual = p->height;
-       var->xres = p->htotal - p->hbend;
-       var->yres = p->vtotal - p->vbend;
-
-       DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
-
-       var->right_margin = p->hsstart;
-       var->hsync_len = p->hsend - p->hsstart;
-       var->left_margin = p->hbend - p->hsend;
-       var->lower_margin = p->vsstart;
-       var->vsync_len = p->vsend - p->vsstart;
-       var->upper_margin = p->vbend - p->vsend;
-       var->bits_per_pixel = depth2bpp(p->depth);
-       
-       pm3fb_encode_depth(var, p->depth);
-
-       base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
-
-       var->xoffset = base % var->xres;
-       var->yoffset = base / var->xres;
-
-       var->height = var->width = -1;
-
-       var->pixclock = KHZ2PICOS(p->pixclock);
-
-       if ((p->video & PM3VideoControl_HSYNC_MASK) ==
-           PM3VideoControl_HSYNC_ACTIVE_HIGH)
-               var->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if ((p->video & PM3VideoControl_VSYNC_MASK) ==
-           PM3VideoControl_VSYNC_ACTIVE_HIGH)
-               var->sync |= FB_SYNC_VERT_HIGH_ACT;
-       if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
-               var->vmode = FB_VMODE_DOUBLE;
-
-       return (0);
-}
-
-static void pm3fb_get_par(void *par, struct fb_info_gen *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-       DTRACE;
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+          info->fix.id);
+       pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */
+       return 0;
 
-       if (!current_par_valid[l_fb_info->board_num]) {
-               if (l_fb_info->use_current)
-                       pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
-               else
-                       memcpy(l_fb_info->current_par,
-                              &(mode_base[0].user_mode),
-                              sizeof(struct pm3fb_par));
-               current_par_valid[l_fb_info->board_num] = 1;
-       }
-       *((struct pm3fb_par *) par) = *(l_fb_info->current_par);
+ err_exit_all:
+       fb_dealloc_cmap(&info->cmap);
+ err_exit_both:
+       iounmap(info->screen_base);
+       release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ err_exit_mmio:
+       iounmap(par->v_regs);
+       release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ err_exit_neither:
+       framebuffer_release(info);
+       return retval;
 }
 
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
+       /*
+        *  Cleanup
+        */
+static void __devexit pm3fb_remove(struct pci_dev *dev)
 {
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-       DTRACE;
-
-       *(l_fb_info->current_par) = *((struct pm3fb_par *) par);
-       current_par_valid[l_fb_info->board_num] = 1;
-
-       pm3fb_write_mode(l_fb_info);
+       struct fb_info *info = pci_get_drvdata(dev);
 
-#ifdef PM3FB_USE_ACCEL
-       pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-}
+       if (info) {
+               struct fb_fix_screeninfo *fix = &info->fix;
+               struct pm3_par *par = info->par;
 
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
-                           unsigned char regno, unsigned char r,
-                           unsigned char g, unsigned char b)
-{
-       DTRACE;
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
 
-       PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
-       PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
-       PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
-       PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
-}
+               iounmap(info->screen_base);
+               release_mem_region(fix->smem_start, fix->smem_len);
+               iounmap(par->v_regs);
+               release_mem_region(fix->mmio_start, fix->mmio_len);
 
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-                          unsigned *blue, unsigned *transp,
-                          struct fb_info *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-       DTRACE;
-
-       if (regno < 256) {
-               *red =
-                   l_fb_info->palette[regno].red << 8 | l_fb_info->
-                   palette[regno].red;
-               *green =
-                   l_fb_info->palette[regno].green << 8 | l_fb_info->
-                   palette[regno].green;
-               *blue =
-                   l_fb_info->palette[regno].blue << 8 | l_fb_info->
-                   palette[regno].blue;
-               *transp =
-                   l_fb_info->palette[regno].transp << 8 | l_fb_info->
-                   palette[regno].transp;
+               pci_set_drvdata(dev, NULL);
+               framebuffer_release(info);
        }
-       return (regno > 255);
 }
 
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                          unsigned blue, unsigned transp,
-                          struct fb_info *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+static struct pci_device_id pm3fb_id_table[] = {
+       { PCI_VENDOR_ID_3DLABS, 0x0a,
+         PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+         0xff0000, 0 },
+       { 0, }
+};
 
-       DTRACE;
+/* For PCI drivers */
+static struct pci_driver pm3fb_driver = {
+       .name =         "pm3fb",
+       .id_table =     pm3fb_id_table,
+       .probe =        pm3fb_probe,
+       .remove =       __devexit_p(pm3fb_remove),
+};
 
-       if (regno < 16) {
-               switch (l_fb_info->current_par->depth) {
-#ifdef FBCON_HAS_CFB8
-               case 8:
-                       break;
-#endif
-#ifdef FBCON_HAS_CFB16
-               case 12:
-                       l_fb_info->cmap.cmap12[regno] =
-                               (((u32) red & 0xf000) >> 4) |
-                               (((u32) green & 0xf000) >> 8) |
-                               (((u32) blue & 0xf000) >> 12);
-                       break;
+MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
 
-               case 15:
-                       l_fb_info->cmap.cmap15[regno] =
-                               (((u32) red & 0xf800) >> 1) |
-                               (((u32) green & 0xf800) >> 6) |
-                               (((u32) blue & 0xf800) >> 11);
-                       break;
-
-               case 16:
-                       l_fb_info->cmap.cmap16[regno] =
-                           ((u32) red & 0xf800) |
-                           (((u32) green & 0xfc00) >> 5) |
-                           (((u32) blue & 0xf800) >> 11);
-                       break;
-#endif
-#ifdef FBCON_HAS_CFB32
-               case 32:
-                       l_fb_info->cmap.cmap32[regno] =
-                           (((u32) transp & 0xff00) << 16) |
-                           (((u32) red & 0xff00) << 8) |
-                           (((u32) green & 0xff00)) |
-                           (((u32) blue & 0xff00) >> 8);
-                       break;
-#endif
-               default:
-                       DPRINTK(1, "bad depth %u\n",
-                               l_fb_info->current_par->depth);
-                       break;
-               }
-       }
-       if (regno < 256) {
-               l_fb_info->palette[regno].red = red >> 8;
-               l_fb_info->palette[regno].green = green >> 8;
-               l_fb_info->palette[regno].blue = blue >> 8;
-               l_fb_info->palette[regno].transp = transp >> 8;
-               if (l_fb_info->current_par->depth == 8)
-                       pm3fb_set_color(l_fb_info, regno, red >> 8,
-                                       green >> 8, blue >> 8);
-       }
-       return (regno > 255);
-}
-
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+int __init pm3fb_init(void)
 {
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-       u32 video;
-
-       DTRACE;
-
-       if (!current_par_valid[l_fb_info->board_num])
-               return (1);
-
-       video = l_fb_info->current_par->video;
-
        /*
-        * Oxygen VX1 - it appears that setting PM3VideoControl and
-        * then PM3RD_SyncControl to the same SYNC settings undoes
-        * any net change - they seem to xor together.  Only set the
-        * sync options in PM3RD_SyncControl.  --rmk
+        *  For kernel boot options (in 'video=pm3fb:<options>' format)
         */
-       video &= ~(PM3VideoControl_HSYNC_MASK |
-                  PM3VideoControl_VSYNC_MASK);
-       video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
-                PM3VideoControl_VSYNC_ACTIVE_HIGH;
-
-       if (blank_mode > 0) {
-               switch (blank_mode - 1) {
-
-               case VESA_NO_BLANKING:  /* FIXME */
-                       video = video & ~(PM3VideoControl_ENABLE);
-                       break;
-
-               case VESA_HSYNC_SUSPEND:
-                       video = video & ~(PM3VideoControl_HSYNC_MASK |
-                                         PM3VideoControl_BLANK_ACTIVE_LOW);
-                       break;
-               case VESA_VSYNC_SUSPEND:
-                       video = video & ~(PM3VideoControl_VSYNC_MASK |
-                                         PM3VideoControl_BLANK_ACTIVE_LOW);
-                       break;
-               case VESA_POWERDOWN:
-                       video = video & ~(PM3VideoControl_HSYNC_MASK |
-                                         PM3VideoControl_VSYNC_MASK |
-                                         PM3VideoControl_BLANK_ACTIVE_LOW);
-                       break;
-               default:
-                       DPRINTK(1, "Unsupported blanking %d\n",
-                               blank_mode);
-                       return (1);
-                       break;
-               }
-       }
-
-       PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+#ifndef MODULE
+       char *option = NULL;
 
-       return (0);
-}
-
-static void pm3fb_set_disp(const void *par, struct display *disp,
-                          struct fb_info_gen *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-       struct pm3fb_par *p = (struct pm3fb_par *) par;
-       u32 flags;
-
-       DTRACE;
-
-       local_irq_save(flags);
-       info->info.screen_base = l_fb_info->v_fb;
-       switch (p->depth) {
-#ifdef FBCON_HAS_CFB8
-       case 8:
-#ifdef PM3FB_USE_ACCEL
-               if (!(noaccel[l_fb_info->board_num]))
-                       disp->dispsw = &pm3fb_cfb8;
-               else
-#endif /* PM3FB_USE_ACCEL */
-                       disp->dispsw = &fbcon_cfb8;
-               break;
+       if (fb_get_options("pm3fb", &option))
+               return -ENODEV;
+       pm3fb_setup(option);
 #endif
-#ifdef FBCON_HAS_CFB16
-       case 12:
-#ifdef PM3FB_USE_ACCEL
-               if (!(noaccel[l_fb_info->board_num]))
-                       disp->dispsw = &pm3fb_cfb16;
-               else
-#endif /* PM3FB_USE_ACCEL */
-                       disp->dispsw = &fbcon_cfb16;
-               disp->dispsw_data = l_fb_info->cmap.cmap12;
-               break;
-       case 15:
-#ifdef PM3FB_USE_ACCEL
-               if (!(noaccel[l_fb_info->board_num]))
-                       disp->dispsw = &pm3fb_cfb16;
-               else
-#endif /* PM3FB_USE_ACCEL */
-                       disp->dispsw = &fbcon_cfb16;
-               disp->dispsw_data = l_fb_info->cmap.cmap15;
-               break;
-       case 16:
-#ifdef PM3FB_USE_ACCEL
-               if (!(noaccel[l_fb_info->board_num]))
-                       disp->dispsw = &pm3fb_cfb16;
-               else
-#endif /* PM3FB_USE_ACCEL */
-                       disp->dispsw = &fbcon_cfb16;
-               disp->dispsw_data = l_fb_info->cmap.cmap16;
-               break;
-#endif
-#ifdef FBCON_HAS_CFB32
-       case 32:
-#ifdef PM3FB_USE_ACCEL
-               if (!(noaccel[l_fb_info->board_num]))
-                       disp->dispsw = &pm3fb_cfb32;
-               else
-#endif /* PM3FB_USE_ACCEL */
-                       disp->dispsw = &fbcon_cfb32;
-               disp->dispsw_data = l_fb_info->cmap.cmap32;
-               break;
-#endif /* FBCON_HAS_CFB32 */
-       default:
-               disp->dispsw = &fbcon_dummy;
-               DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
-               break;
-       }
-       local_irq_restore(flags);
-}
-
-/* */
-static void pm3fb_detect(void)
-{
-       struct pci_dev *dev_array[PM3_MAX_BOARD];
-       struct pci_dev *dev = NULL;
-       struct pm3fb_info *l_fb_info = &(fb_info[0]);
-       unsigned long i, j, done;
-
-       DTRACE;
-
-       for (i = 0; i < PM3_MAX_BOARD; i++) {
-               dev_array[i] = NULL;
-               fb_info[i].dev = NULL;
-       }
-
-       dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
-                           PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
-
-       for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
-               dev_array[i] = dev;
-               dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
-                                   PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
-       }
-
-       if (dev) {              /* more than PM3_MAX_BOARD */
-               printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
-                      PM3_MAX_BOARD);
-       }
-
-       if (!dev_array[0]) {    /* not a single board, abort */
-               return;
-       }
-
-       /* allocate user-defined boards */
-       for (i = 0; i < PM3_MAX_BOARD; i++) {
-               if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
-                       for (j = 0; j < PM3_MAX_BOARD; j++) {
-                               if ((dev_array[j] != NULL) &&
-                                   (dev_array[j]->bus->number == bus[i])
-                                   && (PCI_SLOT(dev_array[j]->devfn) ==
-                                       slot[i])
-                                   && (PCI_FUNC(dev_array[j]->devfn) ==
-                                       func[i])) {
-                                       fb_info[i].dev = dev_array[j];
-                                       dev_array[j] = NULL;
-                               }
-                       }
-               }
-       }
-       /* allocate remaining boards */
-       for (i = 0; i < PM3_MAX_BOARD; i++) {
-               if (fb_info[i].dev == NULL) {
-                       done = 0;
-                       for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
-                               if (dev_array[j] != NULL) {
-                                       fb_info[i].dev = dev_array[j];
-                                       dev_array[j] = NULL;
-                                       done = 1;
-                               }
-                       }
-               }
-       }
-
-       /* at that point, all PCI Permedia3 are detected and allocated */
-       /* now, initialize... or not */
-       for (i = 0; i < PM3_MAX_BOARD; i++) {
-               l_fb_info = &(fb_info[i]);
-               if (l_fb_info->dev && !disable[i]) {    /* PCI device was found and not disabled by user */
-                       DPRINTK(2,
-                               "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
-                               (unsigned long) l_fb_info->dev,
-                               (unsigned long) l_fb_info->dev->vendor,
-                               (unsigned long) l_fb_info->dev->device,
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 0),
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 1),
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 2),
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 3),
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 4),
-                               (unsigned long)
-                               pci_resource_start(l_fb_info->dev, 5),
-                               (unsigned long) l_fb_info->dev->irq);
-
-                       l_fb_info->pIOBase =
-                           (unsigned char *)
-                           pci_resource_start(l_fb_info->dev, 0);
-#ifdef __BIG_ENDIAN
-                       l_fb_info->pIOBase += PM3_REGS_SIZE;
-#endif
-                       l_fb_info->vIOBase = (unsigned char *) -1;
-                       l_fb_info->p_fb =
-                           (unsigned char *)
-                           pci_resource_start(l_fb_info->dev, 1);
-                       l_fb_info->v_fb = (unsigned char *) -1;
-
-                               if (!request_mem_region
-                           ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
-                            "pm3fb")) {
-                               printk
-                                   (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
-                                    l_fb_info->board_num);
-                               continue;
-                       }
-                       if (!request_mem_region
-                           ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
-                            "pm3fb I/O regs")) {
-                               printk
-                                   (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
-                                    l_fb_info->board_num);
-                               continue;
-                       }
-                       if (forcesize[l_fb_info->board_num])
-                               l_fb_info->fb_size = forcesize[l_fb_info->board_num];
-
-                       l_fb_info->fb_size =
-                           pm3fb_size_memory(l_fb_info);
-                               if (l_fb_info->fb_size) {
-                               (void) pci_enable_device(l_fb_info->dev);
-                               pm3fb_common_init(l_fb_info);
-                       } else
-                               printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
-               }
-       }
-}
-
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
-                            struct fb_info_gen *info)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
-       DTRACE;
-
-       if (!current_par_valid[l_fb_info->board_num])
-               return -EINVAL;
-
-       l_fb_info->current_par->base =  /* in 128 bits chunk - i.e. AFTER Shiftbpp */
-           pm3fb_Shiftbpp(l_fb_info,
-                          l_fb_info->current_par->depth,
-                          (var->yoffset * l_fb_info->current_par->width) +
-                          var->xoffset);
-       PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
-       return 0;
-}
 
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
-{
-       struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-       u32 cm, i;
-#ifdef PM3FB_MASTER_DEBUG
-       char cc[3];
-#endif /* PM3FB_MASTER_DEBUG */
-
-       switch(cmd)
-       {
-#ifdef PM3FB_MASTER_DEBUG
-       case PM3FBIO_CLEARMEMORY:
-               if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
-                       return(-EFAULT);
-               pm3fb_clear_memory(l_fb_info, cm);
-               return(0);
-               break;
-
-       case PM3FBIO_CLEARCMAP:
-               if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
-                       return(-EFAULT);
-               pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
-               return(0);
-               break;
-#endif /* PM3FB_MASTER_DEBUG */
-
-       case PM3FBIO_RESETCHIP:
-               cm = 1;
-               PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
-               for (i = 0 ; (i < 10000) && cm ; i++)
-               {
-                       PM3_DELAY(10);
-                       cm = PM3_READ_REG(PM3ResetStatus);
-               }
-               if (cm)
-               {
-                       printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
-                       return(-EIO);
-               }
-               /* first thing first, reload memory timings */
-               pm3fb_write_memory_timings(l_fb_info);
-#ifdef PM3FB_USE_ACCEL
-               pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-               pm3fb_write_mode(l_fb_info);
-               return(0);
-               break;
-
-       default:
-               DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
-               return(-EINVAL);
-       }
+       return pci_register_driver(&pm3fb_driver);
 }
 
-/* ****************************************** */
-/* ***** standard FB API init functions ***** */
-/* ****************************************** */
-
-int __init pm3fb_setup(char *options)
+static void __exit pm3fb_exit(void)
 {
-       long opsi = strlen(options);
-
-       DTRACE;
-
-       memcpy(g_options, options,
-              ((opsi + 1) >
-               PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
-       g_options[PM3_OPTIONS_SIZE - 1] = 0;
-
-       return (0);
+       pci_unregister_driver(&pm3fb_driver);
 }
 
-int __init pm3fb_init(void)
-{
-       DTRACE;
-
-       DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
-
-       pm3fb_real_setup(g_options);
-
-       pm3fb_detect();
-
-       if (!fb_info[0].dev) {  /* not even one board ??? */
-               DPRINTK(1, "No PCI Permedia3 board detected\n");
-       }
-       return (0);
-}
-
-/* ************************* */
-/* **** Module support ***** */
-/* ************************* */
-
 #ifdef MODULE
-MODULE_AUTHOR("Romain Dolbeau");
-MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
-static char *mode[PM3_MAX_BOARD];
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode,"video mode");
-module_param_array(disable, short, NULL, 0);
-MODULE_PARM_DESC(disable,"disable board");
-static short off[PM3_MAX_BOARD];
-module_param_array(off, short, NULL, 0);
-MODULE_PARM_DESC(off,"disable board");
-static char *pciid[PM3_MAX_BOARD];
-module_param_array(pciid, charp, NULL, 0);
-MODULE_PARM_DESC(pciid,"board PCI Id");
-module_param_array(noaccel, short, NULL, 0);
-MODULE_PARM_DESC(noaccel,"disable accel");
-static char *font[PM3_MAX_BOARD];
-module_param_array(font, charp, NULL, 0);
-MODULE_PARM_DESC(font,"choose font");
-module_param(depth, short, NULL, 0);
-MODULE_PARM_DESC(depth,"boot-time depth");
-module_param(printtimings, short, NULL, 0);
-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
-module_param(forcesize, short, NULL, 0);
-MODULE_PARM_DESC(forcesize, "force specified memory size");
-/*
-MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
-MODULE_GENERIC_TABLE(gtype,name)
-MODULE_DEVICE_TABLE(type,name)
-*/
-
-void pm3fb_build_options(void)
-{
-       int i;
-       char ts[128];
-
-       strcpy(g_options, "pm3fb");
-       for (i = 0; i < PM3_MAX_BOARD ; i++)
-       {
-               if (mode[i])
-               {
-                       sprintf(ts, ",mode:%d:%s", i, mode[i]);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-               if (disable[i] || off[i])
-               {
-                       sprintf(ts, ",disable:%d:", i);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-               if (pciid[i])
-               {
-                       sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-               if (noaccel[i])
-               {
-                       sprintf(ts, ",noaccel:%d:", i);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-               if (font[i])
-               {
-                       sprintf(ts, ",font:%d:%s", i, font[i]);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-               if (depth[i])
-               {
-                       sprintf(ts, ",depth:%d:%d", i, depth[i]);
-                       strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
-               }
-       }
-       g_options[PM3_OPTIONS_SIZE - 1] = '\0';
-       DPRINTK(1, "pm3fb use options: %s\n", g_options);
-}
+       /*
+        *  Setup
+        */
 
-int init_module(void)
+/*
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+int __init pm3fb_setup(char *options)
 {
-       DTRACE;
-
-       pm3fb_build_options();
-
-       pm3fb_init();
-
+       /* Parse user speficied options (`video=pm3fb:') */
        return 0;
 }
-
-void cleanup_module(void)
-{
-       DTRACE;
-       {
-               unsigned long i;
-               struct pm3fb_info *l_fb_info;
-               for (i = 0; i < PM3_MAX_BOARD; i++) {
-                       l_fb_info = &(fb_info[i]);
-                       pci_dev_put(l_fb_info->dev);
-                       if (l_fb_info->dev != NULL  && !(disable[l_fb_info->board_num])) {
-                               if (l_fb_info->vIOBase != (unsigned char *) -1) {
-                                       pm3fb_unmapIO(l_fb_info);
-                                       release_mem_region(l_fb_info->p_fb,
-                                                  l_fb_info->fb_size);
-                                       release_mem_region(l_fb_info->pIOBase,
-                                                  PM3_REGS_SIZE);
-                               }
-                               unregister_framebuffer(&l_fb_info->gen.info);
-                       }
-               }
-       }
-}
 #endif /* MODULE */
+
+module_init(pm3fb_init);
+module_exit(pm3fb_exit);
+
+MODULE_LICENSE("GPL");
index 76e6ce353c8ea9c559d3668521ae184cd864eca6..a0e22ac483a3d65161f7e54bdfad322c8918d93c 100644 (file)
@@ -70,8 +70,6 @@ static int riva_gpio_getscl(void* data)
        if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04)
                val = 1;
 
-       val = VGA_RD08(par->riva.PCIO, 0x3d5);
-
        return val;
 }
 
index 756fafb41d780af0b67693cbc147bbf564ac6bbe..d11735895a01b7830b3ad89773f7300e364f02d2 100644 (file)
@@ -796,23 +796,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-/* Get capabilities of accelerator based on the mode */
-
-static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
-                         struct fb_var_screeninfo *var)
-{
-       if (var->bits_per_pixel == 0) {
-               /* can only support 256 8x16 bitmap */
-               caps->x = 1 << (8 - 1);
-               caps->y = 1 << (16 - 1);
-               caps->len = 256;
-       } else {
-               caps->x = ~(u32)0;
-               caps->y = ~(u32)0;
-               caps->len = ~(u32)0;
-       }
-}
-
 /* ------------------------------------------------------------------------- */
 
 /* Frame buffer operations */
@@ -829,7 +812,7 @@ static struct fb_ops s3fb_ops = {
        .fb_fillrect    = s3fb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = s3fb_imageblit,
-       .fb_get_caps    = s3fb_get_caps,
+       .fb_get_caps    = svga_get_caps,
 };
 
 /* ------------------------------------------------------------------------- */
index 842b5cd054c65a744bac004c1d783a7953387023..836a612af977f167e67ff1a0f92fe4708bc6788d 100644 (file)
@@ -14,7 +14,7 @@
  *  of it. 
  *
  *  First the roles of struct fb_info and struct display have changed. Struct
- *  display will go away. The way the the new framebuffer console code will
+ *  display will go away. The way the new framebuffer console code will
  *  work is that it will act to translate data about the tty/console in 
  *  struct vc_data to data in a device independent way in struct fb_info. Then
  *  various functions in struct fb_ops will be called to store the device 
index 079cdc911e480bcabf8198244b5bc4b94dcbcd4f..25df928d37d841317dee63632b08179b2fa4accf 100644 (file)
@@ -347,6 +347,23 @@ int svga_get_tilemax(struct fb_info *info)
        return 256;
 }
 
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+                  struct fb_var_screeninfo *var)
+{
+       if (var->bits_per_pixel == 0) {
+               /* can only support 256 8x16 bitmap */
+               caps->x = 1 << (8 - 1);
+               caps->y = 1 << (16 - 1);
+               caps->len = 256;
+       } else {
+               caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+               caps->y = ~(u32)0;
+               caps->len = ~(u32)0;
+       }
+}
+EXPORT_SYMBOL(svga_get_caps);
 
 /* ------------------------------------------------------------------------- */
 
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
new file mode 100644 (file)
index 0000000..5e9755e
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * linux/drivers/video/vt8623fb.c - fbdev driver for
+ * integrated graphic core in VIA VT8623 [CLE266] chipset
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * 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.
+ *
+ * Code is based on s3fb, some parts are from David Boucher's viafb
+ * (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct vt8623fb_info {
+       char __iomem *mmio_base;
+       int mtrr_reg;
+       struct vgastate state;
+       struct mutex open_lock;
+       unsigned int ref_count;
+       u32 pseudo_palette[16];
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format vt8623fb_formats[] = {
+       { 0,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8,   FB_VISUAL_PSEUDOCOLOR, 16, 16},
+       { 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_PSEUDOCOLOR, 16, 16},
+       { 4,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 1,
+               FB_TYPE_INTERLEAVED_PLANES, 1,          FB_VISUAL_PSEUDOCOLOR, 16, 16},
+       { 8,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_PSEUDOCOLOR, 8, 8},
+/*     {16,  {10, 5, 0}, {5, 5, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 4, 4},     */
+       {16,  {11, 5, 0}, {5, 6, 0},  {0, 5, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 4, 4},
+       {32,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
+               FB_TYPE_PACKED_PIXELS, 0,               FB_VISUAL_TRUECOLOR, 2, 2},
+       SVGA_FORMAT_END
+};
+
+static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
+       60000, 300000, 14318};
+
+/* CRT timing register sets */
+
+struct vga_regset vt8623_h_total_regs[]       = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_h_display_regs[]     = {{0x01, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_end_regs[]   = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_start_regs[]  = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_end_regs[]    = {{0x05, 0, 4}, VGA_REGSET_END};
+
+struct vga_regset vt8623_v_total_regs[]       = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+struct vga_regset vt8623_v_display_regs[]     = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_end_regs[]   = {{0x16, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_start_regs[]  = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_end_regs[]    = {{0x11, 0, 3}, VGA_REGSET_END};
+
+struct vga_regset vt8623_offset_regs[]        = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_line_compare_regs[]  = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_fetch_count_regs[]   = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+struct svga_timing_regs vt8623_timing_regs     = {
+       vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
+       vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
+       vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
+       vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
+
+module_param(mode, charp, 0644);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_tile_ops vt8623fb_tile_ops = {
+       .fb_settile     = svga_settile,
+       .fb_tilecopy    = svga_tilecopy,
+       .fb_tilefill    = svga_tilefill,
+       .fb_tileblit    = svga_tileblit,
+       .fb_tilecursor  = svga_tilecursor,
+       .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+       return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       u32 fg = expand_color(image->fg_color);
+       u32 bg = expand_color(image->bg_color);
+       const u8 *src1, *src;
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       u32 val;
+       int x, y;
+
+       src1 = image->data;
+       dst1 = info->screen_base + (image->dy * info->fix.line_length)
+                + ((image->dx / 8) * 4);
+
+       for (y = 0; y < image->height; y++) {
+               src = src1;
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < image->width; x += 8) {
+                       val = *(src++) * 0x01010101;
+                       val = (val & fg) | (~val & bg);
+                       fb_writel(val, dst++);
+               }
+               src1 += image->width / 8;
+               dst1 += info->fix.line_length;
+       }
+}
+
+/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       u32 fg = expand_color(rect->color);
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       int x, y;
+
+       dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+                + ((rect->dx / 8) * 4);
+
+       for (y = 0; y < rect->height; y++) {
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < rect->width; x += 8) {
+                       fb_writel(fg, dst++);
+               }
+               dst1 += info->fix.line_length;
+       }
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+       return (((c &  1) << 24) | ((c &  2) << 27) | ((c &  4) << 14) | ((c &   8) << 17) |
+               ((c & 16) <<  4) | ((c & 32) <<  7) | ((c & 64) >>  6) | ((c & 128) >>  3)) * 0xF;
+}
+
+/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       u32 fg = image->fg_color * 0x11111111;
+       u32 bg = image->bg_color * 0x11111111;
+       const u8 *src1, *src;
+       u8 __iomem *dst1;
+       u32 __iomem *dst;
+       u32 val;
+       int x, y;
+
+       src1 = image->data;
+       dst1 = info->screen_base + (image->dy * info->fix.line_length)
+                + ((image->dx / 8) * 4);
+
+       for (y = 0; y < image->height; y++) {
+               src = src1;
+               dst = (u32 __iomem *) dst1;
+               for (x = 0; x < image->width; x += 8) {
+                       val = expand_pixel(*(src++));
+                       val = (val & fg) | (~val & bg);
+                       fb_writel(val, dst++);
+               }
+               src1 += image->width / 8;
+               dst1 += info->fix.line_length;
+       }
+}
+
+static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+           && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+               if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+                       vt8623fb_iplan_imageblit(info, image);
+               else
+                       vt8623fb_cfb4_imageblit(info, image);
+       } else
+               cfb_imageblit(info, image);
+}
+
+static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       if ((info->var.bits_per_pixel == 4)
+           && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+           && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+               vt8623fb_iplan_fillrect(info, rect);
+        else
+               cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+       u16 m, n, r;
+       u8 regval;
+       int rv;
+
+       rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+       if (rv < 0) {
+               printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+               return;
+       }
+
+       /* Set VGA misc register  */
+       regval = vga_r(NULL, VGA_MIS_R);
+       vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+       /* Set clock registers */
+       vga_wseq(NULL, 0x46, (n  | (r << 6)));
+       vga_wseq(NULL, 0x47, m);
+
+       udelay(1000);
+
+       /* PLL reset */
+       svga_wseq_mask(0x40, 0x02, 0x02);
+       svga_wseq_mask(0x40, 0x00, 0x02);
+}
+
+
+static int vt8623fb_open(struct fb_info *info, int user)
+{
+       struct vt8623fb_info *par = info->par;
+
+       mutex_lock(&(par->open_lock));
+       if (par->ref_count == 0) {
+               memset(&(par->state), 0, sizeof(struct vgastate));
+               par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+               par->state.num_crtc = 0xA2;
+               par->state.num_seq = 0x50;
+               save_vga(&(par->state));
+       }
+
+       par->ref_count++;
+       mutex_unlock(&(par->open_lock));
+
+       return 0;
+}
+
+static int vt8623fb_release(struct fb_info *info, int user)
+{
+       struct vt8623fb_info *par = info->par;
+
+       mutex_lock(&(par->open_lock));
+       if (par->ref_count == 0) {
+               mutex_unlock(&(par->open_lock));
+               return -EINVAL;
+       }
+
+       if (par->ref_count == 1)
+               restore_vga(&(par->state));
+
+       par->ref_count--;
+       mutex_unlock(&(par->open_lock));
+
+       return 0;
+}
+
+static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       int rv, mem, step;
+
+       /* Find appropriate format */
+       rv = svga_match_format (vt8623fb_formats, var, NULL);
+       if (rv < 0)
+       {
+               printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+               return rv;
+       }
+
+       /* Do not allow to have real resoulution larger than virtual */
+       if (var->xres > var->xres_virtual)
+               var->xres_virtual = var->xres;
+
+       if (var->yres > var->yres_virtual)
+               var->yres_virtual = var->yres;
+
+       /* Round up xres_virtual to have proper alignment of lines */
+       step = vt8623fb_formats[rv].xresstep - 1;
+       var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+       /* Check whether have enough memory */
+       mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+       if (mem > info->screen_size)
+       {
+               printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+               return -EINVAL;
+       }
+
+       /* Text mode is limited to 256 kB of memory */
+       if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
+       {
+               printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10);
+               return -EINVAL;
+       }
+
+       rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
+       if (rv < 0)
+       {
+               printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+               return rv;
+       }
+
+       /* Interlaced mode not supported */
+       if (var->vmode & FB_VMODE_INTERLACED)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int vt8623fb_set_par(struct fb_info *info)
+{
+       u32 mode, offset_value, fetch_value, screen_size;
+       u32 bpp = info->var.bits_per_pixel;
+
+       if (bpp != 0) {
+               info->fix.ypanstep = 1;
+               info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+               info->flags &= ~FBINFO_MISC_TILEBLITTING;
+               info->tileops = NULL;
+
+               /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+               info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+               info->pixmap.blit_y = ~(u32)0;
+
+               offset_value = (info->var.xres_virtual * bpp) / 64;
+               fetch_value  = ((info->var.xres * bpp) / 128) + 4;
+
+               if (bpp == 4)
+                       fetch_value  = (info->var.xres / 8) + 8; /* + 0 is OK */
+
+               screen_size  = info->var.yres_virtual * info->fix.line_length;
+       } else {
+               info->fix.ypanstep = 16;
+               info->fix.line_length = 0;
+
+               info->flags |= FBINFO_MISC_TILEBLITTING;
+               info->tileops = &vt8623fb_tile_ops;
+
+               /* supports 8x16 tiles only */
+               info->pixmap.blit_x = 1 << (8 - 1);
+               info->pixmap.blit_y = 1 << (16 - 1);
+
+               offset_value = info->var.xres_virtual / 16;
+               fetch_value  = (info->var.xres / 8) + 8;
+               screen_size  = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+       }
+
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+
+       /* Unlock registers */
+       svga_wseq_mask(0x10, 0x01, 0x01);
+       svga_wcrt_mask(0x11, 0x00, 0x80);
+       svga_wcrt_mask(0x47, 0x00, 0x01);
+
+       /* Device, screen and sync off */
+       svga_wseq_mask(0x01, 0x20, 0x20);
+       svga_wcrt_mask(0x36, 0x30, 0x30);
+       svga_wcrt_mask(0x17, 0x00, 0x80);
+
+       /* Set default values */
+       svga_set_default_gfx_regs();
+       svga_set_default_atc_regs();
+       svga_set_default_seq_regs();
+       svga_set_default_crt_regs();
+       svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
+       svga_wcrt_multi(vt8623_start_address_regs, 0);
+
+       svga_wcrt_multi(vt8623_offset_regs, offset_value);
+       svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+
+       if (info->var.vmode & FB_VMODE_DOUBLE)
+               svga_wcrt_mask(0x09, 0x80, 0x80);
+       else
+               svga_wcrt_mask(0x09, 0x00, 0x80);
+
+       svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
+       svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
+       svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+       vga_wseq(NULL, 0x17, 0x1F);       // FIFO depth
+       vga_wseq(NULL, 0x18, 0x4E);
+       svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+
+       vga_wcrt(NULL, 0x32, 0x00);
+       vga_wcrt(NULL, 0x34, 0x00);
+       vga_wcrt(NULL, 0x6A, 0x80);
+       vga_wcrt(NULL, 0x6A, 0xC0);
+
+       vga_wgfx(NULL, 0x20, 0x00);
+       vga_wgfx(NULL, 0x21, 0x00);
+       vga_wgfx(NULL, 0x22, 0x00);
+
+       /* Set SR15 according to number of bits per pixel */
+       mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
+       switch (mode) {
+       case 0:
+               pr_debug("fb%d: text mode\n", info->node);
+               svga_set_textmode_vga_regs();
+               svga_wseq_mask(0x15, 0x00, 0xFE);
+               svga_wcrt_mask(0x11, 0x60, 0x70);
+               break;
+       case 1:
+               pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+               vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+               svga_wseq_mask(0x15, 0x20, 0xFE);
+               svga_wcrt_mask(0x11, 0x00, 0x70);
+               break;
+       case 2:
+               pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+               svga_wseq_mask(0x15, 0x00, 0xFE);
+               svga_wcrt_mask(0x11, 0x00, 0x70);
+               break;
+       case 3:
+               pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+               svga_wseq_mask(0x15, 0x22, 0xFE);
+               break;
+       case 4:
+               pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+               svga_wseq_mask(0x15, 0xB6, 0xFE);
+               break;
+       case 5:
+               pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+               svga_wseq_mask(0x15, 0xAE, 0xFE);
+               break;
+       default:
+               printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
+               return (-EINVAL);
+       }
+
+       vt8623_set_pixclock(info, info->var.pixclock);
+       svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+                        (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
+                        1, info->node);
+
+       memset_io(info->screen_base, 0x00, screen_size);
+
+       /* Device and screen back on */
+       svga_wcrt_mask(0x17, 0x80, 0x80);
+       svga_wcrt_mask(0x36, 0x00, 0x30);
+       svga_wseq_mask(0x01, 0x00, 0x20);
+
+       return 0;
+}
+
+
+static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                               u_int transp, struct fb_info *fb)
+{
+       switch (fb->var.bits_per_pixel) {
+       case 0:
+       case 4:
+               if (regno >= 16)
+                       return -EINVAL;
+
+               outb(0x0F, VGA_PEL_MSK);
+               outb(regno, VGA_PEL_IW);
+               outb(red >> 10, VGA_PEL_D);
+               outb(green >> 10, VGA_PEL_D);
+               outb(blue >> 10, VGA_PEL_D);
+               break;
+       case 8:
+               if (regno >= 256)
+                       return -EINVAL;
+
+               outb(0xFF, VGA_PEL_MSK);
+               outb(regno, VGA_PEL_IW);
+               outb(red >> 10, VGA_PEL_D);
+               outb(green >> 10, VGA_PEL_D);
+               outb(blue >> 10, VGA_PEL_D);
+               break;
+       case 16:
+               if (regno >= 16)
+                       return 0;
+
+               if (fb->var.green.length == 5)
+                       ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+                               ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+               else if (fb->var.green.length == 6)
+                       ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+                               ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+               else
+                       return -EINVAL;
+               break;
+       case 24:
+       case 32:
+               if (regno >= 16)
+                       return 0;
+
+               /* ((transp & 0xFF00) << 16) */
+               ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+                       (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int vt8623fb_blank(int blank_mode, struct fb_info *info)
+{
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               pr_debug("fb%d: unblank\n", info->node);
+               svga_wcrt_mask(0x36, 0x00, 0x30);
+               svga_wseq_mask(0x01, 0x00, 0x20);
+               break;
+       case FB_BLANK_NORMAL:
+               pr_debug("fb%d: blank\n", info->node);
+               svga_wcrt_mask(0x36, 0x00, 0x30);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
+               svga_wcrt_mask(0x36, 0x10, 0x30);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
+               svga_wcrt_mask(0x36, 0x20, 0x30);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               break;
+       case FB_BLANK_POWERDOWN:
+               pr_debug("fb%d: DPMS off (no sync)\n", info->node);
+               svga_wcrt_mask(0x36, 0x30, 0x30);
+               svga_wseq_mask(0x01, 0x20, 0x20);
+               break;
+       }
+
+       return 0;
+}
+
+
+static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       unsigned int offset;
+
+       /* Calculate the offset */
+       if (var->bits_per_pixel == 0) {
+               offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+               offset = offset >> 3;
+       } else {
+               offset = (var->yoffset * info->fix.line_length) +
+                        (var->xoffset * var->bits_per_pixel / 8);
+               offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+       }
+
+       /* Set the offset */
+       svga_wcrt_multi(vt8623_start_address_regs, offset);
+
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops vt8623fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open        = vt8623fb_open,
+       .fb_release     = vt8623fb_release,
+       .fb_check_var   = vt8623fb_check_var,
+       .fb_set_par     = vt8623fb_set_par,
+       .fb_setcolreg   = vt8623fb_setcolreg,
+       .fb_blank       = vt8623fb_blank,
+       .fb_pan_display = vt8623fb_pan_display,
+       .fb_fillrect    = vt8623fb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = vt8623fb_imageblit,
+       .fb_get_caps    = svga_get_caps,
+};
+
+
+/* PCI probe */
+
+static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       struct fb_info *info;
+       struct vt8623fb_info *par;
+       unsigned int memsize1, memsize2;
+       int rc;
+
+       /* Ignore secondary VGA device because there is no VGA arbitration */
+       if (! svga_primary_device(dev)) {
+               dev_info(&(dev->dev), "ignoring secondary device\n");
+               return -ENODEV;
+       }
+
+       /* Allocate and fill driver data structure */
+       info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+       if (! info) {
+               dev_err(&(dev->dev), "cannot allocate memory\n");
+               return -ENOMEM;
+       }
+
+       par = info->par;
+       mutex_init(&par->open_lock);
+
+       info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+       info->fbops = &vt8623fb_ops;
+
+       /* Prepare PCI device */
+
+       rc = pci_enable_device(dev);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot enable PCI device\n");
+               goto err_enable_device;
+       }
+
+       rc = pci_request_regions(dev, "vt8623fb");
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+               goto err_request_regions;
+       }
+
+       info->fix.smem_start = pci_resource_start(dev, 0);
+       info->fix.smem_len = pci_resource_len(dev, 0);
+       info->fix.mmio_start = pci_resource_start(dev, 1);
+       info->fix.mmio_len = pci_resource_len(dev, 1);
+
+       /* Map physical IO memory address into kernel space */
+       info->screen_base = pci_iomap(dev, 0, 0);
+       if (! info->screen_base) {
+               rc = -ENOMEM;
+               dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+               goto err_iomap_1;
+       }
+
+       par->mmio_base = pci_iomap(dev, 1, 0);
+       if (! par->mmio_base) {
+               rc = -ENOMEM;
+               dev_err(&(dev->dev), "iomap for MMIO failed\n");
+               goto err_iomap_2;
+       }
+
+       /* Find how many physical memory there is on card */
+       memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
+       memsize2 = vga_rseq(NULL, 0x39) << 2;
+
+       if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
+               info->screen_size = memsize1 << 20;
+       else {
+               dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+               info->screen_size = 16 << 20;
+       }
+
+       info->fix.smem_len = info->screen_size;
+       strcpy(info->fix.id, "VIA VT8623");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       info->fix.ypanstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->pseudo_palette = (void*)par->pseudo_palette;
+
+       /* Prepare startup mode */
+
+       rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+       if (! ((rc == 1) || (rc == 2))) {
+               rc = -EINVAL;
+               dev_err(&(dev->dev), "mode %s not found\n", mode);
+               goto err_find_mode;
+       }
+
+       rc = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot allocate colormap\n");
+               goto err_alloc_cmap;
+       }
+
+       rc = register_framebuffer(info);
+       if (rc < 0) {
+               dev_err(&(dev->dev), "cannot register framebugger\n");
+               goto err_reg_fb;
+       }
+
+       printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+                pci_name(dev), info->fix.smem_len >> 20);
+
+       /* Record a reference to the driver data */
+       pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+       if (mtrr) {
+               par->mtrr_reg = -1;
+               par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+       }
+#endif
+
+       return 0;
+
+       /* Error handling */
+err_reg_fb:
+       fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+       pci_iounmap(dev, par->mmio_base);
+err_iomap_2:
+       pci_iounmap(dev, info->screen_base);
+err_iomap_1:
+       pci_release_regions(dev);
+err_request_regions:
+/*     pci_disable_device(dev); */
+err_enable_device:
+       framebuffer_release(info);
+       return rc;
+}
+
+/* PCI remove */
+
+static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct vt8623fb_info *par = info->par;
+
+       if (info) {
+#ifdef CONFIG_MTRR
+               if (par->mtrr_reg >= 0) {
+                       mtrr_del(par->mtrr_reg, 0, 0);
+                       par->mtrr_reg = -1;
+               }
+#endif
+
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+
+               pci_iounmap(dev, info->screen_base);
+               pci_iounmap(dev, par->mmio_base);
+               pci_release_regions(dev);
+/*             pci_disable_device(dev); */
+
+               pci_set_drvdata(dev, NULL);
+               framebuffer_release(info);
+       }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct vt8623fb_info *par = info->par;
+
+       dev_info(&(dev->dev), "suspend\n");
+
+       acquire_console_sem();
+       mutex_lock(&(par->open_lock));
+
+       if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+               mutex_unlock(&(par->open_lock));
+               release_console_sem();
+               return 0;
+       }
+
+       fb_set_suspend(info, 1);
+
+       pci_save_state(dev);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
+
+       mutex_unlock(&(par->open_lock));
+       release_console_sem();
+
+       return 0;
+}
+
+
+/* PCI resume */
+
+static int vt8623_pci_resume(struct pci_dev* dev)
+{
+       struct fb_info *info = pci_get_drvdata(dev);
+       struct vt8623fb_info *par = info->par;
+
+       dev_info(&(dev->dev), "resume\n");
+
+       acquire_console_sem();
+       mutex_lock(&(par->open_lock));
+
+       if (par->ref_count == 0) {
+               mutex_unlock(&(par->open_lock));
+               release_console_sem();
+               return 0;
+       }
+
+       pci_set_power_state(dev, PCI_D0);
+       pci_restore_state(dev);
+
+       if (pci_enable_device(dev))
+               goto fail;
+
+       pci_set_master(dev);
+
+       vt8623fb_set_par(info);
+       fb_set_suspend(info, 0);
+
+       mutex_unlock(&(par->open_lock));
+fail:
+       release_console_sem();
+
+       return 0;
+}
+#else
+#define vt8623_pci_suspend NULL
+#define vt8623_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id vt8623_devices[] __devinitdata = {
+       {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, vt8623_devices);
+
+static struct pci_driver vt8623fb_pci_driver = {
+       .name           = "vt8623fb",
+       .id_table       = vt8623_devices,
+       .probe          = vt8623_pci_probe,
+       .remove         = __devexit_p(vt8623_pci_remove),
+       .suspend        = vt8623_pci_suspend,
+       .resume         = vt8623_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit vt8623fb_cleanup(void)
+{
+       pr_debug("vt8623fb: cleaning up\n");
+       pci_unregister_driver(&vt8623fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+int __init vt8623fb_init(void)
+{
+
+#ifndef MODULE
+       char *option = NULL;
+
+       if (fb_get_options("vt8623fb", &option))
+               return -ENODEV;
+
+       if (option && *option)
+               mode = option;
+#endif
+
+       pr_debug("vt8623fb: initializing\n");
+       return pci_register_driver(&vt8623fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(vt8623fb_init);
+module_exit(vt8623fb_cleanup);
index c287a9ae4fdd56690444c44a2f6e57269e50cb5a..ca75b3ad3a2ebd6f64ae48fc7d476c7ec98f86ec 100644 (file)
@@ -1,4 +1,5 @@
 menu "Dallas's 1-wire bus"
+       depends on HAS_IOMEM
 
 config W1
        tristate "Dallas's 1-wire support"
index 4622dabb2253ec3ed8690fa8b007ccac2be6fd6c..0fa0c1193e81335869c6e93e3a3df070105101b5 100644 (file)
@@ -724,10 +724,6 @@ config FAT_FS
          file system and use GNU tar's M option. GNU tar is a program
          available for Unix and DOS ("man tar" or "info tar").
 
-         It is now also becoming possible to read and write compressed FAT
-         file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
-         details.
-
          The FAT support will enlarge your kernel by about 37 KB. If unsure,
          say Y.
 
index 9edf4112bee0512a081b1666b3a1e426905cece3..720c29d57a626f19b6ca6577b330309248247f5b 100644 (file)
@@ -22,6 +22,10 @@ endif
 obj-$(CONFIG_INOTIFY)          += inotify.o
 obj-$(CONFIG_INOTIFY_USER)     += inotify_user.o
 obj-$(CONFIG_EPOLL)            += eventpoll.o
+obj-$(CONFIG_ANON_INODES)      += anon_inodes.o
+obj-$(CONFIG_SIGNALFD)         += signalfd.o
+obj-$(CONFIG_TIMERFD)          += timerfd.o
+obj-$(CONFIG_EVENTFD)          += eventfd.o
 obj-$(CONFIG_COMPAT)           += compat.o compat_ioctl.o
 
 nfsd-$(CONFIG_NFSD)            := nfsctl.o
index 4aa8079e71be8c7c9ffb7f92d88cd1ce852a38af..c8796906f584bdb2bffe406e186b4f17e6aa5c75 100644 (file)
@@ -628,11 +628,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned
                        return err;
        }
        if (to < PAGE_CACHE_SIZE) {
-               char *kaddr = kmap_atomic(page, KM_USER0);
-
-               memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0);
                if (size > offset + to) {
                        if (size < offset + PAGE_CACHE_SIZE)
                                tmp = size & ~PAGE_CACHE_MASK;
index cf83e5d63512021e9d69c6b18ce067b9f296eea0..73ce561f3ea0c2ea5cd901156a0c3cbf730ed200 100644 (file)
@@ -22,6 +22,7 @@ kafs-objs := \
        vlclient.o \
        vlocation.o \
        vnode.o \
-       volume.o
+       volume.o \
+       write.o
 
 obj-$(CONFIG_AFS_FS)  := kafs.o
index 52d0752265b8a4f4bc120be164f6a75d93963ecf..2452579481404fe702aa852b39ab404254773c5b 100644 (file)
@@ -16,6 +16,9 @@
 
 #define AFS_MAXCELLNAME        64              /* maximum length of a cell name */
 #define AFS_MAXVOLNAME 64              /* maximum length of a volume name */
+#define AFSNAMEMAX     256             /* maximum length of a filename plus NUL */
+#define AFSPATHMAX     1024            /* maximum length of a pathname plus NUL */
+#define AFSOPAQUEMAX   1024            /* maximum length of an opaque field */
 
 typedef unsigned                       afs_volid_t;
 typedef unsigned                       afs_vnodeid_t;
@@ -143,4 +146,24 @@ struct afs_volsync {
        time_t                  creation;       /* volume creation time */
 };
 
+/*
+ * AFS volume status record
+ */
+struct afs_volume_status {
+       u32                     vid;            /* volume ID */
+       u32                     parent_id;      /* parent volume ID */
+       u8                      online;         /* true if volume currently online and available */
+       u8                      in_service;     /* true if volume currently in service */
+       u8                      blessed;        /* same as in_service */
+       u8                      needs_salvage;  /* true if consistency checking required */
+       u32                     type;           /* volume type (afs_voltype_t) */
+       u32                     min_quota;      /* minimum space set aside (blocks) */
+       u32                     max_quota;      /* maximum space this volume may occupy (blocks) */
+       u32                     blocks_in_use;  /* space this volume currently occupies (blocks) */
+       u32                     part_blocks_avail; /* space available in volume's partition */
+       u32                     part_max_blocks; /* size of volume's partition */
+};
+
+#define AFS_BLOCK_SIZE 1024
+
 #endif /* AFS_H */
index 89e0d1650a72503d8b78ac0279378962876f4e94..a18c374ebe080d9cbbc9544bd2e4dbdbf42ec62a 100644 (file)
@@ -18,6 +18,8 @@
 enum AFS_FS_Operations {
        FSFETCHDATA             = 130,  /* AFS Fetch file data */
        FSFETCHSTATUS           = 132,  /* AFS Fetch file status */
+       FSSTOREDATA             = 133,  /* AFS Store file data */
+       FSSTORESTATUS           = 135,  /* AFS Store file status */
        FSREMOVEFILE            = 136,  /* AFS Remove a file */
        FSCREATEFILE            = 137,  /* AFS Create a file */
        FSRENAME                = 138,  /* AFS Rename or move a file or directory */
@@ -26,9 +28,12 @@ enum AFS_FS_Operations {
        FSMAKEDIR               = 141,  /* AFS Create a directory */
        FSREMOVEDIR             = 142,  /* AFS Remove a directory */
        FSGIVEUPCALLBACKS       = 147,  /* AFS Discard callback promises */
-       FSGETVOLUMEINFO         = 148,  /* AFS Get root volume information */
+       FSGETVOLUMEINFO         = 148,  /* AFS Get information about a volume */
+       FSGETVOLUMESTATUS       = 149,  /* AFS Get volume status information */
        FSGETROOTVOLUME         = 151,  /* AFS Get root volume name */
        FSLOOKUP                = 161,  /* AFS lookup file in directory */
+       FSFETCHDATA64           = 65537, /* AFS Fetch file data */
+       FSSTOREDATA64           = 65538, /* AFS Store file data */
 };
 
 enum AFS_FS_Errors {
index 9bdbf36a9aa9ac20fe3ecb94f4403483af74ad0e..f64e40fefc02841d8c9625e556780e963c0f2090 100644 (file)
@@ -44,7 +44,7 @@ void afs_init_callback_state(struct afs_server *server)
        while (!RB_EMPTY_ROOT(&server->cb_promises)) {
                vnode = rb_entry(server->cb_promises.rb_node,
                                 struct afs_vnode, cb_promise);
-               _debug("UNPROMISE { vid=%x vn=%u uq=%u}",
+               _debug("UNPROMISE { vid=%x:%u uq=%u}",
                       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
                rb_erase(&vnode->cb_promise, &server->cb_promises);
                vnode->cb_promised = false;
@@ -84,11 +84,8 @@ void afs_broken_callback_work(struct work_struct *work)
 
                /* if the vnode's data version number changed then its contents
                 * are different */
-               if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-                       _debug("zap data {%x:%u}",
-                              vnode->fid.vid, vnode->fid.vnode);
-                       invalidate_remote_inode(&vnode->vfs_inode);
-               }
+               if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+                       afs_zap_data(vnode);
        }
 
 out:
index 0c1e902f17a3d80db2e32135c0278a3130495e92..719af4fb15dc5dfbb42322f953ba7012dd763a0c 100644 (file)
@@ -55,7 +55,8 @@ const struct inode_operations afs_dir_inode_operations = {
        .rmdir          = afs_rmdir,
        .rename         = afs_rename,
        .permission     = afs_permission,
-       .getattr        = afs_inode_getattr,
+       .getattr        = afs_getattr,
+       .setattr        = afs_setattr,
 };
 
 static struct dentry_operations afs_fs_dentry_operations = {
@@ -491,12 +492,12 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 
        vnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},%p{%s},",
+       _enter("{%x:%u},%p{%s},",
               vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
 
        ASSERTCMP(dentry->d_inode, ==, NULL);
 
-       if (dentry->d_name.len > 255) {
+       if (dentry->d_name.len >= AFSNAMEMAX) {
                _leave(" = -ENAMETOOLONG");
                return ERR_PTR(-ENAMETOOLONG);
        }
@@ -731,11 +732,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%s},%o",
+       _enter("{%x:%u},{%s},%o",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -796,11 +797,11 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
 
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%s}",
+       _enter("{%x:%u},{%s}",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -842,11 +843,11 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
 
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%s}",
+       _enter("{%x:%u},{%s}",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -916,11 +917,11 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
 
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%s},%o,",
+       _enter("{%x:%u},{%s},%o,",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -983,13 +984,13 @@ static int afs_link(struct dentry *from, struct inode *dir,
        vnode = AFS_FS_I(from->d_inode);
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%x:%d},{%s}",
+       _enter("{%x:%u},{%x:%u},{%s}",
               vnode->fid.vid, vnode->fid.vnode,
               dvnode->fid.vid, dvnode->fid.vnode,
               dentry->d_name.name);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -1032,16 +1033,16 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
 
        dvnode = AFS_FS_I(dir);
 
-       _enter("{%x:%d},{%s},%s",
+       _enter("{%x:%u},{%s},%s",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
               content);
 
        ret = -ENAMETOOLONG;
-       if (dentry->d_name.len > 255)
+       if (dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        ret = -EINVAL;
-       if (strlen(content) > 1023)
+       if (strlen(content) >= AFSPATHMAX)
                goto error;
 
        key = afs_request_key(dvnode->volume->cell);
@@ -1104,14 +1105,14 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
        orig_dvnode = AFS_FS_I(old_dir);
        new_dvnode = AFS_FS_I(new_dir);
 
-       _enter("{%x:%d},{%x:%d},{%x:%d},{%s}",
+       _enter("{%x:%u},{%x:%u},{%x:%u},{%s}",
               orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
               vnode->fid.vid, vnode->fid.vnode,
               new_dvnode->fid.vid, new_dvnode->fid.vnode,
               new_dentry->d_name.name);
 
        ret = -ENAMETOOLONG;
-       if (new_dentry->d_name.len > 255)
+       if (new_dentry->d_name.len >= AFSNAMEMAX)
                goto error;
 
        key = afs_request_key(orig_dvnode->volume->cell);
index ae256498f4f70684e007bae54e40ff7dd2e0b027..9c0e721d9fc219fff078507b879b92b7ae41b1fb 100644 (file)
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/writeback.h>
 #include "internal.h"
 
-static int afs_file_readpage(struct file *file, struct page *page);
-static void afs_file_invalidatepage(struct page *page, unsigned long offset);
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_readpage(struct file *file, struct page *page);
+static void afs_invalidatepage(struct page *page, unsigned long offset);
+static int afs_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_launder_page(struct page *page);
 
 const struct file_operations afs_file_operations = {
        .open           = afs_open,
        .release        = afs_release,
        .llseek         = generic_file_llseek,
        .read           = do_sync_read,
+       .write          = do_sync_write,
        .aio_read       = generic_file_aio_read,
+       .aio_write      = afs_file_write,
        .mmap           = generic_file_readonly_mmap,
        .sendfile       = generic_file_sendfile,
+       .fsync          = afs_fsync,
 };
 
 const struct inode_operations afs_file_inode_operations = {
-       .getattr        = afs_inode_getattr,
+       .getattr        = afs_getattr,
+       .setattr        = afs_setattr,
        .permission     = afs_permission,
 };
 
 const struct address_space_operations afs_fs_aops = {
-       .readpage       = afs_file_readpage,
-       .set_page_dirty = __set_page_dirty_nobuffers,
-       .releasepage    = afs_file_releasepage,
-       .invalidatepage = afs_file_invalidatepage,
+       .readpage       = afs_readpage,
+       .set_page_dirty = afs_set_page_dirty,
+       .launder_page   = afs_launder_page,
+       .releasepage    = afs_releasepage,
+       .invalidatepage = afs_invalidatepage,
+       .prepare_write  = afs_prepare_write,
+       .commit_write   = afs_commit_write,
+       .writepage      = afs_writepage,
+       .writepages     = afs_writepages,
 };
 
 /*
@@ -52,7 +63,7 @@ int afs_open(struct inode *inode, struct file *file)
        struct key *key;
        int ret;
 
-       _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+       _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
 
        key = afs_request_key(vnode->volume->cell);
        if (IS_ERR(key)) {
@@ -78,7 +89,7 @@ int afs_release(struct inode *inode, struct file *file)
 {
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
-       _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+       _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
 
        key_put(file->private_data);
        _leave(" = 0");
@@ -89,10 +100,10 @@ int afs_release(struct inode *inode, struct file *file)
  * deal with notification that a page was read from the cache
  */
 #ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_read_complete(void *cookie_data,
-                                           struct page *page,
-                                           void *data,
-                                           int error)
+static void afs_readpage_read_complete(void *cookie_data,
+                                      struct page *page,
+                                      void *data,
+                                      int error)
 {
        _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
@@ -109,10 +120,10 @@ static void afs_file_readpage_read_complete(void *cookie_data,
  * deal with notification that a page was written to the cache
  */
 #ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_write_complete(void *cookie_data,
-                                            struct page *page,
-                                            void *data,
-                                            int error)
+static void afs_readpage_write_complete(void *cookie_data,
+                                       struct page *page,
+                                       void *data,
+                                       int error)
 {
        _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
@@ -121,9 +132,9 @@ static void afs_file_readpage_write_complete(void *cookie_data,
 #endif
 
 /*
- * AFS read page from file (or symlink)
+ * AFS read page from file, directory or symlink
  */
-static int afs_file_readpage(struct file *file, struct page *page)
+static int afs_readpage(struct file *file, struct page *page)
 {
        struct afs_vnode *vnode;
        struct inode *inode;
@@ -218,27 +229,10 @@ error:
        return ret;
 }
 
-/*
- * get a page cookie for the specified page
- */
-#ifdef AFS_CACHING_SUPPORT
-int afs_cache_get_page_cookie(struct page *page,
-                             struct cachefs_page **_page_cookie)
-{
-       int ret;
-
-       _enter("");
-       ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
-
-       _leave(" = %d", ret);
-       return ret;
-}
-#endif
-
 /*
  * invalidate part or all of a page
  */
-static void afs_file_invalidatepage(struct page *page, unsigned long offset)
+static void afs_invalidatepage(struct page *page, unsigned long offset)
 {
        int ret = 1;
 
@@ -247,11 +241,6 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset)
        BUG_ON(!PageLocked(page));
 
        if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
-               struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-               cachefs_uncache_page(vnode->cache,page);
-#endif
-
                /* We release buffers only if the entire page is being
                 * invalidated.
                 * The get_block cached value has been unconditionally
@@ -271,26 +260,34 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset)
        _leave(" = %d", ret);
 }
 
+/*
+ * write back a dirty page
+ */
+static int afs_launder_page(struct page *page)
+{
+       _enter("{%lu}", page->index);
+
+       return 0;
+}
+
 /*
  * release a page and cleanup its private data
  */
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
+static int afs_releasepage(struct page *page, gfp_t gfp_flags)
 {
-       struct cachefs_page *pageio;
+       struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+       struct afs_writeback *wb;
 
-       _enter("{%lu},%x", page->index, gfp_flags);
+       _enter("{{%x:%u}[%lu],%lx},%x",
+              vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
+              gfp_flags);
 
        if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
-               struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-               cachefs_uncache_page(vnode->cache, page);
-#endif
-
-               pageio = (struct cachefs_page *) page_private(page);
+               wb = (struct afs_writeback *) page_private(page);
+               ASSERT(wb != NULL);
                set_page_private(page, 0);
                ClearPagePrivate(page);
-
-               kfree(pageio);
+               afs_put_writeback(wb);
        }
 
        _leave(" = 0");
index e54e6c2ad343a25aba23997806a21b06dbca369a..5dff1308b6f0da5475a20701063036a78bf21b90 100644 (file)
@@ -33,8 +33,10 @@ static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
  */
 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                                      struct afs_file_status *status,
-                                     struct afs_vnode *vnode)
+                                     struct afs_vnode *vnode,
+                                     afs_dataversion_t *store_version)
 {
+       afs_dataversion_t expected_version;
        const __be32 *bp = *_bp;
        umode_t mode;
        u64 data_version, size;
@@ -101,7 +103,11 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                vnode->vfs_inode.i_atime        = vnode->vfs_inode.i_ctime;
        }
 
-       if (status->data_version != data_version) {
+       expected_version = status->data_version;
+       if (store_version)
+               expected_version = *store_version;
+
+       if (expected_version != data_version) {
                status->data_version = data_version;
                if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
                        _debug("vnode modified %llx on {%x:%u}",
@@ -110,6 +116,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
                        set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
                        set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
                }
+       } else if (store_version) {
+               status->data_version = data_version;
        }
 }
 
@@ -155,6 +163,67 @@ static void xdr_decode_AFSVolSync(const __be32 **_bp,
        *_bp = bp;
 }
 
+/*
+ * encode the requested attributes into an AFSStoreStatus block
+ */
+static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
+{
+       __be32 *bp = *_bp;
+       u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
+
+       mask = 0;
+       if (attr->ia_valid & ATTR_MTIME) {
+               mask |= AFS_SET_MTIME;
+               mtime = attr->ia_mtime.tv_sec;
+       }
+
+       if (attr->ia_valid & ATTR_UID) {
+               mask |= AFS_SET_OWNER;
+               owner = attr->ia_uid;
+       }
+
+       if (attr->ia_valid & ATTR_GID) {
+               mask |= AFS_SET_GROUP;
+               group = attr->ia_gid;
+       }
+
+       if (attr->ia_valid & ATTR_MODE) {
+               mask |= AFS_SET_MODE;
+               mode = attr->ia_mode & S_IALLUGO;
+       }
+
+       *bp++ = htonl(mask);
+       *bp++ = htonl(mtime);
+       *bp++ = htonl(owner);
+       *bp++ = htonl(group);
+       *bp++ = htonl(mode);
+       *bp++ = 0;              /* segment size */
+       *_bp = bp;
+}
+
+/*
+ * decode an AFSFetchVolumeStatus block
+ */
+static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
+                                           struct afs_volume_status *vs)
+{
+       const __be32 *bp = *_bp;
+
+       vs->vid                 = ntohl(*bp++);
+       vs->parent_id           = ntohl(*bp++);
+       vs->online              = ntohl(*bp++);
+       vs->in_service          = ntohl(*bp++);
+       vs->blessed             = ntohl(*bp++);
+       vs->needs_salvage       = ntohl(*bp++);
+       vs->type                = ntohl(*bp++);
+       vs->min_quota           = ntohl(*bp++);
+       vs->max_quota           = ntohl(*bp++);
+       vs->blocks_in_use       = ntohl(*bp++);
+       vs->part_blocks_avail   = ntohl(*bp++);
+       vs->part_max_blocks     = ntohl(*bp++);
+       *_bp = bp;
+}
+
 /*
  * deliver reply data to an FS.FetchStatus
  */
@@ -175,7 +244,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call,
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
        xdr_decode_AFSCallBack(&bp, vnode);
        if (call->reply2)
                xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -206,7 +275,7 @@ int afs_fs_fetch_file_status(struct afs_server *server,
        struct afs_call *call;
        __be32 *bp;
 
-       _enter(",%x,{%x:%d},,",
+       _enter(",%x,{%x:%u},,",
               key_serial(key), vnode->fid.vid, vnode->fid.vnode);
 
        call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
@@ -247,9 +316,33 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
        case 0:
                call->offset = 0;
                call->unmarshall++;
+               if (call->operation_ID != FSFETCHDATA64) {
+                       call->unmarshall++;
+                       goto no_msw;
+               }
 
-               /* extract the returned data length */
+               /* extract the upper part of the returned data length of an
+                * FSFETCHDATA64 op (which should always be 0 using this
+                * client) */
        case 1:
+               _debug("extract data length (MSW)");
+               ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->count = ntohl(call->tmp);
+               _debug("DATA length MSW: %u", call->count);
+               if (call->count > 0)
+                       return -EBADMSG;
+               call->offset = 0;
+               call->unmarshall++;
+
+       no_msw:
+               /* extract the returned data length */
+       case 2:
                _debug("extract data length");
                ret = afs_extract_data(call, skb, last, &call->tmp, 4);
                switch (ret) {
@@ -265,32 +358,27 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
                call->offset = 0;
                call->unmarshall++;
 
-               if (call->count < PAGE_SIZE) {
+               /* extract the returned data */
+       case 3:
+               _debug("extract data");
+               if (call->count > 0) {
                        page = call->reply3;
                        buffer = kmap_atomic(page, KM_USER0);
-                       memset(buffer + PAGE_SIZE - call->count, 0,
-                              call->count);
+                       ret = afs_extract_data(call, skb, last, buffer,
+                                              call->count);
                        kunmap_atomic(buffer, KM_USER0);
-               }
-
-               /* extract the returned data */
-       case 2:
-               _debug("extract data");
-               page = call->reply3;
-               buffer = kmap_atomic(page, KM_USER0);
-               ret = afs_extract_data(call, skb, last, buffer, call->count);
-               kunmap_atomic(buffer, KM_USER0);
-               switch (ret) {
-               case 0:         break;
-               case -EAGAIN:   return 0;
-               default:        return ret;
+                       switch (ret) {
+                       case 0:         break;
+                       case -EAGAIN:   return 0;
+                       default:        return ret;
+                       }
                }
 
                call->offset = 0;
                call->unmarshall++;
 
                /* extract the metadata */
-       case 3:
+       case 4:
                ret = afs_extract_data(call, skb, last, call->buffer,
                                       (21 + 3 + 6) * 4);
                switch (ret) {
@@ -300,7 +388,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
                }
 
                bp = call->buffer;
-               xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+               xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
                xdr_decode_AFSCallBack(&bp, vnode);
                if (call->reply2)
                        xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -308,7 +396,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
                call->offset = 0;
                call->unmarshall++;
 
-       case 4:
+       case 5:
                _debug("trailer");
                if (skb->len != 0)
                        return -EBADMSG;
@@ -318,6 +406,14 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
        if (!last)
                return 0;
 
+       if (call->count < PAGE_SIZE) {
+               _debug("clear");
+               page = call->reply3;
+               buffer = kmap_atomic(page, KM_USER0);
+               memset(buffer + call->count, 0, PAGE_SIZE - call->count);
+               kunmap_atomic(buffer, KM_USER0);
+       }
+
        _leave(" = 0 [done]");
        return 0;
 }
@@ -332,6 +428,56 @@ static const struct afs_call_type afs_RXFSFetchData = {
        .destructor     = afs_flat_call_destructor,
 };
 
+static const struct afs_call_type afs_RXFSFetchData64 = {
+       .name           = "FS.FetchData64",
+       .deliver        = afs_deliver_fs_fetch_data,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * fetch data from a very large file
+ */
+static int afs_fs_fetch_data64(struct afs_server *server,
+                              struct key *key,
+                              struct afs_vnode *vnode,
+                              off_t offset, size_t length,
+                              struct page *buffer,
+                              const struct afs_wait_mode *wait_mode)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter("");
+
+       ASSERTCMP(length, <, ULONG_MAX);
+
+       call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+       call->reply = vnode;
+       call->reply2 = NULL; /* volsync */
+       call->reply3 = buffer;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->operation_ID = FSFETCHDATA64;
+
+       /* marshall the parameters */
+       bp = call->request;
+       bp[0] = htonl(FSFETCHDATA64);
+       bp[1] = htonl(vnode->fid.vid);
+       bp[2] = htonl(vnode->fid.vnode);
+       bp[3] = htonl(vnode->fid.unique);
+       bp[4] = htonl(upper_32_bits(offset));
+       bp[5] = htonl((u32) offset);
+       bp[6] = 0;
+       bp[7] = htonl((u32) length);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
 /*
  * fetch data from a file
  */
@@ -345,6 +491,10 @@ int afs_fs_fetch_data(struct afs_server *server,
        struct afs_call *call;
        __be32 *bp;
 
+       if (upper_32_bits(offset) || upper_32_bits(offset + length))
+               return afs_fs_fetch_data64(server, key, vnode, offset, length,
+                                          buffer, wait_mode);
+
        _enter("");
 
        call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
@@ -357,6 +507,7 @@ int afs_fs_fetch_data(struct afs_server *server,
        call->reply3 = buffer;
        call->service_id = FS_SERVICE;
        call->port = htons(AFS_FS_PORT);
+       call->operation_ID = FSFETCHDATA;
 
        /* marshall the parameters */
        bp = call->request;
@@ -476,8 +627,8 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call,
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
        xdr_decode_AFSFid(&bp, call->reply2);
-       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
-       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
        xdr_decode_AFSCallBack_raw(&bp, call->reply4);
        /* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
@@ -574,7 +725,7 @@ static int afs_deliver_fs_remove(struct afs_call *call,
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
        /* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
        _leave(" = 0 [done]");
@@ -657,8 +808,8 @@ static int afs_deliver_fs_link(struct afs_call *call,
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
-       xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
+       xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
        /* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
        _leave(" = 0 [done]");
@@ -746,8 +897,8 @@ static int afs_deliver_fs_symlink(struct afs_call *call,
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
        xdr_decode_AFSFid(&bp, call->reply2);
-       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
-       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+       xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
        /* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
        _leave(" = 0 [done]");
@@ -852,9 +1003,10 @@ static int afs_deliver_fs_rename(struct afs_call *call,
 
        /* unmarshall the reply once we've received all of it */
        bp = call->buffer;
-       xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
+       xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
        if (new_dvnode != orig_dvnode)
-               xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
+               xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
+                                         NULL);
        /* xdr_decode_AFSVolSync(&bp, call->replyX); */
 
        _leave(" = 0 [done]");
@@ -936,3 +1088,663 @@ int afs_fs_rename(struct afs_server *server,
 
        return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 }
+
+/*
+ * deliver reply data to an FS.StoreData
+ */
+static int afs_deliver_fs_store_data(struct afs_call *call,
+                                    struct sk_buff *skb, bool last)
+{
+       struct afs_vnode *vnode = call->reply;
+       const __be32 *bp;
+
+       _enter(",,%u", last);
+
+       afs_transfer_reply(call, skb);
+       if (!last) {
+               _leave(" = 0 [more]");
+               return 0;
+       }
+
+       if (call->reply_size != call->reply_max) {
+               _leave(" = -EBADMSG [%u != %u]",
+                      call->reply_size, call->reply_max);
+               return -EBADMSG;
+       }
+
+       /* unmarshall the reply once we've received all of it */
+       bp = call->buffer;
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
+                                 &call->store_version);
+       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+       afs_pages_written_back(vnode, call);
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+/*
+ * FS.StoreData operation type
+ */
+static const struct afs_call_type afs_RXFSStoreData = {
+       .name           = "FS.StoreData",
+       .deliver        = afs_deliver_fs_store_data,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSStoreData64 = {
+       .name           = "FS.StoreData64",
+       .deliver        = afs_deliver_fs_store_data,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * store a set of pages to a very large file
+ */
+static int afs_fs_store_data64(struct afs_server *server,
+                              struct afs_writeback *wb,
+                              pgoff_t first, pgoff_t last,
+                              unsigned offset, unsigned to,
+                              loff_t size, loff_t pos, loff_t i_size,
+                              const struct afs_wait_mode *wait_mode)
+{
+       struct afs_vnode *vnode = wb->vnode;
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter(",%x,{%x:%u},,",
+              key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+
+       call = afs_alloc_flat_call(&afs_RXFSStoreData64,
+                                  (4 + 6 + 3 * 2) * 4,
+                                  (21 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->wb = wb;
+       call->key = wb->key;
+       call->reply = vnode;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->mapping = vnode->vfs_inode.i_mapping;
+       call->first = first;
+       call->last = last;
+       call->first_offset = offset;
+       call->last_to = to;
+       call->send_pages = true;
+       call->store_version = vnode->status.data_version + 1;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSSTOREDATA64);
+       *bp++ = htonl(vnode->fid.vid);
+       *bp++ = htonl(vnode->fid.vnode);
+       *bp++ = htonl(vnode->fid.unique);
+
+       *bp++ = 0; /* mask */
+       *bp++ = 0; /* mtime */
+       *bp++ = 0; /* owner */
+       *bp++ = 0; /* group */
+       *bp++ = 0; /* unix mode */
+       *bp++ = 0; /* segment size */
+
+       *bp++ = htonl(pos >> 32);
+       *bp++ = htonl((u32) pos);
+       *bp++ = htonl(size >> 32);
+       *bp++ = htonl((u32) size);
+       *bp++ = htonl(i_size >> 32);
+       *bp++ = htonl((u32) i_size);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * store a set of pages
+ */
+int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
+                     pgoff_t first, pgoff_t last,
+                     unsigned offset, unsigned to,
+                     const struct afs_wait_mode *wait_mode)
+{
+       struct afs_vnode *vnode = wb->vnode;
+       struct afs_call *call;
+       loff_t size, pos, i_size;
+       __be32 *bp;
+
+       _enter(",%x,{%x:%u},,",
+              key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+
+       size = to - offset;
+       if (first != last)
+               size += (loff_t)(last - first) << PAGE_SHIFT;
+       pos = (loff_t)first << PAGE_SHIFT;
+       pos += offset;
+
+       i_size = i_size_read(&vnode->vfs_inode);
+       if (pos + size > i_size)
+               i_size = size + pos;
+
+       _debug("size %llx, at %llx, i_size %llx",
+              (unsigned long long) size, (unsigned long long) pos,
+              (unsigned long long) i_size);
+
+       if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
+               return afs_fs_store_data64(server, wb, first, last, offset, to,
+                                          size, pos, i_size, wait_mode);
+
+       call = afs_alloc_flat_call(&afs_RXFSStoreData,
+                                  (4 + 6 + 3) * 4,
+                                  (21 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->wb = wb;
+       call->key = wb->key;
+       call->reply = vnode;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->mapping = vnode->vfs_inode.i_mapping;
+       call->first = first;
+       call->last = last;
+       call->first_offset = offset;
+       call->last_to = to;
+       call->send_pages = true;
+       call->store_version = vnode->status.data_version + 1;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSSTOREDATA);
+       *bp++ = htonl(vnode->fid.vid);
+       *bp++ = htonl(vnode->fid.vnode);
+       *bp++ = htonl(vnode->fid.unique);
+
+       *bp++ = 0; /* mask */
+       *bp++ = 0; /* mtime */
+       *bp++ = 0; /* owner */
+       *bp++ = 0; /* group */
+       *bp++ = 0; /* unix mode */
+       *bp++ = 0; /* segment size */
+
+       *bp++ = htonl(pos);
+       *bp++ = htonl(size);
+       *bp++ = htonl(i_size);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * deliver reply data to an FS.StoreStatus
+ */
+static int afs_deliver_fs_store_status(struct afs_call *call,
+                                      struct sk_buff *skb, bool last)
+{
+       afs_dataversion_t *store_version;
+       struct afs_vnode *vnode = call->reply;
+       const __be32 *bp;
+
+       _enter(",,%u", last);
+
+       afs_transfer_reply(call, skb);
+       if (!last) {
+               _leave(" = 0 [more]");
+               return 0;
+       }
+
+       if (call->reply_size != call->reply_max) {
+               _leave(" = -EBADMSG [%u != %u]",
+                      call->reply_size, call->reply_max);
+               return -EBADMSG;
+       }
+
+       /* unmarshall the reply once we've received all of it */
+       store_version = NULL;
+       if (call->operation_ID == FSSTOREDATA)
+               store_version = &call->store_version;
+
+       bp = call->buffer;
+       xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
+       /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+/*
+ * FS.StoreStatus operation type
+ */
+static const struct afs_call_type afs_RXFSStoreStatus = {
+       .name           = "FS.StoreStatus",
+       .deliver        = afs_deliver_fs_store_status,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSStoreData_as_Status = {
+       .name           = "FS.StoreData",
+       .deliver        = afs_deliver_fs_store_status,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
+       .name           = "FS.StoreData64",
+       .deliver        = afs_deliver_fs_store_status,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * set the attributes on a very large file, using FS.StoreData rather than
+ * FS.StoreStatus so as to alter the file size also
+ */
+static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
+                                struct afs_vnode *vnode, struct iattr *attr,
+                                const struct afs_wait_mode *wait_mode)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter(",%x,{%x:%u},,",
+              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+       ASSERT(attr->ia_valid & ATTR_SIZE);
+
+       call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
+                                  (4 + 6 + 3 * 2) * 4,
+                                  (21 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+       call->reply = vnode;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->store_version = vnode->status.data_version + 1;
+       call->operation_ID = FSSTOREDATA;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSSTOREDATA64);
+       *bp++ = htonl(vnode->fid.vid);
+       *bp++ = htonl(vnode->fid.vnode);
+       *bp++ = htonl(vnode->fid.unique);
+
+       xdr_encode_AFS_StoreStatus(&bp, attr);
+
+       *bp++ = 0;                              /* position of start of write */
+       *bp++ = 0;
+       *bp++ = 0;                              /* size of write */
+       *bp++ = 0;
+       *bp++ = htonl(attr->ia_size >> 32);     /* new file length */
+       *bp++ = htonl((u32) attr->ia_size);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
+ * so as to alter the file size also
+ */
+static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
+                              struct afs_vnode *vnode, struct iattr *attr,
+                              const struct afs_wait_mode *wait_mode)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       _enter(",%x,{%x:%u},,",
+              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+       ASSERT(attr->ia_valid & ATTR_SIZE);
+       if (attr->ia_size >> 32)
+               return afs_fs_setattr_size64(server, key, vnode, attr,
+                                            wait_mode);
+
+       call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
+                                  (4 + 6 + 3) * 4,
+                                  (21 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+       call->reply = vnode;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->store_version = vnode->status.data_version + 1;
+       call->operation_ID = FSSTOREDATA;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSSTOREDATA);
+       *bp++ = htonl(vnode->fid.vid);
+       *bp++ = htonl(vnode->fid.vnode);
+       *bp++ = htonl(vnode->fid.unique);
+
+       xdr_encode_AFS_StoreStatus(&bp, attr);
+
+       *bp++ = 0;                              /* position of start of write */
+       *bp++ = 0;                              /* size of write */
+       *bp++ = htonl(attr->ia_size);           /* new file length */
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * set the attributes on a file, using FS.StoreData if there's a change in file
+ * size, and FS.StoreStatus otherwise
+ */
+int afs_fs_setattr(struct afs_server *server, struct key *key,
+                  struct afs_vnode *vnode, struct iattr *attr,
+                  const struct afs_wait_mode *wait_mode)
+{
+       struct afs_call *call;
+       __be32 *bp;
+
+       if (attr->ia_valid & ATTR_SIZE)
+               return afs_fs_setattr_size(server, key, vnode, attr,
+                                          wait_mode);
+
+       _enter(",%x,{%x:%u},,",
+              key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+       call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
+                                  (4 + 6) * 4,
+                                  (21 + 6) * 4);
+       if (!call)
+               return -ENOMEM;
+
+       call->key = key;
+       call->reply = vnode;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+       call->operation_ID = FSSTORESTATUS;
+
+       /* marshall the parameters */
+       bp = call->request;
+       *bp++ = htonl(FSSTORESTATUS);
+       *bp++ = htonl(vnode->fid.vid);
+       *bp++ = htonl(vnode->fid.vnode);
+       *bp++ = htonl(vnode->fid.unique);
+
+       xdr_encode_AFS_StoreStatus(&bp, attr);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * deliver reply data to an FS.GetVolumeStatus
+ */
+static int afs_deliver_fs_get_volume_status(struct afs_call *call,
+                                           struct sk_buff *skb, bool last)
+{
+       const __be32 *bp;
+       char *p;
+       int ret;
+
+       _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+       switch (call->unmarshall) {
+       case 0:
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the returned status record */
+       case 1:
+               _debug("extract status");
+               ret = afs_extract_data(call, skb, last, call->buffer,
+                                      12 * 4);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               bp = call->buffer;
+               xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the volume name length */
+       case 2:
+               ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->count = ntohl(call->tmp);
+               _debug("volname length: %u", call->count);
+               if (call->count >= AFSNAMEMAX)
+                       return -EBADMSG;
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the volume name */
+       case 3:
+               _debug("extract volname");
+               if (call->count > 0) {
+                       ret = afs_extract_data(call, skb, last, call->reply3,
+                                              call->count);
+                       switch (ret) {
+                       case 0:         break;
+                       case -EAGAIN:   return 0;
+                       default:        return ret;
+                       }
+               }
+
+               p = call->reply3;
+               p[call->count] = 0;
+               _debug("volname '%s'", p);
+
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the volume name padding */
+               if ((call->count & 3) == 0) {
+                       call->unmarshall++;
+                       goto no_volname_padding;
+               }
+               call->count = 4 - (call->count & 3);
+
+       case 4:
+               ret = afs_extract_data(call, skb, last, call->buffer,
+                                      call->count);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->offset = 0;
+               call->unmarshall++;
+       no_volname_padding:
+
+               /* extract the offline message length */
+       case 5:
+               ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->count = ntohl(call->tmp);
+               _debug("offline msg length: %u", call->count);
+               if (call->count >= AFSNAMEMAX)
+                       return -EBADMSG;
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the offline message */
+       case 6:
+               _debug("extract offline");
+               if (call->count > 0) {
+                       ret = afs_extract_data(call, skb, last, call->reply3,
+                                              call->count);
+                       switch (ret) {
+                       case 0:         break;
+                       case -EAGAIN:   return 0;
+                       default:        return ret;
+                       }
+               }
+
+               p = call->reply3;
+               p[call->count] = 0;
+               _debug("offline '%s'", p);
+
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the offline message padding */
+               if ((call->count & 3) == 0) {
+                       call->unmarshall++;
+                       goto no_offline_padding;
+               }
+               call->count = 4 - (call->count & 3);
+
+       case 7:
+               ret = afs_extract_data(call, skb, last, call->buffer,
+                                      call->count);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->offset = 0;
+               call->unmarshall++;
+       no_offline_padding:
+
+               /* extract the message of the day length */
+       case 8:
+               ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->count = ntohl(call->tmp);
+               _debug("motd length: %u", call->count);
+               if (call->count >= AFSNAMEMAX)
+                       return -EBADMSG;
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the message of the day */
+       case 9:
+               _debug("extract motd");
+               if (call->count > 0) {
+                       ret = afs_extract_data(call, skb, last, call->reply3,
+                                              call->count);
+                       switch (ret) {
+                       case 0:         break;
+                       case -EAGAIN:   return 0;
+                       default:        return ret;
+                       }
+               }
+
+               p = call->reply3;
+               p[call->count] = 0;
+               _debug("motd '%s'", p);
+
+               call->offset = 0;
+               call->unmarshall++;
+
+               /* extract the message of the day padding */
+               if ((call->count & 3) == 0) {
+                       call->unmarshall++;
+                       goto no_motd_padding;
+               }
+               call->count = 4 - (call->count & 3);
+
+       case 10:
+               ret = afs_extract_data(call, skb, last, call->buffer,
+                                      call->count);
+               switch (ret) {
+               case 0:         break;
+               case -EAGAIN:   return 0;
+               default:        return ret;
+               }
+
+               call->offset = 0;
+               call->unmarshall++;
+       no_motd_padding:
+
+       case 11:
+               _debug("trailer %d", skb->len);
+               if (skb->len != 0)
+                       return -EBADMSG;
+               break;
+       }
+
+       if (!last)
+               return 0;
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+/*
+ * destroy an FS.GetVolumeStatus call
+ */
+static void afs_get_volume_status_call_destructor(struct afs_call *call)
+{
+       kfree(call->reply3);
+       call->reply3 = NULL;
+       afs_flat_call_destructor(call);
+}
+
+/*
+ * FS.GetVolumeStatus operation type
+ */
+static const struct afs_call_type afs_RXFSGetVolumeStatus = {
+       .name           = "FS.GetVolumeStatus",
+       .deliver        = afs_deliver_fs_get_volume_status,
+       .abort_to_error = afs_abort_to_error,
+       .destructor     = afs_get_volume_status_call_destructor,
+};
+
+/*
+ * fetch the status of a volume
+ */
+int afs_fs_get_volume_status(struct afs_server *server,
+                            struct key *key,
+                            struct afs_vnode *vnode,
+                            struct afs_volume_status *vs,
+                            const struct afs_wait_mode *wait_mode)
+{
+       struct afs_call *call;
+       __be32 *bp;
+       void *tmpbuf;
+
+       _enter("");
+
+       tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
+
+       call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
+       if (!call) {
+               kfree(tmpbuf);
+               return -ENOMEM;
+       }
+
+       call->key = key;
+       call->reply = vnode;
+       call->reply2 = vs;
+       call->reply3 = tmpbuf;
+       call->service_id = FS_SERVICE;
+       call->port = htons(AFS_FS_PORT);
+
+       /* marshall the parameters */
+       bp = call->request;
+       bp[0] = htonl(FSGETVOLUMESTATUS);
+       bp[1] = htonl(vnode->fid.vid);
+
+       return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
index c184a4ee59950ddf48a69a1cd3f555134a465029..47f5fed7195dbbf11cc6ea9a1b7e2ca6f43cdbc3 100644 (file)
@@ -125,7 +125,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
        struct inode *inode;
        int ret;
 
-       _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique);
+       _enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique);
 
        as = sb->s_fs_info;
        data.volume = as->volume;
@@ -203,6 +203,23 @@ bad_inode:
        return ERR_PTR(ret);
 }
 
+/*
+ * mark the data attached to an inode as obsolete due to a write on the server
+ * - might also want to ditch all the outstanding writes and dirty pages
+ */
+void afs_zap_data(struct afs_vnode *vnode)
+{
+       _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+       /* nuke all the non-dirty pages that aren't locked, mapped or being
+        * written back in a regular file and completely discard the pages in a
+        * directory or symlink */
+       if (S_ISREG(vnode->vfs_inode.i_mode))
+               invalidate_remote_inode(&vnode->vfs_inode);
+       else
+               invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
+}
+
 /*
  * validate a vnode/inode
  * - there are several things we need to check
@@ -258,10 +275,8 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
 
        /* if the vnode's data version number changed then its contents are
         * different */
-       if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
-               _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
-               invalidate_remote_inode(&vnode->vfs_inode);
-       }
+       if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+               afs_zap_data(vnode);
 
        clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
        mutex_unlock(&vnode->validate_lock);
@@ -278,7 +293,7 @@ error_unlock:
 /*
  * read the attributes of an inode
  */
-int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
+int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                      struct kstat *stat)
 {
        struct inode *inode;
@@ -301,7 +316,7 @@ void afs_clear_inode(struct inode *inode)
 
        vnode = AFS_FS_I(inode);
 
-       _enter("{%x:%d.%d} v=%u x=%u t=%u }",
+       _enter("{%x:%u.%d} v=%u x=%u t=%u }",
               vnode->fid.vid,
               vnode->fid.vnode,
               vnode->fid.unique,
@@ -323,6 +338,7 @@ void afs_clear_inode(struct inode *inode)
                vnode->server = NULL;
        }
 
+       ASSERT(list_empty(&vnode->writebacks));
        ASSERT(!vnode->cb_promised);
 
 #ifdef AFS_CACHING_SUPPORT
@@ -339,3 +355,47 @@ void afs_clear_inode(struct inode *inode)
 
        _leave("");
 }
+
+/*
+ * set the attributes of an inode
+ */
+int afs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+       struct key *key;
+       int ret;
+
+       _enter("{%x:%u},{n=%s},%x",
+              vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+              attr->ia_valid);
+
+       if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
+                               ATTR_MTIME))) {
+               _leave(" = 0 [unsupported]");
+               return 0;
+       }
+
+       /* flush any dirty data outstanding on a regular file */
+       if (S_ISREG(vnode->vfs_inode.i_mode)) {
+               filemap_write_and_wait(vnode->vfs_inode.i_mapping);
+               afs_writeback_all(vnode);
+       }
+
+       if (attr->ia_valid & ATTR_FILE) {
+               key = attr->ia_file->private_data;
+       } else {
+               key = afs_request_key(vnode->volume->cell);
+               if (IS_ERR(key)) {
+                       ret = PTR_ERR(key);
+                       goto error;
+               }
+       }
+
+       ret = afs_vnode_setattr(vnode, key, attr);
+       if (!(attr->ia_valid & ATTR_FILE))
+               key_put(key);
+
+error:
+       _leave(" = %d", ret);
+       return ret;
+}
index d90c158cd9346d46c0abbb9dd01dcacf6b1c30f2..4953ba5a6f4452cac4293755ee3edf25392d241e 100644 (file)
@@ -21,6 +21,7 @@
 
 #define AFS_CELL_MAX_ADDRS 15
 
+struct pagevec;
 struct afs_call;
 
 typedef enum {
@@ -75,12 +76,15 @@ struct afs_call {
        struct key              *key;           /* security for this call */
        struct afs_server       *server;        /* server affected by incoming CM call */
        void                    *request;       /* request data (first part) */
-       void                    *request2;      /* request data (second part) */
+       struct address_space    *mapping;       /* page set */
+       struct afs_writeback    *wb;            /* writeback being performed */
        void                    *buffer;        /* reply receive buffer */
        void                    *reply;         /* reply buffer (first part) */
        void                    *reply2;        /* reply buffer (second part) */
        void                    *reply3;        /* reply buffer (third part) */
        void                    *reply4;        /* reply buffer (fourth part) */
+       pgoff_t                 first;          /* first page in mapping to deal with */
+       pgoff_t                 last;           /* last page in mapping to deal with */
        enum {                                  /* call state */
                AFS_CALL_REQUESTING,    /* request is being sent for outgoing call */
                AFS_CALL_AWAIT_REPLY,   /* awaiting reply to outgoing call */
@@ -97,14 +101,18 @@ struct afs_call {
        unsigned                request_size;   /* size of request data */
        unsigned                reply_max;      /* maximum size of reply */
        unsigned                reply_size;     /* current size of reply */
+       unsigned                first_offset;   /* offset into mapping[first] */
+       unsigned                last_to;        /* amount of mapping[last] */
        unsigned short          offset;         /* offset into received data store */
        unsigned char           unmarshall;     /* unmarshalling phase */
        bool                    incoming;       /* T if incoming call */
+       bool                    send_pages;     /* T if data from mapping should be sent */
        u16                     service_id;     /* RxRPC service ID to call */
        __be16                  port;           /* target UDP port */
        __be32                  operation_ID;   /* operation ID for an incoming call */
        u32                     count;          /* count for use in unmarshalling */
        __be32                  tmp;            /* place to extract temporary data */
+       afs_dataversion_t       store_version;  /* updated version expected from store */
 };
 
 struct afs_call_type {
@@ -123,6 +131,32 @@ struct afs_call_type {
        void (*destructor)(struct afs_call *call);
 };
 
+/*
+ * record of an outstanding writeback on a vnode
+ */
+struct afs_writeback {
+       struct list_head        link;           /* link in vnode->writebacks */
+       struct work_struct      writer;         /* work item to perform the writeback */
+       struct afs_vnode        *vnode;         /* vnode to which this write applies */
+       struct key              *key;           /* owner of this write */
+       wait_queue_head_t       waitq;          /* completion and ready wait queue */
+       pgoff_t                 first;          /* first page in batch */
+       pgoff_t                 point;          /* last page in current store op */
+       pgoff_t                 last;           /* last page in batch (inclusive) */
+       unsigned                offset_first;   /* offset into first page of start of write */
+       unsigned                to_last;        /* offset into last page of end of write */
+       int                     num_conflicts;  /* count of conflicting writes in list */
+       int                     usage;
+       bool                    conflicts;      /* T if has dependent conflicts */
+       enum {
+               AFS_WBACK_SYNCING,              /* synchronisation being performed */
+               AFS_WBACK_PENDING,              /* write pending */
+               AFS_WBACK_CONFLICTING,          /* conflicting writes posted */
+               AFS_WBACK_WRITING,              /* writing back */
+               AFS_WBACK_COMPLETE              /* the writeback record has been unlinked */
+       } state __attribute__((packed));
+};
+
 /*
  * AFS superblock private data
  * - there's one superblock per volume
@@ -305,6 +339,7 @@ struct afs_vnode {
        wait_queue_head_t       update_waitq;   /* status fetch waitqueue */
        int                     update_cnt;     /* number of outstanding ops that will update the
                                                 * status */
+       spinlock_t              writeback_lock; /* lock for writebacks */
        spinlock_t              lock;           /* waitqueue/flags lock */
        unsigned long           flags;
 #define AFS_VNODE_CB_BROKEN    0               /* set if vnode's callback was broken */
@@ -316,6 +351,8 @@ struct afs_vnode {
 
        long                    acl_order;      /* ACL check count (callback break count) */
 
+       struct list_head        writebacks;     /* alterations in pagecache that need writing */
+
        /* outstanding callback notification on this file */
        struct rb_node          server_rb;      /* link in server->fs_vnodes */
        struct rb_node          cb_promise;     /* link in server->cb_promises */
@@ -433,10 +470,6 @@ extern const struct file_operations afs_file_operations;
 extern int afs_open(struct inode *, struct file *);
 extern int afs_release(struct inode *, struct file *);
 
-#ifdef AFS_CACHING_SUPPORT
-extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
-#endif
-
 /*
  * fsclient.c
  */
@@ -467,6 +500,16 @@ extern int afs_fs_rename(struct afs_server *, struct key *,
                         struct afs_vnode *, const char *,
                         struct afs_vnode *, const char *,
                         const struct afs_wait_mode *);
+extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *,
+                            pgoff_t, pgoff_t, unsigned, unsigned,
+                            const struct afs_wait_mode *);
+extern int afs_fs_setattr(struct afs_server *, struct key *,
+                         struct afs_vnode *, struct iattr *,
+                         const struct afs_wait_mode *);
+extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
+                                   struct afs_vnode *,
+                                   struct afs_volume_status *,
+                                   const struct afs_wait_mode *);
 
 /*
  * inode.c
@@ -474,10 +517,10 @@ extern int afs_fs_rename(struct afs_server *, struct key *,
 extern struct inode *afs_iget(struct super_block *, struct key *,
                              struct afs_fid *, struct afs_file_status *,
                              struct afs_callback *);
+extern void afs_zap_data(struct afs_vnode *);
 extern int afs_validate(struct afs_vnode *, struct key *);
-extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
-                            struct kstat *);
-extern void afs_zap_permits(struct rcu_head *);
+extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int afs_setattr(struct dentry *, struct iattr *);
 extern void afs_clear_inode(struct inode *);
 
 /*
@@ -533,6 +576,7 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
  */
 extern void afs_clear_permits(struct afs_vnode *);
 extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
+extern void afs_zap_permits(struct rcu_head *);
 extern struct key *afs_request_key(struct afs_cell *);
 extern int afs_permission(struct inode *, int, struct nameidata *);
 
@@ -629,6 +673,11 @@ extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *,
                             struct afs_file_status *, struct afs_server **);
 extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
                            struct key *, const char *, const char *);
+extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
+                               unsigned, unsigned);
+extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
+extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
+                                      struct afs_volume_status *);
 
 /*
  * volume.c
@@ -645,6 +694,23 @@ extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *);
 extern int afs_volume_release_fileserver(struct afs_vnode *,
                                         struct afs_server *, int);
 
+/*
+ * write.c
+ */
+extern int afs_set_page_dirty(struct page *);
+extern void afs_put_writeback(struct afs_writeback *);
+extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_writepage(struct page *, struct writeback_control *);
+extern int afs_writepages(struct address_space *, struct writeback_control *);
+extern int afs_write_inode(struct inode *, int);
+extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
+extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
+                             unsigned long, loff_t);
+extern int afs_writeback_all(struct afs_vnode *);
+extern int afs_fsync(struct file *, struct dentry *, int);
+
+
 /*****************************************************************************/
 /*
  * debug tracing
@@ -726,6 +792,21 @@ do {                                                                       \
        }                                                               \
 } while(0)
 
+#define ASSERTRANGE(L, OP1, N, OP2, H)                                 \
+do {                                                                   \
+       if (unlikely(!((L) OP1 (N)) || !((N) OP2 (H)))) {               \
+               printk(KERN_ERR "\n");                                  \
+               printk(KERN_ERR "AFS: Assertion failed\n");             \
+               printk(KERN_ERR "%lu "#OP1" %lu "#OP2" %lu is false\n", \
+                      (unsigned long)(L), (unsigned long)(N),          \
+                      (unsigned long)(H));                             \
+               printk(KERN_ERR "0x%lx "#OP1" 0x%lx "#OP2" 0x%lx is false\n", \
+                      (unsigned long)(L), (unsigned long)(N),          \
+                      (unsigned long)(H));                             \
+               BUG();                                                  \
+       }                                                               \
+} while(0)
+
 #define ASSERTIF(C, X)                                         \
 do {                                                           \
        if (unlikely((C) && !(X))) {                            \
@@ -758,6 +839,10 @@ do {                                               \
 do {                                           \
 } while(0)
 
+#define ASSERTRANGE(L, OP1, N, OP2, H)         \
+do {                                           \
+} while(0)
+
 #define ASSERTIF(C, X)                         \
 do {                                           \
 } while(0)
index 80ec6fd19a733fb50efb3fb896061fea76a08298..f1f71ff7d5c673ccccffd02f965224ea51456934 100644 (file)
@@ -149,6 +149,7 @@ error_cache:
        afs_vlocation_purge();
        afs_cell_purge();
        afs_proc_cleanup();
+       rcu_barrier();
        printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
        return ret;
 }
@@ -176,6 +177,7 @@ static void __exit afs_exit(void)
        cachefs_unregister_netfs(&afs_cache_netfs);
 #endif
        afs_proc_cleanup();
+       rcu_barrier();
 }
 
 module_exit(afs_exit);
index cdb9792d8161eb0324fdf3c6315cfae435d0b86a..d1a889c4074292b8dbf6d4f251497e681067cd1a 100644 (file)
@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code)
 {
        switch (abort_code) {
        case 13:                return -EACCES;
+       case 27:                return -EFBIG;
        case 30:                return -EROFS;
        case VSALVAGE:          return -EIO;
        case VNOVNODE:          return -ENOENT;
index 034fcfd4e3304d2ff6942c2a91c5ab6237460558..a3684dcc76e7985a4a2b53ea32c81cd12f61cd86 100644 (file)
@@ -36,7 +36,7 @@ const struct inode_operations afs_mntpt_inode_operations = {
        .lookup         = afs_mntpt_lookup,
        .follow_link    = afs_mntpt_follow_link,
        .readlink       = page_readlink,
-       .getattr        = afs_inode_getattr,
+       .getattr        = afs_getattr,
 };
 
 static LIST_HEAD(afs_vfsmounts);
@@ -58,7 +58,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
        char *buf;
        int ret;
 
-       _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique);
+       _enter("{%x:%u,%u}",
+              vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
        /* read the contents of the symlink into the pagecache */
        page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
index 222c1a3abbb8fdbcf30a6c9fd48c25b0d34f1b25..1b36f45076ade8a365661120baf7741c2e3cef2b 100644 (file)
@@ -236,6 +236,70 @@ void afs_flat_call_destructor(struct afs_call *call)
        call->buffer = NULL;
 }
 
+/*
+ * attach the data from a bunch of pages on an inode to a call
+ */
+int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov)
+{
+       struct page *pages[8];
+       unsigned count, n, loop, offset, to;
+       pgoff_t first = call->first, last = call->last;
+       int ret;
+
+       _enter("");
+
+       offset = call->first_offset;
+       call->first_offset = 0;
+
+       do {
+               _debug("attach %lx-%lx", first, last);
+
+               count = last - first + 1;
+               if (count > ARRAY_SIZE(pages))
+                       count = ARRAY_SIZE(pages);
+               n = find_get_pages_contig(call->mapping, first, count, pages);
+               ASSERTCMP(n, ==, count);
+
+               loop = 0;
+               do {
+                       msg->msg_flags = 0;
+                       to = PAGE_SIZE;
+                       if (first + loop >= last)
+                               to = call->last_to;
+                       else
+                               msg->msg_flags = MSG_MORE;
+                       iov->iov_base = kmap(pages[loop]) + offset;
+                       iov->iov_len = to - offset;
+                       offset = 0;
+
+                       _debug("- range %u-%u%s",
+                              offset, to, msg->msg_flags ? " [more]" : "");
+                       msg->msg_iov = (struct iovec *) iov;
+                       msg->msg_iovlen = 1;
+
+                       /* have to change the state *before* sending the last
+                        * packet as RxRPC might give us the reply before it
+                        * returns from sending the request */
+                       if (first + loop >= last)
+                               call->state = AFS_CALL_AWAIT_REPLY;
+                       ret = rxrpc_kernel_send_data(call->rxcall, msg,
+                                                    to - offset);
+                       kunmap(pages[loop]);
+                       if (ret < 0)
+                               break;
+               } while (++loop < count);
+               first += count;
+
+               for (loop = 0; loop < count; loop++)
+                       put_page(pages[loop]);
+               if (ret < 0)
+                       break;
+       } while (first <= last);
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
 /*
  * initiate a call
  */
@@ -253,8 +317,9 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
        ASSERT(call->type != NULL);
        ASSERT(call->type->name != NULL);
 
-       _debug("MAKE %p{%s} [%d]",
-              call, call->type->name, atomic_read(&afs_outstanding_calls));
+       _debug("____MAKE %p{%s,%x} [%d]____",
+              call, call->type->name, key_serial(call->key),
+              atomic_read(&afs_outstanding_calls));
 
        call->wait_mode = wait_mode;
        INIT_WORK(&call->async_work, afs_process_async_call);
@@ -289,16 +354,23 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
        msg.msg_iovlen          = 1;
        msg.msg_control         = NULL;
        msg.msg_controllen      = 0;
-       msg.msg_flags           = 0;
+       msg.msg_flags           = (call->send_pages ? MSG_MORE : 0);
 
        /* have to change the state *before* sending the last packet as RxRPC
         * might give us the reply before it returns from sending the
         * request */
-       call->state = AFS_CALL_AWAIT_REPLY;
+       if (!call->send_pages)
+               call->state = AFS_CALL_AWAIT_REPLY;
        ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size);
        if (ret < 0)
                goto error_do_abort;
 
+       if (call->send_pages) {
+               ret = afs_send_pages(call, &msg, iov);
+               if (ret < 0)
+                       goto error_do_abort;
+       }
+
        /* at this point, an async call may no longer exist as it may have
         * already completed */
        return wait_mode->wait(call);
index f9f424d804589aa108d0d19821521bb6386e9bbc..e0ea88b63ebf429e7d2ec45c7f6377b24ab27364 100644 (file)
@@ -109,7 +109,7 @@ void afs_clear_permits(struct afs_vnode *vnode)
 {
        struct afs_permits *permits;
 
-       _enter("{%x}", vnode->fid.vnode);
+       _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
 
        mutex_lock(&vnode->permits_lock);
        permits = vnode->permits;
@@ -132,7 +132,8 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order)
        struct afs_vnode *auth_vnode;
        int count, loop;
 
-       _enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order);
+       _enter("{%x:%u},%x,%lx",
+              vnode->fid.vid, vnode->fid.vnode, key_serial(key), acl_order);
 
        auth_vnode = afs_get_auth_inode(vnode, key);
        if (IS_ERR(auth_vnode)) {
@@ -220,7 +221,8 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
        bool valid;
        int loop, ret;
 
-       _enter("");
+       _enter("{%x:%u},%x",
+              vnode->fid.vid, vnode->fid.vnode, key_serial(key));
 
        auth_vnode = afs_get_auth_inode(vnode, key);
        if (IS_ERR(auth_vnode)) {
@@ -268,9 +270,9 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
                        _leave(" = %d", ret);
                        return ret;
                }
+               *_access = vnode->status.caller_access;
        }
 
-       *_access = vnode->status.caller_access;
        iput(&auth_vnode->vfs_inode);
        _leave(" = 0 [access %x]", *_access);
        return 0;
@@ -288,7 +290,7 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
        struct key *key;
        int ret;
 
-       _enter("{{%x:%x},%lx},%x,",
+       _enter("{{%x:%u},%lx},%x,",
               vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
 
        key = afs_request_key(vnode->volume->cell);
index 96bb23b476a2f4282a03a07a9a146d2e4d1b2e24..231ae4150279e2b98f78dac4b9a45ec5bde26633 100644 (file)
@@ -252,6 +252,9 @@ static void afs_destroy_server(struct afs_server *server)
 {
        _enter("%p", server);
 
+       ASSERTIF(server->cb_break_head != server->cb_break_tail,
+                delayed_work_pending(&server->cb_break_work));
+
        ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
        ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
        ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
index 7030d76155fcdf42398ccc71e8a6c8af17237d9a..579af632c8e8e81bae602daa79afcb1b62363968 100644 (file)
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
+#include <linux/statfs.h>
 #include "internal.h"
 
 #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
 
 static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
                            unsigned long flags);
-
 static int afs_get_sb(struct file_system_type *fs_type,
                      int flags, const char *dev_name,
                      void *data, struct vfsmount *mnt);
-
 static struct inode *afs_alloc_inode(struct super_block *sb);
-
 static void afs_put_super(struct super_block *sb);
-
 static void afs_destroy_inode(struct inode *inode);
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
 
 struct file_system_type afs_fs_type = {
        .owner          = THIS_MODULE,
@@ -47,9 +45,10 @@ struct file_system_type afs_fs_type = {
 };
 
 static const struct super_operations afs_super_ops = {
-       .statfs         = simple_statfs,
+       .statfs         = afs_statfs,
        .alloc_inode    = afs_alloc_inode,
        .drop_inode     = generic_delete_inode,
+       .write_inode    = afs_write_inode,
        .destroy_inode  = afs_destroy_inode,
        .clear_inode    = afs_clear_inode,
        .umount_begin   = afs_umount_begin,
@@ -66,7 +65,7 @@ enum {
        afs_opt_vol,
 };
 
-static const match_table_t afs_options_list = {
+static match_table_t afs_options_list = {
        { afs_opt_cell,         "cell=%s"       },
        { afs_opt_rwpath,       "rwpath"        },
        { afs_opt_vol,          "vol=%s"        },
@@ -459,7 +458,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
                init_waitqueue_head(&vnode->update_waitq);
                mutex_init(&vnode->permits_lock);
                mutex_init(&vnode->validate_lock);
+               spin_lock_init(&vnode->writeback_lock);
                spin_lock_init(&vnode->lock);
+               INIT_LIST_HEAD(&vnode->writebacks);
                INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
        }
 }
@@ -485,6 +486,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
        vnode->flags            = 1 << AFS_VNODE_UNSET;
        vnode->cb_promised      = false;
 
+       _leave(" = %p", &vnode->vfs_inode);
        return &vnode->vfs_inode;
 }
 
@@ -495,7 +497,7 @@ static void afs_destroy_inode(struct inode *inode)
 {
        struct afs_vnode *vnode = AFS_FS_I(inode);
 
-       _enter("{%lu}", inode->i_ino);
+       _enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode);
 
        _debug("DESTROY INODE %p", inode);
 
@@ -504,3 +506,36 @@ static void afs_destroy_inode(struct inode *inode)
        kmem_cache_free(afs_inode_cachep, vnode);
        atomic_dec(&afs_count_active_inodes);
 }
+
+/*
+ * return information about an AFS volume
+ */
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct afs_volume_status vs;
+       struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+       struct key *key;
+       int ret;
+
+       key = afs_request_key(vnode->volume->cell);
+       if (IS_ERR(key))
+               return PTR_ERR(key);
+
+       ret = afs_vnode_get_volume_status(vnode, key, &vs);
+       key_put(key);
+       if (ret < 0) {
+               _leave(" = %d", ret);
+               return ret;
+       }
+
+       buf->f_type     = dentry->d_sb->s_magic;
+       buf->f_bsize    = AFS_BLOCK_SIZE;
+       buf->f_namelen  = AFSNAMEMAX - 1;
+
+       if (vs.max_quota == 0)
+               buf->f_blocks = vs.part_max_blocks;
+       else
+               buf->f_blocks = vs.max_quota;
+       buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use;
+       return 0;
+}
index a1904ab8426adb12fdecfcc3a353da6b909bdee1..c36c98ce2c3ce75c7c6a214194f521a79c6a0bbe 100644 (file)
@@ -175,24 +175,33 @@ static void afs_vnode_deleted_remotely(struct afs_vnode *vnode)
 {
        struct afs_server *server;
 
+       _enter("{%p}", vnode->server);
+
        set_bit(AFS_VNODE_DELETED, &vnode->flags);
 
        server = vnode->server;
-       if (vnode->cb_promised) {
-               spin_lock(&server->cb_lock);
+       if (server) {
                if (vnode->cb_promised) {
-                       rb_erase(&vnode->cb_promise, &server->cb_promises);
-                       vnode->cb_promised = false;
+                       spin_lock(&server->cb_lock);
+                       if (vnode->cb_promised) {
+                               rb_erase(&vnode->cb_promise,
+                                        &server->cb_promises);
+                               vnode->cb_promised = false;
+                       }
+                       spin_unlock(&server->cb_lock);
                }
-               spin_unlock(&server->cb_lock);
-       }
 
-       spin_lock(&vnode->server->fs_lock);
-       rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
-       spin_unlock(&vnode->server->fs_lock);
+               spin_lock(&server->fs_lock);
+               rb_erase(&vnode->server_rb, &server->fs_vnodes);
+               spin_unlock(&server->fs_lock);
 
-       vnode->server = NULL;
-       afs_put_server(server);
+               vnode->server = NULL;
+               afs_put_server(server);
+       } else {
+               ASSERT(!vnode->cb_promised);
+       }
+
+       _leave("");
 }
 
 /*
@@ -225,7 +234,7 @@ void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
  */
 static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
 {
-       _enter("%p,%d", vnode, ret);
+       _enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret);
 
        spin_lock(&vnode->lock);
 
@@ -261,7 +270,7 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode,
 
        DECLARE_WAITQUEUE(myself, current);
 
-       _enter("%s,{%u,%u,%u}",
+       _enter("%s,{%x:%u.%u}",
               vnode->volume->vlocation->vldb.name,
               vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
@@ -389,7 +398,7 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%x,,,",
+       _enter("%s{%x:%u.%u},%x,,,",
               vnode->volume->vlocation->vldb.name,
               vnode->fid.vid,
               vnode->fid.vnode,
@@ -446,7 +455,7 @@ int afs_vnode_create(struct afs_vnode *vnode, struct key *key,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%x,%s,,",
+       _enter("%s{%x:%u.%u},%x,%s,,",
               vnode->volume->vlocation->vldb.name,
               vnode->fid.vid,
               vnode->fid.vnode,
@@ -502,7 +511,7 @@ int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%x,%s",
+       _enter("%s{%x:%u.%u},%x,%s",
               vnode->volume->vlocation->vldb.name,
               vnode->fid.vid,
               vnode->fid.vnode,
@@ -557,7 +566,7 @@ extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
+       _enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s",
               dvnode->volume->vlocation->vldb.name,
               dvnode->fid.vid,
               dvnode->fid.vnode,
@@ -628,7 +637,7 @@ int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%x,%s,%s,,,",
+       _enter("%s{%x:%u.%u},%x,%s,%s,,,",
               vnode->volume->vlocation->vldb.name,
               vnode->fid.vid,
               vnode->fid.vnode,
@@ -687,7 +696,7 @@ int afs_vnode_rename(struct afs_vnode *orig_dvnode,
        struct afs_server *server;
        int ret;
 
-       _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
+       _enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s",
               orig_dvnode->volume->vlocation->vldb.name,
               orig_dvnode->fid.vid,
               orig_dvnode->fid.vnode,
@@ -753,3 +762,162 @@ no_server:
        _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
        return PTR_ERR(server);
 }
+
+/*
+ * write to a file
+ */
+int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last,
+                        unsigned offset, unsigned to)
+{
+       struct afs_server *server;
+       struct afs_vnode *vnode = wb->vnode;
+       int ret;
+
+       _enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x",
+              vnode->volume->vlocation->vldb.name,
+              vnode->fid.vid,
+              vnode->fid.vnode,
+              vnode->fid.unique,
+              key_serial(wb->key),
+              first, last, offset, to);
+
+       /* this op will fetch the status */
+       spin_lock(&vnode->lock);
+       vnode->update_cnt++;
+       spin_unlock(&vnode->lock);
+
+       do {
+               /* pick a server to query */
+               server = afs_volume_pick_fileserver(vnode);
+               if (IS_ERR(server))
+                       goto no_server;
+
+               _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+               ret = afs_fs_store_data(server, wb, first, last, offset, to,
+                                       &afs_sync_call);
+
+       } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+       /* adjust the flags */
+       if (ret == 0) {
+               afs_vnode_finalise_status_update(vnode, server);
+               afs_put_server(server);
+       } else {
+               afs_vnode_status_update_failed(vnode, ret);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+
+no_server:
+       spin_lock(&vnode->lock);
+       vnode->update_cnt--;
+       ASSERTCMP(vnode->update_cnt, >=, 0);
+       spin_unlock(&vnode->lock);
+       return PTR_ERR(server);
+}
+
+/*
+ * set the attributes on a file
+ */
+int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key,
+                     struct iattr *attr)
+{
+       struct afs_server *server;
+       int ret;
+
+       _enter("%s{%x:%u.%u},%x",
+              vnode->volume->vlocation->vldb.name,
+              vnode->fid.vid,
+              vnode->fid.vnode,
+              vnode->fid.unique,
+              key_serial(key));
+
+       /* this op will fetch the status */
+       spin_lock(&vnode->lock);
+       vnode->update_cnt++;
+       spin_unlock(&vnode->lock);
+
+       do {
+               /* pick a server to query */
+               server = afs_volume_pick_fileserver(vnode);
+               if (IS_ERR(server))
+                       goto no_server;
+
+               _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+               ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call);
+
+       } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+       /* adjust the flags */
+       if (ret == 0) {
+               afs_vnode_finalise_status_update(vnode, server);
+               afs_put_server(server);
+       } else {
+               afs_vnode_status_update_failed(vnode, ret);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+
+no_server:
+       spin_lock(&vnode->lock);
+       vnode->update_cnt--;
+       ASSERTCMP(vnode->update_cnt, >=, 0);
+       spin_unlock(&vnode->lock);
+       return PTR_ERR(server);
+}
+
+/*
+ * get the status of a volume
+ */
+int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
+                               struct afs_volume_status *vs)
+{
+       struct afs_server *server;
+       int ret;
+
+       _enter("%s{%x:%u.%u},%x,",
+              vnode->volume->vlocation->vldb.name,
+              vnode->fid.vid,
+              vnode->fid.vnode,
+              vnode->fid.unique,
+              key_serial(key));
+
+       /* this op will fetch the status */
+       spin_lock(&vnode->lock);
+       vnode->update_cnt++;
+       spin_unlock(&vnode->lock);
+
+       do {
+               /* pick a server to query */
+               server = afs_volume_pick_fileserver(vnode);
+               if (IS_ERR(server))
+                       goto no_server;
+
+               _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+               ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call);
+
+       } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+       /* adjust the flags */
+       if (ret == 0) {
+               afs_vnode_finalise_status_update(vnode, server);
+               afs_put_server(server);
+       } else {
+               afs_vnode_status_update_failed(vnode, ret);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+
+no_server:
+       spin_lock(&vnode->lock);
+       vnode->update_cnt--;
+       ASSERTCMP(vnode->update_cnt, >=, 0);
+       spin_unlock(&vnode->lock);
+       return PTR_ERR(server);
+}
diff --git a/fs/afs/write.c b/fs/afs/write.c
new file mode 100644 (file)
index 0000000..28f3751
--- /dev/null
@@ -0,0 +1,828 @@
+/* handling of writes to regular files and writing back to the server
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/pagevec.h>
+#include "internal.h"
+
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+                                          struct page *page);
+
+/*
+ * mark a page as having been made dirty and thus needing writeback
+ */
+int afs_set_page_dirty(struct page *page)
+{
+       _enter("");
+       return __set_page_dirty_nobuffers(page);
+}
+
+/*
+ * unlink a writeback record because its usage has reached zero
+ * - must be called with the wb->vnode->writeback_lock held
+ */
+static void afs_unlink_writeback(struct afs_writeback *wb)
+{
+       struct afs_writeback *front;
+       struct afs_vnode *vnode = wb->vnode;
+
+       list_del_init(&wb->link);
+       if (!list_empty(&vnode->writebacks)) {
+               /* if an fsync rises to the front of the queue then wake it
+                * up */
+               front = list_entry(vnode->writebacks.next,
+                                  struct afs_writeback, link);
+               if (front->state == AFS_WBACK_SYNCING) {
+                       _debug("wake up sync");
+                       front->state = AFS_WBACK_COMPLETE;
+                       wake_up(&front->waitq);
+               }
+       }
+}
+
+/*
+ * free a writeback record
+ */
+static void afs_free_writeback(struct afs_writeback *wb)
+{
+       _enter("");
+       key_put(wb->key);
+       kfree(wb);
+}
+
+/*
+ * dispose of a reference to a writeback record
+ */
+void afs_put_writeback(struct afs_writeback *wb)
+{
+       struct afs_vnode *vnode = wb->vnode;
+
+       _enter("{%d}", wb->usage);
+
+       spin_lock(&vnode->writeback_lock);
+       if (--wb->usage == 0)
+               afs_unlink_writeback(wb);
+       else
+               wb = NULL;
+       spin_unlock(&vnode->writeback_lock);
+       if (wb)
+               afs_free_writeback(wb);
+}
+
+/*
+ * partly or wholly fill a page that's under preparation for writing
+ */
+static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
+                        unsigned start, unsigned len, struct page *page)
+{
+       int ret;
+
+       _enter(",,%u,%u", start, len);
+
+       ASSERTCMP(start + len, <=, PAGE_SIZE);
+
+       ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+       if (ret < 0) {
+               if (ret == -ENOENT) {
+                       _debug("got NOENT from server"
+                              " - marking file deleted and stale");
+                       set_bit(AFS_VNODE_DELETED, &vnode->flags);
+                       ret = -ESTALE;
+               }
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * prepare a page for being written to
+ */
+static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
+                           struct key *key, unsigned offset, unsigned to)
+{
+       unsigned eof, tail, start, stop, len;
+       loff_t i_size, pos;
+       void *p;
+       int ret;
+
+       _enter("");
+
+       if (offset == 0 && to == PAGE_SIZE)
+               return 0;
+
+       p = kmap_atomic(page, KM_USER0);
+
+       i_size = i_size_read(&vnode->vfs_inode);
+       pos = (loff_t) page->index << PAGE_SHIFT;
+       if (pos >= i_size) {
+               /* partial write, page beyond EOF */
+               _debug("beyond");
+               if (offset > 0)
+                       memset(p, 0, offset);
+               if (to < PAGE_SIZE)
+                       memset(p + to, 0, PAGE_SIZE - to);
+               kunmap_atomic(p, KM_USER0);
+               return 0;
+       }
+
+       if (i_size - pos >= PAGE_SIZE) {
+               /* partial write, page entirely before EOF */
+               _debug("before");
+               tail = eof = PAGE_SIZE;
+       } else {
+               /* partial write, page overlaps EOF */
+               eof = i_size - pos;
+               _debug("overlap %u", eof);
+               tail = max(eof, to);
+               if (tail < PAGE_SIZE)
+                       memset(p + tail, 0, PAGE_SIZE - tail);
+               if (offset > eof)
+                       memset(p + eof, 0, PAGE_SIZE - eof);
+       }
+
+       kunmap_atomic(p, KM_USER0);
+
+       ret = 0;
+       if (offset > 0 || eof > to) {
+               /* need to fill one or two bits that aren't going to be written
+                * (cover both fillers in one read if there are two) */
+               start = (offset > 0) ? 0 : to;
+               stop = (eof > to) ? eof : offset;
+               len = stop - start;
+               _debug("wr=%u-%u av=0-%u rd=%u@%u",
+                      offset, to, eof, start, len);
+               ret = afs_fill_page(vnode, key, start, len, page);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * prepare to perform part of a write to a page
+ * - the caller holds the page locked, preventing it from being written out or
+ *   modified by anyone else
+ */
+int afs_prepare_write(struct file *file, struct page *page,
+                     unsigned offset, unsigned to)
+{
+       struct afs_writeback *candidate, *wb;
+       struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+       struct key *key = file->private_data;
+       pgoff_t index;
+       int ret;
+
+       _enter("{%x:%u},{%lx},%u,%u",
+              vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+       candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
+       if (!candidate)
+               return -ENOMEM;
+       candidate->vnode = vnode;
+       candidate->first = candidate->last = page->index;
+       candidate->offset_first = offset;
+       candidate->to_last = to;
+       candidate->usage = 1;
+       candidate->state = AFS_WBACK_PENDING;
+       init_waitqueue_head(&candidate->waitq);
+
+       if (!PageUptodate(page)) {
+               _debug("not up to date");
+               ret = afs_prepare_page(vnode, page, key, offset, to);
+               if (ret < 0) {
+                       kfree(candidate);
+                       _leave(" = %d [prep]", ret);
+                       return ret;
+               }
+               SetPageUptodate(page);
+       }
+
+try_again:
+       index = page->index;
+       spin_lock(&vnode->writeback_lock);
+
+       /* see if this page is already pending a writeback under a suitable key
+        * - if so we can just join onto that one */
+       wb = (struct afs_writeback *) page_private(page);
+       if (wb) {
+               if (wb->key == key && wb->state == AFS_WBACK_PENDING)
+                       goto subsume_in_current_wb;
+               goto flush_conflicting_wb;
+       }
+
+       if (index > 0) {
+               /* see if we can find an already pending writeback that we can
+                * append this page to */
+               list_for_each_entry(wb, &vnode->writebacks, link) {
+                       if (wb->last == index - 1 && wb->key == key &&
+                           wb->state == AFS_WBACK_PENDING)
+                               goto append_to_previous_wb;
+               }
+       }
+
+       list_add_tail(&candidate->link, &vnode->writebacks);
+       candidate->key = key_get(key);
+       spin_unlock(&vnode->writeback_lock);
+       SetPagePrivate(page);
+       set_page_private(page, (unsigned long) candidate);
+       _leave(" = 0 [new]");
+       return 0;
+
+subsume_in_current_wb:
+       _debug("subsume");
+       ASSERTRANGE(wb->first, <=, index, <=, wb->last);
+       if (index == wb->first && offset < wb->offset_first)
+               wb->offset_first = offset;
+       if (index == wb->last && to > wb->to_last)
+               wb->to_last = to;
+       spin_unlock(&vnode->writeback_lock);
+       kfree(candidate);
+       _leave(" = 0 [sub]");
+       return 0;
+
+append_to_previous_wb:
+       _debug("append into %lx-%lx", wb->first, wb->last);
+       wb->usage++;
+       wb->last++;
+       wb->to_last = to;
+       spin_unlock(&vnode->writeback_lock);
+       SetPagePrivate(page);
+       set_page_private(page, (unsigned long) wb);
+       kfree(candidate);
+       _leave(" = 0 [app]");
+       return 0;
+
+       /* the page is currently bound to another context, so if it's dirty we
+        * need to flush it before we can use the new context */
+flush_conflicting_wb:
+       _debug("flush conflict");
+       if (wb->state == AFS_WBACK_PENDING)
+               wb->state = AFS_WBACK_CONFLICTING;
+       spin_unlock(&vnode->writeback_lock);
+       if (PageDirty(page)) {
+               ret = afs_write_back_from_locked_page(wb, page);
+               if (ret < 0) {
+                       afs_put_writeback(candidate);
+                       _leave(" = %d", ret);
+                       return ret;
+               }
+       }
+
+       /* the page holds a ref on the writeback record */
+       afs_put_writeback(wb);
+       set_page_private(page, 0);
+       ClearPagePrivate(page);
+       goto try_again;
+}
+
+/*
+ * finalise part of a write to a page
+ */
+int afs_commit_write(struct file *file, struct page *page,
+                    unsigned offset, unsigned to)
+{
+       struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+       loff_t i_size, maybe_i_size;
+
+       _enter("{%x:%u},{%lx},%u,%u",
+              vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+       maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
+       maybe_i_size += to;
+
+       i_size = i_size_read(&vnode->vfs_inode);
+       if (maybe_i_size > i_size) {
+               spin_lock(&vnode->writeback_lock);
+               i_size = i_size_read(&vnode->vfs_inode);
+               if (maybe_i_size > i_size)
+                       i_size_write(&vnode->vfs_inode, maybe_i_size);
+               spin_unlock(&vnode->writeback_lock);
+       }
+
+       set_page_dirty(page);
+
+       if (PageDirty(page))
+               _debug("dirtied");
+
+       return 0;
+}
+
+/*
+ * kill all the pages in the given range
+ */
+static void afs_kill_pages(struct afs_vnode *vnode, bool error,
+                          pgoff_t first, pgoff_t last)
+{
+       struct pagevec pv;
+       unsigned count, loop;
+
+       _enter("{%x:%u},%lx-%lx",
+              vnode->fid.vid, vnode->fid.vnode, first, last);
+
+       pagevec_init(&pv, 0);
+
+       do {
+               _debug("kill %lx-%lx", first, last);
+
+               count = last - first + 1;
+               if (count > PAGEVEC_SIZE)
+                       count = PAGEVEC_SIZE;
+               pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping,
+                                             first, count, pv.pages);
+               ASSERTCMP(pv.nr, ==, count);
+
+               for (loop = 0; loop < count; loop++) {
+                       ClearPageUptodate(pv.pages[loop]);
+                       if (error)
+                               SetPageError(pv.pages[loop]);
+                       end_page_writeback(pv.pages[loop]);
+               }
+
+               __pagevec_release(&pv);
+       } while (first < last);
+
+       _leave("");
+}
+
+/*
+ * synchronously write back the locked page and any subsequent non-locked dirty
+ * pages also covered by the same writeback record
+ */
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+                                          struct page *primary_page)
+{
+       struct page *pages[8], *page;
+       unsigned long count;
+       unsigned n, offset, to;
+       pgoff_t start, first, last;
+       int loop, ret;
+
+       _enter(",%lx", primary_page->index);
+
+       count = 1;
+       if (!clear_page_dirty_for_io(primary_page))
+               BUG();
+       if (test_set_page_writeback(primary_page))
+               BUG();
+
+       /* find all consecutive lockable dirty pages, stopping when we find a
+        * page that is not immediately lockable, is not dirty or is missing,
+        * or we reach the end of the range */
+       start = primary_page->index;
+       if (start >= wb->last)
+               goto no_more;
+       start++;
+       do {
+               _debug("more %lx [%lx]", start, count);
+               n = wb->last - start + 1;
+               if (n > ARRAY_SIZE(pages))
+                       n = ARRAY_SIZE(pages);
+               n = find_get_pages_contig(wb->vnode->vfs_inode.i_mapping,
+                                         start, n, pages);
+               _debug("fgpc %u", n);
+               if (n == 0)
+                       goto no_more;
+               if (pages[0]->index != start) {
+                       do {
+                               put_page(pages[--n]);
+                       } while (n > 0);
+                       goto no_more;
+               }
+
+               for (loop = 0; loop < n; loop++) {
+                       page = pages[loop];
+                       if (page->index > wb->last)
+                               break;
+                       if (TestSetPageLocked(page))
+                               break;
+                       if (!PageDirty(page) ||
+                           page_private(page) != (unsigned long) wb) {
+                               unlock_page(page);
+                               break;
+                       }
+                       if (!clear_page_dirty_for_io(page))
+                               BUG();
+                       if (test_set_page_writeback(page))
+                               BUG();
+                       unlock_page(page);
+                       put_page(page);
+               }
+               count += loop;
+               if (loop < n) {
+                       for (; loop < n; loop++)
+                               put_page(pages[loop]);
+                       goto no_more;
+               }
+
+               start += loop;
+       } while (start <= wb->last && count < 65536);
+
+no_more:
+       /* we now have a contiguous set of dirty pages, each with writeback set
+        * and the dirty mark cleared; the first page is locked and must remain
+        * so, all the rest are unlocked */
+       first = primary_page->index;
+       last = first + count - 1;
+
+       offset = (first == wb->first) ? wb->offset_first : 0;
+       to = (last == wb->last) ? wb->to_last : PAGE_SIZE;
+
+       _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to);
+
+       ret = afs_vnode_store_data(wb, first, last, offset, to);
+       if (ret < 0) {
+               switch (ret) {
+               case -EDQUOT:
+               case -ENOSPC:
+                       set_bit(AS_ENOSPC,
+                               &wb->vnode->vfs_inode.i_mapping->flags);
+                       break;
+               case -EROFS:
+               case -EIO:
+               case -EREMOTEIO:
+               case -EFBIG:
+               case -ENOENT:
+               case -ENOMEDIUM:
+               case -ENXIO:
+                       afs_kill_pages(wb->vnode, true, first, last);
+                       set_bit(AS_EIO, &wb->vnode->vfs_inode.i_mapping->flags);
+                       break;
+               case -EACCES:
+               case -EPERM:
+               case -ENOKEY:
+               case -EKEYEXPIRED:
+               case -EKEYREJECTED:
+               case -EKEYREVOKED:
+                       afs_kill_pages(wb->vnode, false, first, last);
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               ret = count;
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * write a page back to the server
+ * - the caller locked the page for us
+ */
+int afs_writepage(struct page *page, struct writeback_control *wbc)
+{
+       struct backing_dev_info *bdi = page->mapping->backing_dev_info;
+       struct afs_writeback *wb;
+       int ret;
+
+       _enter("{%lx},", page->index);
+
+       wb = (struct afs_writeback *) page_private(page);
+       ASSERT(wb != NULL);
+
+       ret = afs_write_back_from_locked_page(wb, page);
+       unlock_page(page);
+       if (ret < 0) {
+               _leave(" = %d", ret);
+               return 0;
+       }
+
+       wbc->nr_to_write -= ret;
+       if (wbc->nonblocking && bdi_write_congested(bdi))
+               wbc->encountered_congestion = 1;
+
+       _leave(" = 0");
+       return 0;
+}
+
+/*
+ * write a region of pages back to the server
+ */
+int afs_writepages_region(struct address_space *mapping,
+                         struct writeback_control *wbc,
+                         pgoff_t index, pgoff_t end, pgoff_t *_next)
+{
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+       struct afs_writeback *wb;
+       struct page *page;
+       int ret, n;
+
+       _enter(",,%lx,%lx,", index, end);
+
+       do {
+               n = find_get_pages_tag(mapping, &index, PAGECACHE_TAG_DIRTY,
+                                      1, &page);
+               if (!n)
+                       break;
+
+               _debug("wback %lx", page->index);
+
+               if (page->index > end) {
+                       *_next = index;
+                       page_cache_release(page);
+                       _leave(" = 0 [%lx]", *_next);
+                       return 0;
+               }
+
+               /* at this point we hold neither mapping->tree_lock nor lock on
+                * the page itself: the page may be truncated or invalidated
+                * (changing page->mapping to NULL), or even swizzled back from
+                * swapper_space to tmpfs file mapping
+                */
+               lock_page(page);
+
+               if (page->mapping != mapping) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       continue;
+               }
+
+               if (wbc->sync_mode != WB_SYNC_NONE)
+                       wait_on_page_writeback(page);
+
+               if (PageWriteback(page) || !PageDirty(page)) {
+                       unlock_page(page);
+                       continue;
+               }
+
+               wb = (struct afs_writeback *) page_private(page);
+               ASSERT(wb != NULL);
+
+               spin_lock(&wb->vnode->writeback_lock);
+               wb->state = AFS_WBACK_WRITING;
+               spin_unlock(&wb->vnode->writeback_lock);
+
+               ret = afs_write_back_from_locked_page(wb, page);
+               unlock_page(page);
+               page_cache_release(page);
+               if (ret < 0) {
+                       _leave(" = %d", ret);
+                       return ret;
+               }
+
+               wbc->nr_to_write -= ret;
+
+               if (wbc->nonblocking && bdi_write_congested(bdi)) {
+                       wbc->encountered_congestion = 1;
+                       break;
+               }
+
+               cond_resched();
+       } while (index < end && wbc->nr_to_write > 0);
+
+       *_next = index;
+       _leave(" = 0 [%lx]", *_next);
+       return 0;
+}
+
+/*
+ * write some of the pending data back to the server
+ */
+int afs_writepages(struct address_space *mapping,
+                  struct writeback_control *wbc)
+{
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+       pgoff_t start, end, next;
+       int ret;
+
+       _enter("");
+
+       if (wbc->nonblocking && bdi_write_congested(bdi)) {
+               wbc->encountered_congestion = 1;
+               _leave(" = 0 [congest]");
+               return 0;
+       }
+
+       if (wbc->range_cyclic) {
+               start = mapping->writeback_index;
+               end = -1;
+               ret = afs_writepages_region(mapping, wbc, start, end, &next);
+               if (start > 0 && wbc->nr_to_write > 0 && ret == 0 &&
+                   !(wbc->nonblocking && wbc->encountered_congestion))
+                       ret = afs_writepages_region(mapping, wbc, 0, start,
+                                                   &next);
+               mapping->writeback_index = next;
+       } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
+               end = (pgoff_t)(LLONG_MAX >> PAGE_CACHE_SHIFT);
+               ret = afs_writepages_region(mapping, wbc, 0, end, &next);
+               if (wbc->nr_to_write > 0)
+                       mapping->writeback_index = next;
+       } else {
+               start = wbc->range_start >> PAGE_CACHE_SHIFT;
+               end = wbc->range_end >> PAGE_CACHE_SHIFT;
+               ret = afs_writepages_region(mapping, wbc, start, end, &next);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * write an inode back
+ */
+int afs_write_inode(struct inode *inode, int sync)
+{
+       struct afs_vnode *vnode = AFS_FS_I(inode);
+       int ret;
+
+       _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
+
+       ret = 0;
+       if (sync) {
+               ret = filemap_fdatawait(inode->i_mapping);
+               if (ret < 0)
+                       __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+       }
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * completion of write to server
+ */
+void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
+{
+       struct afs_writeback *wb = call->wb;
+       struct pagevec pv;
+       unsigned count, loop;
+       pgoff_t first = call->first, last = call->last;
+       bool free_wb;
+
+       _enter("{%x:%u},{%lx-%lx}",
+              vnode->fid.vid, vnode->fid.vnode, first, last);
+
+       ASSERT(wb != NULL);
+
+       pagevec_init(&pv, 0);
+
+       do {
+               _debug("done %lx-%lx", first, last);
+
+               count = last - first + 1;
+               if (count > PAGEVEC_SIZE)
+                       count = PAGEVEC_SIZE;
+               pv.nr = find_get_pages_contig(call->mapping, first, count,
+                                             pv.pages);
+               ASSERTCMP(pv.nr, ==, count);
+
+               spin_lock(&vnode->writeback_lock);
+               for (loop = 0; loop < count; loop++) {
+                       struct page *page = pv.pages[loop];
+                       end_page_writeback(page);
+                       if (page_private(page) == (unsigned long) wb) {
+                               set_page_private(page, 0);
+                               ClearPagePrivate(page);
+                               wb->usage--;
+                       }
+               }
+               free_wb = false;
+               if (wb->usage == 0) {
+                       afs_unlink_writeback(wb);
+                       free_wb = true;
+               }
+               spin_unlock(&vnode->writeback_lock);
+               first += count;
+               if (free_wb) {
+                       afs_free_writeback(wb);
+                       wb = NULL;
+               }
+
+               __pagevec_release(&pv);
+       } while (first <= last);
+
+       _leave("");
+}
+
+/*
+ * write to an AFS file
+ */
+ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
+                      unsigned long nr_segs, loff_t pos)
+{
+       struct dentry *dentry = iocb->ki_filp->f_path.dentry;
+       struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+       ssize_t result;
+       size_t count = iov_length(iov, nr_segs);
+       int ret;
+
+       _enter("{%x.%u},{%zu},%lu,",
+              vnode->fid.vid, vnode->fid.vnode, count, nr_segs);
+
+       if (IS_SWAPFILE(&vnode->vfs_inode)) {
+               printk(KERN_INFO
+                      "AFS: Attempt to write to active swap file!\n");
+               return -EBUSY;
+       }
+
+       if (!count)
+               return 0;
+
+       result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+       if (IS_ERR_VALUE(result)) {
+               _leave(" = %zd", result);
+               return result;
+       }
+
+       /* return error values for O_SYNC and IS_SYNC() */
+       if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) {
+               ret = afs_fsync(iocb->ki_filp, dentry, 1);
+               if (ret < 0)
+                       result = ret;
+       }
+
+       _leave(" = %zd", result);
+       return result;
+}
+
+/*
+ * flush the vnode to the fileserver
+ */
+int afs_writeback_all(struct afs_vnode *vnode)
+{
+       struct address_space *mapping = vnode->vfs_inode.i_mapping;
+       struct writeback_control wbc = {
+               .bdi            = mapping->backing_dev_info,
+               .sync_mode      = WB_SYNC_ALL,
+               .nr_to_write    = LONG_MAX,
+               .for_writepages = 1,
+               .range_cyclic   = 1,
+       };
+       int ret;
+
+       _enter("");
+
+       ret = mapping->a_ops->writepages(mapping, &wbc);
+       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
+/*
+ * flush any dirty pages for this process, and check for write errors.
+ * - the return status from this call provides a reliable indication of
+ *   whether any write errors occurred for this process.
+ */
+int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+       struct afs_writeback *wb, *xwb;
+       struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+       int ret;
+
+       _enter("{%x:%u},{n=%s},%d",
+              vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+              datasync);
+
+       /* use a writeback record as a marker in the queue - when this reaches
+        * the front of the queue, all the outstanding writes are either
+        * completed or rejected */
+       wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+       if (!wb)
+               return -ENOMEM;
+       wb->vnode = vnode;
+       wb->first = 0;
+       wb->last = -1;
+       wb->offset_first = 0;
+       wb->to_last = PAGE_SIZE;
+       wb->usage = 1;
+       wb->state = AFS_WBACK_SYNCING;
+       init_waitqueue_head(&wb->waitq);
+
+       spin_lock(&vnode->writeback_lock);
+       list_for_each_entry(xwb, &vnode->writebacks, link) {
+               if (xwb->state == AFS_WBACK_PENDING)
+                       xwb->state = AFS_WBACK_CONFLICTING;
+       }
+       list_add_tail(&wb->link, &vnode->writebacks);
+       spin_unlock(&vnode->writeback_lock);
+
+       /* push all the outstanding writebacks to the server */
+       ret = afs_writeback_all(vnode);
+       if (ret < 0) {
+               afs_put_writeback(wb);
+               _leave(" = %d [wb]", ret);
+               return ret;
+       }
+
+       /* wait for the preceding writes to actually complete */
+       ret = wait_event_interruptible(wb->waitq,
+                                      wb->state == AFS_WBACK_COMPLETE ||
+                                      vnode->writebacks.next == &wb->link);
+       afs_put_writeback(wb);
+       _leave(" = %d", ret);
+       return ret;
+}
index b97ab8028b6d2e9dde3ce85e5a2a91ad3140a7b0..dbe699e9828c3ac840529876d4daf2dda56abb47 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -30,6 +30,7 @@
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
+#include <linux/eventfd.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -346,10 +347,9 @@ void fastcall exit_aio(struct mm_struct *mm)
 
                wait_for_all_aios(ctx);
                /*
-                * this is an overkill, but ensures we don't leave
-                * the ctx on the aio_wq
+                * Ensure we don't leave the ctx on the aio_wq
                 */
-               flush_workqueue(aio_wq);
+               cancel_work_sync(&ctx->wq.work);
 
                if (1 != atomic_read(&ctx->users))
                        printk(KERN_DEBUG
@@ -372,7 +372,7 @@ void fastcall __put_ioctx(struct kioctx *ctx)
        BUG_ON(ctx->reqs_active);
 
        cancel_delayed_work(&ctx->wq);
-       flush_workqueue(aio_wq);
+       cancel_work_sync(&ctx->wq.work);
        aio_free_ring(ctx);
        mmdrop(ctx->mm);
        ctx->mm = NULL;
@@ -418,6 +418,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
        req->private = NULL;
        req->ki_iovec = NULL;
        INIT_LIST_HEAD(&req->ki_run_list);
+       req->ki_eventfd = ERR_PTR(-EINVAL);
 
        /* Check if the completion queue has enough free space to
         * accept an event from this io.
@@ -459,6 +460,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
 {
        assert_spin_locked(&ctx->ctx_lock);
 
+       if (!IS_ERR(req->ki_eventfd))
+               fput(req->ki_eventfd);
        if (req->ki_dtor)
                req->ki_dtor(req);
        if (req->ki_iovec != &req->ki_inline_vec)
@@ -943,6 +946,14 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
                return 1;
        }
 
+       /*
+        * Check if the user asked us to deliver the result through an
+        * eventfd. The eventfd_signal() function is safe to be called
+        * from IRQ context.
+        */
+       if (!IS_ERR(iocb->ki_eventfd))
+               eventfd_signal(iocb->ki_eventfd, 1);
+
        info = &ctx->ring_info;
 
        /* add a completion event to the ring buffer.
@@ -1527,8 +1538,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        ssize_t ret;
 
        /* enforce forwards compatibility on users */
-       if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
-                    iocb->aio_reserved3)) {
+       if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) {
                pr_debug("EINVAL: io_submit: reserve field set\n");
                return -EINVAL;
        }
@@ -1552,6 +1562,19 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                fput(file);
                return -EAGAIN;
        }
+       if (iocb->aio_flags & IOCB_FLAG_RESFD) {
+               /*
+                * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
+                * instance of the file* now. The file descriptor must be
+                * an eventfd() fd, and will be signaled for each completed
+                * event using the eventfd_signal() function.
+                */
+               req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
+               if (unlikely(IS_ERR(req->ki_eventfd))) {
+                       ret = PTR_ERR(req->ki_eventfd);
+                       goto out_put_req;
+               }
+       }
 
        req->ki_filp = file;
        ret = put_user(req->ki_key, &user_iocb->aio_key);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
new file mode 100644 (file)
index 0000000..40fe3a3
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ *  fs/anon_inodes.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ *  Thanks to Arnd Bergmann for code review and suggestions.
+ *  More changes for Thomas Gleixner suggestions.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/magic.h>
+#include <linux/anon_inodes.h>
+
+#include <asm/uaccess.h>
+
+static struct vfsmount *anon_inode_mnt __read_mostly;
+static struct inode *anon_inode_inode;
+static const struct file_operations anon_inode_fops;
+
+static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags,
+                              const char *dev_name, void *data,
+                              struct vfsmount *mnt)
+{
+       return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC,
+                            mnt);
+}
+
+static int anon_inodefs_delete_dentry(struct dentry *dentry)
+{
+       /*
+        * We faked vfs to believe the dentry was hashed when we created it.
+        * Now we restore the flag so that dput() will work correctly.
+        */
+       dentry->d_flags |= DCACHE_UNHASHED;
+       return 1;
+}
+
+static struct file_system_type anon_inode_fs_type = {
+       .name           = "anon_inodefs",
+       .get_sb         = anon_inodefs_get_sb,
+       .kill_sb        = kill_anon_super,
+};
+static struct dentry_operations anon_inodefs_dentry_operations = {
+       .d_delete       = anon_inodefs_delete_dentry,
+};
+
+/**
+ * anon_inode_getfd - creates a new file instance by hooking it up to and
+ *                    anonymous inode, and a dentry that describe the "class"
+ *                    of the file
+ *
+ * @pfd:     [out]   pointer to the file descriptor
+ * @dpinode: [out]   pointer to the inode
+ * @pfile:   [out]   pointer to the file struct
+ * @name:    [in]    name of the "class" of the new file
+ * @fops     [in]    file operations for the new file
+ * @priv     [in]    private data for the new file (will be file's private_data)
+ *
+ * Creates a new file by hooking it on a single inode. This is useful for files
+ * that do not need to have a full-fledged inode in order to operate correctly.
+ * All the files created with anon_inode_getfd() will share a single inode, by
+ * hence saving memory and avoiding code duplication for the file/inode/dentry
+ * setup.
+ */
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+                    const char *name, const struct file_operations *fops,
+                    void *priv)
+{
+       struct qstr this;
+       struct dentry *dentry;
+       struct inode *inode;
+       struct file *file;
+       int error, fd;
+
+       if (IS_ERR(anon_inode_inode))
+               return -ENODEV;
+       file = get_empty_filp();
+       if (!file)
+               return -ENFILE;
+
+       inode = igrab(anon_inode_inode);
+       if (IS_ERR(inode)) {
+               error = PTR_ERR(inode);
+               goto err_put_filp;
+       }
+
+       error = get_unused_fd();
+       if (error < 0)
+               goto err_iput;
+       fd = error;
+
+       /*
+        * Link the inode to a directory entry by creating a unique name
+        * using the inode sequence number.
+        */
+       error = -ENOMEM;
+       this.name = name;
+       this.len = strlen(name);
+       this.hash = 0;
+       dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
+       if (!dentry)
+               goto err_put_unused_fd;
+       dentry->d_op = &anon_inodefs_dentry_operations;
+       /* Do not publish this dentry inside the global dentry hash table */
+       dentry->d_flags &= ~DCACHE_UNHASHED;
+       d_instantiate(dentry, inode);
+
+       file->f_path.mnt = mntget(anon_inode_mnt);
+       file->f_path.dentry = dentry;
+       file->f_mapping = inode->i_mapping;
+
+       file->f_pos = 0;
+       file->f_flags = O_RDWR;
+       file->f_op = fops;
+       file->f_mode = FMODE_READ | FMODE_WRITE;
+       file->f_version = 0;
+       file->private_data = priv;
+
+       fd_install(fd, file);
+
+       *pfd = fd;
+       *pinode = inode;
+       *pfile = file;
+       return 0;
+
+err_put_unused_fd:
+       put_unused_fd(fd);
+err_iput:
+       iput(inode);
+err_put_filp:
+       put_filp(file);
+       return error;
+}
+
+/*
+ * A single inode exist for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes has no per-instance data associated, so we can avoid
+ * the allocation of multiple of them.
+ */
+static struct inode *anon_inode_mkinode(void)
+{
+       struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
+
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       inode->i_fop = &anon_inode_fops;
+
+       /*
+        * Mark the inode dirty from the very beginning,
+        * that way it will never be moved to the dirty
+        * list because mark_inode_dirty() will think
+        * that it already _is_ on the dirty list.
+        */
+       inode->i_state = I_DIRTY;
+       inode->i_mode = S_IRUSR | S_IWUSR;
+       inode->i_uid = current->fsuid;
+       inode->i_gid = current->fsgid;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       return inode;
+}
+
+static int __init anon_inode_init(void)
+{
+       int error;
+
+       error = register_filesystem(&anon_inode_fs_type);
+       if (error)
+               goto err_exit;
+       anon_inode_mnt = kern_mount(&anon_inode_fs_type);
+       if (IS_ERR(anon_inode_mnt)) {
+               error = PTR_ERR(anon_inode_mnt);
+               goto err_unregister_filesystem;
+       }
+       anon_inode_inode = anon_inode_mkinode();
+       if (IS_ERR(anon_inode_inode)) {
+               error = PTR_ERR(anon_inode_inode);
+               goto err_mntput;
+       }
+
+       return 0;
+
+err_mntput:
+       mntput(anon_inode_mnt);
+err_unregister_filesystem:
+       unregister_filesystem(&anon_inode_fs_type);
+err_exit:
+       panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+}
+
+fs_initcall(anon_inode_init);
+
index 4ef544434b515d85511bf86c95a6322f520921a0..8b4cca3c4705c7b880d8ded266160a84c74c0cbf 100644 (file)
@@ -101,7 +101,7 @@ struct autofs_symlink {
 struct autofs_sb_info {
        u32 magic;
        struct file *pipe;
-       pid_t oz_pgrp;
+       struct pid *oz_pgrp;
        int catatonic;
        struct super_block *sb;
        unsigned long exp_timeout;
@@ -122,7 +122,7 @@ static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
    filesystem without "magic".) */
 
 static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
-       return sbi->catatonic || process_group(current) == sbi->oz_pgrp;
+       return sbi->catatonic || task_pgrp(current) == sbi->oz_pgrp;
 }
 
 /* Hash operations */
index aa0b61ff827078c8045d8a141a0d1a7a27fbdce0..e7204d71acc94660f4a50a3d2c10eb2a6a816e63 100644 (file)
@@ -34,12 +34,14 @@ void autofs_kill_sb(struct super_block *sb)
        if (!sbi)
                goto out_kill_sb;
 
-       if ( !sbi->catatonic )
+       if (!sbi->catatonic)
                autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
+       put_pid(sbi->oz_pgrp);
+
        autofs_hash_nuke(sbi);
-       for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
-               if ( test_bit(n, sbi->symlink_bitmap) )
+       for (n = 0; n < AUTOFS_MAX_SYMLINKS; n++) {
+               if (test_bit(n, sbi->symlink_bitmap))
                        kfree(sbi->symlink[n].data);
        }
 
@@ -69,7 +71,8 @@ static match_table_t autofs_tokens = {
        {Opt_err, NULL}
 };
 
-static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
+static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
+               pid_t *pgrp, int *minproto, int *maxproto)
 {
        char *p;
        substring_t args[MAX_OPT_ARGS];
@@ -138,9 +141,10 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
        int pipefd;
        struct autofs_sb_info *sbi;
        int minproto, maxproto;
+       pid_t pgid;
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
-       if ( !sbi )
+       if (!sbi)
                goto fail_unlock;
        DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
@@ -149,7 +153,6 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
        sbi->pipe = NULL;
        sbi->catatonic = 1;
        sbi->exp_timeout = 0;
-       sbi->oz_pgrp = process_group(current);
        autofs_initialize_hash(&sbi->dirhash);
        sbi->queues = NULL;
        memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN);
@@ -169,26 +172,36 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
                goto fail_iput;
 
        /* Can this call block?  - WTF cares? s is locked. */
-       if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+       if (parse_options(data, &pipefd, &root_inode->i_uid,
+                               &root_inode->i_gid, &pgid, &minproto,
+                               &maxproto)) {
                printk("autofs: called with bogus options\n");
                goto fail_dput;
        }
 
        /* Couldn't this be tested earlier? */
-       if ( minproto > AUTOFS_PROTO_VERSION || 
-            maxproto < AUTOFS_PROTO_VERSION ) {
+       if (minproto > AUTOFS_PROTO_VERSION ||
+            maxproto < AUTOFS_PROTO_VERSION) {
                printk("autofs: kernel does not match daemon version\n");
                goto fail_dput;
        }
 
-       DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
+       DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, pgid));
+       sbi->oz_pgrp = find_get_pid(pgid);
+
+       if (!sbi->oz_pgrp) {
+               printk("autofs: could not find process group %d\n", pgid);
+               goto fail_dput;
+       }
+
        pipe = fget(pipefd);
        
-       if ( !pipe ) {
+       if (!pipe) {
                printk("autofs: could not open pipe file descriptor\n");
-               goto fail_dput;
+               goto fail_put_pid;
        }
-       if ( !pipe->f_op || !pipe->f_op->write )
+
+       if (!pipe->f_op || !pipe->f_op->write)
                goto fail_fput;
        sbi->pipe = pipe;
        sbi->catatonic = 0;
@@ -202,6 +215,8 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
 fail_fput:
        printk("autofs: pipe file descriptor does not contain proper ops\n");
        fput(pipe);
+fail_put_pid:
+       put_pid(sbi->oz_pgrp);
 fail_dput:
        dput(root);
        goto fail_free;
@@ -230,7 +245,7 @@ static void autofs_read_inode(struct inode *inode)
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_blocks = 0;
 
-       if ( ino == AUTOFS_ROOT_INO ) {
+       if (ino == AUTOFS_ROOT_INO) {
                inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
                inode->i_op = &autofs_root_inode_operations;
                inode->i_fop = &autofs_root_operations;
@@ -241,12 +256,12 @@ static void autofs_read_inode(struct inode *inode)
        inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
        inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
        
-       if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
+       if (ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO) {
                /* Symlink inode - should be in symlink list */
                struct autofs_symlink *sl;
 
                n = ino - AUTOFS_FIRST_SYMLINK;
-               if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
+               if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
                        printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
                        return;
                }
index f2597205939d5efc6b56031a7569687c4f7063f1..c1489533277ae87d1f1d5358d7248e35ef5d6eb5 100644 (file)
@@ -67,8 +67,8 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
                filp->f_pos = ++nr;
                /* fall through */
        default:
-               while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
-                       if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
+               while (onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent)) {
+                       if (!ent->dentry || d_mountpoint(ent->dentry)) {
                                if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
                                        goto out;
                                filp->f_pos = nr;
@@ -88,10 +88,10 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
        struct autofs_dir_ent *ent;
        int status = 0;
 
-       if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
+       if (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
                do {
-                       if ( status && dentry->d_inode ) {
-                               if ( status != -ENOENT )
+                       if (status && dentry->d_inode) {
+                               if (status != -ENOENT)
                                        printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
                                return 0; /* Try to get the kernel to invalidate this dentry */
                        }
@@ -106,7 +106,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
                                return 1;
                        }
                        status = autofs_wait(sbi, &dentry->d_name);
-               } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) );
+               } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)));
        }
 
        /* Abuse this field as a pointer to the directory entry, used to
@@ -124,13 +124,13 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
 
        /* If this is a directory that isn't a mount point, bitch at the
           daemon and fix it in user space */
-       if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+       if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
                return !autofs_wait(sbi, &dentry->d_name);
        }
 
        /* We don't update the usages for the autofs daemon itself, this
           is necessary for recursive autofs mounts */
-       if ( !autofs_oz_mode(sbi) ) {
+       if (!autofs_oz_mode(sbi)) {
                autofs_update_usage(&sbi->dirhash,ent);
        }
 
@@ -157,7 +157,7 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd)
        sbi = autofs_sbi(dir->i_sb);
 
        /* Pending dentry */
-       if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
+       if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
                if (autofs_oz_mode(sbi))
                        res = 1;
                else
@@ -173,7 +173,7 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd)
        }
                
        /* Check for a non-mountpoint directory */
-       if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+       if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
                if (autofs_oz_mode(sbi))
                        res = 1;
                else
@@ -183,9 +183,9 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd)
        }
 
        /* Update the usage list */
-       if ( !autofs_oz_mode(sbi) ) {
+       if (!autofs_oz_mode(sbi)) {
                ent = (struct autofs_dir_ent *) dentry->d_time;
-               if ( ent )
+               if (ent)
                        autofs_update_usage(&sbi->dirhash,ent);
        }
        unlock_kernel();
@@ -213,8 +213,10 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
        sbi = autofs_sbi(dir->i_sb);
 
        oz_mode = autofs_oz_mode(sbi);
-       DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
-                current->pid, process_group(current), sbi->catatonic, oz_mode));
+       DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, "
+                               "oz_mode = %d\n", pid_nr(task_pid(current)),
+                               process_group(current), sbi->catatonic,
+                               oz_mode));
 
        /*
         * Mark the dentry incomplete, but add it. This is needed so
@@ -258,7 +260,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
         * doesn't do the right thing for all system calls, but it should
         * be OK for the operations we permit from an autofs.
         */
-       if ( dentry->d_inode && d_unhashed(dentry) )
+       if (dentry->d_inode && d_unhashed(dentry))
                return ERR_PTR(-ENOENT);
 
        return NULL;
@@ -277,18 +279,18 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        autofs_say(dentry->d_name.name,dentry->d_name.len);
 
        lock_kernel();
-       if ( !autofs_oz_mode(sbi) ) {
+       if (!autofs_oz_mode(sbi)) {
                unlock_kernel();
                return -EACCES;
        }
 
-       if ( autofs_hash_lookup(dh, &dentry->d_name) ) {
+       if (autofs_hash_lookup(dh, &dentry->d_name)) {
                unlock_kernel();
                return -EEXIST;
        }
 
        n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
-       if ( n >= AUTOFS_MAX_SYMLINKS ) {
+       if (n >= AUTOFS_MAX_SYMLINKS) {
                unlock_kernel();
                return -ENOSPC;
        }
@@ -297,14 +299,14 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        sl = &sbi->symlink[n];
        sl->len = strlen(symname);
        sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
-       if ( !sl->data ) {
+       if (!sl->data) {
                clear_bit(n,sbi->symlink_bitmap);
                unlock_kernel();
                return -ENOSPC;
        }
 
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
-       if ( !ent ) {
+       if (!ent) {
                kfree(sl->data);
                clear_bit(n,sbi->symlink_bitmap);
                unlock_kernel();
@@ -312,7 +314,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
        }
 
        ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
-       if ( !ent->name ) {
+       if (!ent->name) {
                kfree(sl->data);
                kfree(ent);
                clear_bit(n,sbi->symlink_bitmap);
@@ -354,23 +356,23 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
 
        /* This allows root to remove symlinks */
        lock_kernel();
-       if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) {
+       if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) {
                unlock_kernel();
                return -EACCES;
        }
 
        ent = autofs_hash_lookup(dh, &dentry->d_name);
-       if ( !ent ) {
+       if (!ent) {
                unlock_kernel();
                return -ENOENT;
        }
 
        n = ent->ino - AUTOFS_FIRST_SYMLINK;
-       if ( n >= AUTOFS_MAX_SYMLINKS ) {
+       if (n >= AUTOFS_MAX_SYMLINKS) {
                unlock_kernel();
                return -EISDIR; /* It's a directory, dummy */
        }
-       if ( !test_bit(n,sbi->symlink_bitmap) ) {
+       if (!test_bit(n,sbi->symlink_bitmap)) {
                unlock_kernel();
                return -EINVAL; /* Nonexistent symlink?  Shouldn't happen */
        }
@@ -392,23 +394,23 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
        struct autofs_dir_ent *ent;
 
        lock_kernel();
-       if ( !autofs_oz_mode(sbi) ) {
+       if (!autofs_oz_mode(sbi)) {
                unlock_kernel();
                return -EACCES;
        }
 
        ent = autofs_hash_lookup(dh, &dentry->d_name);
-       if ( !ent ) {
+       if (!ent) {
                unlock_kernel();
                return -ENOENT;
        }
 
-       if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) {
+       if ((unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO) {
                unlock_kernel();
                return -ENOTDIR; /* Not a directory */
        }
 
-       if ( ent->dentry != dentry ) {
+       if (ent->dentry != dentry) {
                printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
        }
 
@@ -429,18 +431,18 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        ino_t ino;
 
        lock_kernel();
-       if ( !autofs_oz_mode(sbi) ) {
+       if (!autofs_oz_mode(sbi)) {
                unlock_kernel();
                return -EACCES;
        }
 
        ent = autofs_hash_lookup(dh, &dentry->d_name);
-       if ( ent ) {
+       if (ent) {
                unlock_kernel();
                return -EEXIST;
        }
 
-       if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
+       if (sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO) {
                printk("autofs: Out of inode numbers -- what the heck did you do??\n");
                unlock_kernel();
                return -ENOSPC;
@@ -448,13 +450,13 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        ino = sbi->next_dir_ino++;
 
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
-       if ( !ent ) {
+       if (!ent) {
                unlock_kernel();
                return -ENOSPC;
        }
 
        ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
-       if ( !ent->name ) {
+       if (!ent->name) {
                kfree(ent);
                unlock_kernel();
                return -ENOSPC;
@@ -483,7 +485,7 @@ static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
            put_user(sbi->exp_timeout / HZ, p))
                return -EFAULT;
 
-       if ( ntimeout > ULONG_MAX/HZ )
+       if (ntimeout > ULONG_MAX/HZ)
                sbi->exp_timeout = 0;
        else
                sbi->exp_timeout = ntimeout * HZ;
@@ -511,15 +513,14 @@ static inline int autofs_expire_run(struct super_block *sb,
        pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
        pkt.hdr.type = autofs_ptype_expire;
 
-       if ( !sbi->exp_timeout ||
-            !(ent = autofs_expire(sb,sbi,mnt)) )
+       if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt)))
                return -EAGAIN;
 
        pkt.len = ent->len;
        memcpy(pkt.name, ent->name, pkt.len);
        pkt.name[pkt.len] = '\0';
 
-       if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+       if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)))
                return -EFAULT;
 
        return 0;
@@ -537,11 +538,11 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp,
 
        DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current)));
 
-       if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+       if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
                return -ENOTTY;
        
-       if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        
        switch(cmd) {
index 5769a2f9ad60a0f0222eb693ebb576a665cce624..692364e8ffc395117d3deb0eec2676eac89dc2d2 100644 (file)
@@ -218,8 +218,7 @@ static match_table_t tokens = {
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
-                        pid_t *pgrp, unsigned int *type,
-                        int *minproto, int *maxproto)
+               pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto)
 {
        char *p;
        substring_t args[MAX_OPT_ARGS];
@@ -314,7 +313,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        struct autofs_info *ino;
 
        sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
-       if ( !sbi )
+       if (!sbi)
                goto fail_unlock;
        DPRINTK("starting up, sbi = %p",sbi);
 
@@ -363,10 +362,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        root->d_fsdata = ino;
 
        /* Can this call block? */
-       if (parse_options(data, &pipefd,
-                         &root_inode->i_uid, &root_inode->i_gid,
-                         &sbi->oz_pgrp, &sbi->type,
-                         &sbi->min_proto, &sbi->max_proto)) {
+       if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid,
+                               &sbi->oz_pgrp, &sbi->type, &sbi->min_proto,
+                               &sbi->max_proto)) {
                printk("autofs: called with bogus options\n");
                goto fail_dput;
        }
@@ -396,11 +394,11 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
        pipe = fget(pipefd);
        
-       if ( !pipe ) {
+       if (!pipe) {
                printk("autofs: could not open pipe file descriptor\n");
                goto fail_dput;
        }
-       if ( !pipe->f_op || !pipe->f_op->write )
+       if (!pipe->f_op || !pipe->f_op->write)
                goto fail_fput;
        sbi->pipe = pipe;
        sbi->pipefd = pipefd;
index 15170f4e13a763e704af9a6b9871f843a1d65a8a..2d4c8a3e604e776a8a5fe680d5e974c729770dd0 100644 (file)
@@ -759,7 +759,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
        struct autofs_info *p_ino;
        
        /* This allows root to remove symlinks */
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EACCES;
 
        if (atomic_dec_and_test(&ino->count)) {
@@ -833,7 +833,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct autofs_info *p_ino;
        struct inode *inode;
 
-       if ( !autofs4_oz_mode(sbi) )
+       if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
        DPRINTK("dentry %p, creating %.*s",
@@ -871,11 +871,11 @@ static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
        int rv;
        unsigned long ntimeout;
 
-       if ( (rv = get_user(ntimeout, p)) ||
-            (rv = put_user(sbi->exp_timeout/HZ, p)) )
+       if ((rv = get_user(ntimeout, p)) ||
+            (rv = put_user(sbi->exp_timeout/HZ, p)))
                return rv;
 
-       if ( ntimeout > ULONG_MAX/HZ )
+       if (ntimeout > ULONG_MAX/HZ)
                sbi->exp_timeout = 0;
        else
                sbi->exp_timeout = ntimeout * HZ;
@@ -906,7 +906,7 @@ static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p)
        DPRINTK("returning %d", sbi->needs_reghost);
 
        status = put_user(sbi->needs_reghost, p);
-       if ( status )
+       if (status)
                return status;
 
        sbi->needs_reghost = 0;
@@ -975,11 +975,11 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
        DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",
                cmd,arg,sbi,process_group(current));
 
-       if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+       if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
                return -ENOTTY;
        
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        
        switch(cmd) {
index 18657f001b43ba8b1393da95cb7b0481910ba937..72d0b412c376641428244fac1acab7684b7cc748 100644 (file)
@@ -675,19 +675,8 @@ static ssize_t
 bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
 {
        char *s = enabled ? "enabled" : "disabled";
-       int len = strlen(s);
-       loff_t pos = *ppos;
 
-       if (pos < 0)
-               return -EINVAL;
-       if (pos >= len)
-               return 0;
-       if (len < pos + nbytes)
-               nbytes = len - pos;
-       if (copy_to_user(buf, s + pos, nbytes))
-               return -EFAULT;
-       *ppos = pos + nbytes;
-       return nbytes;
+       return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
 }
 
 static ssize_t bm_status_write(struct file * file, const char __user * buffer,
index eb820b82a636fc917a699ff86caf0e5e853f780b..aecd057cd0e0607631201d93be38bda0b9e44001 100644 (file)
@@ -1846,13 +1846,8 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
                if (block_start >= to)
                        break;
                if (buffer_new(bh)) {
-                       void *kaddr;
-
                        clear_buffer_new(bh);
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       memset(kaddr+block_start, 0, bh->b_size);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr, KM_USER0);
+                       zero_user_page(page, block_start, bh->b_size, KM_USER0);
                        set_buffer_uptodate(bh);
                        mark_buffer_dirty(bh);
                }
@@ -1940,10 +1935,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
                                        SetPageError(page);
                        }
                        if (!buffer_mapped(bh)) {
-                               void *kaddr = kmap_atomic(page, KM_USER0);
-                               memset(kaddr + i * blocksize, 0, blocksize);
-                               flush_dcache_page(page);
-                               kunmap_atomic(kaddr, KM_USER0);
+                               zero_user_page(page, i * blocksize, blocksize,
+                                               KM_USER0);
                                if (!err)
                                        set_buffer_uptodate(bh);
                                continue;
@@ -2086,7 +2079,6 @@ int cont_prepare_write(struct page *page, unsigned offset,
        long status;
        unsigned zerofrom;
        unsigned blocksize = 1 << inode->i_blkbits;
-       void *kaddr;
 
        while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) {
                status = -ENOMEM;
@@ -2108,10 +2100,8 @@ int cont_prepare_write(struct page *page, unsigned offset,
                                                PAGE_CACHE_SIZE, get_block);
                if (status)
                        goto out_unmap;
-               kaddr = kmap_atomic(new_page, KM_USER0);
-               memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
-               flush_dcache_page(new_page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, zerofrom, PAGE_CACHE_SIZE - zerofrom,
+                               KM_USER0);
                generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE);
                unlock_page(new_page);
                page_cache_release(new_page);
@@ -2138,10 +2128,7 @@ int cont_prepare_write(struct page *page, unsigned offset,
        if (status)
                goto out1;
        if (zerofrom < offset) {
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr+zerofrom, 0, offset-zerofrom);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, zerofrom, offset - zerofrom, KM_USER0);
                __block_commit_write(inode, page, zerofrom, offset);
        }
        return 0;
@@ -2340,10 +2327,7 @@ failed:
         * Error recovery is pretty slack.  Clear the page and mark it dirty
         * so we'll later zero out any blocks which _were_ allocated.
         */
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr, 0, PAGE_CACHE_SIZE);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
        SetPageUptodate(page);
        set_page_dirty(page);
        return ret;
@@ -2382,7 +2366,6 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
        loff_t i_size = i_size_read(inode);
        const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
        unsigned offset;
-       void *kaddr;
        int ret;
 
        /* Is the page fully inside i_size? */
@@ -2413,10 +2396,7 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
         * the  page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
 out:
        ret = mpage_writepage(page, get_block, wbc);
        if (ret == -EAGAIN)
@@ -2437,7 +2417,6 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
        unsigned to;
        struct page *page;
        const struct address_space_operations *a_ops = mapping->a_ops;
-       char *kaddr;
        int ret = 0;
 
        if ((offset & (blocksize - 1)) == 0)
@@ -2451,10 +2430,8 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
        to = (offset + blocksize) & ~(blocksize - 1);
        ret = a_ops->prepare_write(NULL, page, offset, to);
        if (ret == 0) {
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+                               KM_USER0);
                /*
                 * It would be more correct to call aops->commit_write()
                 * here, but this is more efficient.
@@ -2480,7 +2457,6 @@ int block_truncate_page(struct address_space *mapping,
        struct inode *inode = mapping->host;
        struct page *page;
        struct buffer_head *bh;
-       void *kaddr;
        int err;
 
        blocksize = 1 << inode->i_blkbits;
@@ -2534,11 +2510,7 @@ int block_truncate_page(struct address_space *mapping,
                        goto unlock;
        }
 
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, length);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
-
+       zero_user_page(page, offset, length, KM_USER0);
        mark_buffer_dirty(bh);
        err = 0;
 
@@ -2559,7 +2531,6 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
        loff_t i_size = i_size_read(inode);
        const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
        unsigned offset;
-       void *kaddr;
 
        /* Is the page fully inside i_size? */
        if (page->index < end_index)
@@ -2585,10 +2556,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
         * the  page size, the remaining memory is zeroed when mapped, and
         * writes to that region are not written out to the file."
         */
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
        return __block_write_full_page(inode, page, get_block, wbc);
 }
 
@@ -2978,7 +2946,7 @@ static void buffer_exit_cpu(int cpu)
 static int buffer_cpu_notify(struct notifier_block *self,
                              unsigned long action, void *hcpu)
 {
-       if (action == CPU_DEAD)
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
                buffer_exit_cpu((unsigned long)hcpu);
        return NOTIFY_OK;
 }
index 9cf75df9b2bb4753356ca9e3e5ae527b49329268..7b21b0a82596f77ed36d844e67d35f1e32934e9a 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/security.h>
 #include <linux/highmem.h>
+#include <linux/signal.h>
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/eventpoll.h>
@@ -2199,3 +2200,51 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
 #endif /* TIF_RESTORE_SIGMASK */
 
 #endif /* CONFIG_EPOLL */
+
+#ifdef CONFIG_SIGNALFD
+
+asmlinkage long compat_sys_signalfd(int ufd,
+                                   const compat_sigset_t __user *sigmask,
+                                   compat_size_t sigsetsize)
+{
+       compat_sigset_t ss32;
+       sigset_t tmp;
+       sigset_t __user *ksigmask;
+
+       if (sigsetsize != sizeof(compat_sigset_t))
+               return -EINVAL;
+       if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
+               return -EFAULT;
+       sigset_from_compat(&tmp, &ss32);
+       ksigmask = compat_alloc_user_space(sizeof(sigset_t));
+       if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+               return -EFAULT;
+
+       return sys_signalfd(ufd, ksigmask, sizeof(sigset_t));
+}
+
+#endif /* CONFIG_SIGNALFD */
+
+#ifdef CONFIG_TIMERFD
+
+asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
+                                  const struct compat_itimerspec __user *utmr)
+{
+       long res;
+       struct itimerspec t;
+       struct itimerspec __user *ut;
+
+       res = -EFAULT;
+       if (get_compat_itimerspec(&t, utmr))
+               goto err_exit;
+       ut = compat_alloc_user_space(sizeof(*ut));
+       if (copy_to_user(ut, &t, sizeof(t)) )
+               goto err_exit;
+
+       res = sys_timerfd(ufd, clockid, flags, ut);
+err_exit:
+       return res;
+}
+
+#endif /* CONFIG_TIMERFD */
+
index d92bc3eb7afcb33f398dbf35a3e4bc8f2c0c5393..65643def31825d99fa7df8399871fd4e2d8b4144 100644 (file)
@@ -3566,10 +3566,13 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
                        goto found_handler;
        }
 
+#ifdef CONFIG_NET
        if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
            cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
                error = siocdevprivate_ioctl(fd, cmd, arg);
-       } else {
+       } else
+#endif
+       {
                static int count;
 
                if (++count <= 50)
index d98be5e013280e7708e825d4b458acc3219c5a62..3527c7c6def898cb39d1118738b8d7a89475edc7 100644 (file)
@@ -77,36 +77,6 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
        return ret;
 }
 
-
-/**
- *     flush_read_buffer - push buffer to userspace.
- *     @buffer:        data buffer for file.
- *     @userbuf:       user-passed buffer.
- *     @count:         number of bytes requested.
- *     @ppos:          file position.
- *
- *     Copy the buffer we filled in fill_read_buffer() to userspace.
- *     This is done at the reader's leisure, copying and advancing
- *     the amount they specify each time.
- *     This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf,
-                            size_t count, loff_t * ppos)
-{
-       int error;
-
-       if (*ppos > buffer->count)
-               return 0;
-
-       if (count > (buffer->count - *ppos))
-               count = buffer->count - *ppos;
-
-       error = copy_to_user(buf,buffer->page + *ppos,count);
-       if (!error)
-               *ppos += count;
-       return error ? -EFAULT : count;
-}
-
 /**
  *     configfs_read_file - read an attribute.
  *     @file:  file pointer.
@@ -139,7 +109,8 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
        }
        pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
                 __FUNCTION__, count, *ppos, buffer->page);
-       retval = flush_read_buffer(buffer,buf,count,ppos);
+       retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+                                        buffer->count);
 out:
        up(&buffer->sem);
        return retval;
index d9d0833444f59da15dc8be42420c13366429d402..8593f3dfd2990a013b6fd580e22e1e82b83d4fbf 100644 (file)
@@ -439,7 +439,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
  * Wait on and process all in-flight BIOs.  This must only be called once
  * all bios have been issued so that the refcount can only decrease.
  * This just waits for all bios to make it through dio_bio_complete.  IO
- * errors are propogated through dio->io_error and should be propogated via
+ * errors are propagated through dio->io_error and should be propagated via
  * dio_complete().
  */
 static void dio_await_completion(struct dio *dio)
@@ -867,7 +867,6 @@ static int do_direct_IO(struct dio *dio)
 do_holes:
                        /* Handle holes */
                        if (!buffer_mapped(map_bh)) {
-                               char *kaddr;
                                loff_t i_size_aligned;
 
                                /* AKPM: eargh, -ENOTBLK is a hack */
@@ -888,11 +887,8 @@ do_holes:
                                        page_cache_release(page);
                                        goto out;
                                }
-                               kaddr = kmap_atomic(page, KM_USER0);
-                               memset(kaddr + (block_in_page << blkbits),
-                                               0, 1 << blkbits);
-                               flush_dcache_page(page);
-                               kunmap_atomic(kaddr, KM_USER0);
+                               zero_user_page(page, block_in_page << blkbits,
+                                               1 << blkbits, KM_USER0);
                                dio->block_in_file++;
                                block_in_page++;
                                goto next_block;
diff --git a/fs/eventfd.c b/fs/eventfd.c
new file mode 100644 (file)
index 0000000..480e2b3
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *  fs/eventfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/anon_inodes.h>
+#include <linux/eventfd.h>
+
+struct eventfd_ctx {
+       spinlock_t lock;
+       wait_queue_head_t wqh;
+       /*
+        * Every time that a write(2) is performed on an eventfd, the
+        * value of the __u64 being written is added to "count" and a
+        * wakeup is performed on "wqh". A read(2) will return the "count"
+        * value to userspace, and will reset "count" to zero. The kernel
+        * size eventfd_signal() also, adds to the "count" counter and
+        * issue a wakeup.
+        */
+       __u64 count;
+};
+
+/*
+ * Adds "n" to the eventfd counter "count". Returns "n" in case of
+ * success, or a value lower then "n" in case of coutner overflow.
+ * This function is supposed to be called by the kernel in paths
+ * that do not allow sleeping. In this function we allow the counter
+ * to reach the ULLONG_MAX value, and we signal this as overflow
+ * condition by returining a POLLERR to poll(2).
+ */
+int eventfd_signal(struct file *file, int n)
+{
+       struct eventfd_ctx *ctx = file->private_data;
+       unsigned long flags;
+
+       if (n < 0)
+               return -EINVAL;
+       spin_lock_irqsave(&ctx->lock, flags);
+       if (ULLONG_MAX - ctx->count < n)
+               n = (int) (ULLONG_MAX - ctx->count);
+       ctx->count += n;
+       if (waitqueue_active(&ctx->wqh))
+               wake_up_locked(&ctx->wqh);
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       return n;
+}
+
+static int eventfd_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+static unsigned int eventfd_poll(struct file *file, poll_table *wait)
+{
+       struct eventfd_ctx *ctx = file->private_data;
+       unsigned int events = 0;
+       unsigned long flags;
+
+       poll_wait(file, &ctx->wqh, wait);
+
+       spin_lock_irqsave(&ctx->lock, flags);
+       if (ctx->count > 0)
+               events |= POLLIN;
+       if (ctx->count == ULLONG_MAX)
+               events |= POLLERR;
+       if (ULLONG_MAX - 1 > ctx->count)
+               events |= POLLOUT;
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       return events;
+}
+
+static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       struct eventfd_ctx *ctx = file->private_data;
+       ssize_t res;
+       __u64 ucnt;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count < sizeof(ucnt))
+               return -EINVAL;
+       spin_lock_irq(&ctx->lock);
+       res = -EAGAIN;
+       ucnt = ctx->count;
+       if (ucnt > 0)
+               res = sizeof(ucnt);
+       else if (!(file->f_flags & O_NONBLOCK)) {
+               __add_wait_queue(&ctx->wqh, &wait);
+               for (res = 0;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (ctx->count > 0) {
+                               ucnt = ctx->count;
+                               res = sizeof(ucnt);
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               res = -ERESTARTSYS;
+                               break;
+                       }
+                       spin_unlock_irq(&ctx->lock);
+                       schedule();
+                       spin_lock_irq(&ctx->lock);
+               }
+               __remove_wait_queue(&ctx->wqh, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+       if (res > 0) {
+               ctx->count = 0;
+               if (waitqueue_active(&ctx->wqh))
+                       wake_up_locked(&ctx->wqh);
+       }
+       spin_unlock_irq(&ctx->lock);
+       if (res > 0 && put_user(ucnt, (__u64 __user *) buf))
+               return -EFAULT;
+
+       return res;
+}
+
+static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       struct eventfd_ctx *ctx = file->private_data;
+       ssize_t res;
+       __u64 ucnt;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count < sizeof(ucnt))
+               return -EINVAL;
+       if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
+               return -EFAULT;
+       if (ucnt == ULLONG_MAX)
+               return -EINVAL;
+       spin_lock_irq(&ctx->lock);
+       res = -EAGAIN;
+       if (ULLONG_MAX - ctx->count > ucnt)
+               res = sizeof(ucnt);
+       else if (!(file->f_flags & O_NONBLOCK)) {
+               __add_wait_queue(&ctx->wqh, &wait);
+               for (res = 0;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (ULLONG_MAX - ctx->count > ucnt) {
+                               res = sizeof(ucnt);
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               res = -ERESTARTSYS;
+                               break;
+                       }
+                       spin_unlock_irq(&ctx->lock);
+                       schedule();
+                       spin_lock_irq(&ctx->lock);
+               }
+               __remove_wait_queue(&ctx->wqh, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+       if (res > 0) {
+               ctx->count += ucnt;
+               if (waitqueue_active(&ctx->wqh))
+                       wake_up_locked(&ctx->wqh);
+       }
+       spin_unlock_irq(&ctx->lock);
+
+       return res;
+}
+
+static const struct file_operations eventfd_fops = {
+       .release        = eventfd_release,
+       .poll           = eventfd_poll,
+       .read           = eventfd_read,
+       .write          = eventfd_write,
+};
+
+struct file *eventfd_fget(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (!file)
+               return ERR_PTR(-EBADF);
+       if (file->f_op != &eventfd_fops) {
+               fput(file);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return file;
+}
+
+asmlinkage long sys_eventfd(unsigned int count)
+{
+       int error, fd;
+       struct eventfd_ctx *ctx;
+       struct file *file;
+       struct inode *inode;
+
+       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       init_waitqueue_head(&ctx->wqh);
+       spin_lock_init(&ctx->lock);
+       ctx->count = count;
+
+       /*
+        * When we call this, the initialization must be complete, since
+        * anon_inode_getfd() will install the fd.
+        */
+       error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
+                                &eventfd_fops, ctx);
+       if (!error)
+               return fd;
+
+       kfree(ctx);
+       return error;
+}
+
index b5c7ca584939acb628cd3f7644a99c3c53d0681d..1aad34ea61a4af5986ac91302c5760bd5a4ef023 100644 (file)
@@ -11,7 +11,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -34,6 +33,7 @@
 #include <linux/mount.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
+#include <linux/anon_inodes.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -41,7 +41,6 @@
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 
-
 /*
  * LOCKING:
  * There are three level of locking required by epoll :
@@ -74,9 +73,6 @@
  * a greater scalability.
  */
 
-
-#define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */
-
 #define DEBUG_EPOLL 0
 
 #if DEBUG_EPOLL > 0
 
 #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
 
-
 struct epoll_filefd {
        struct file *file;
        int fd;
@@ -224,43 +219,6 @@ struct ep_pqueue {
        struct epitem *epi;
 };
 
-
-
-static void ep_poll_safewake_init(struct poll_safewake *psw);
-static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-                   struct eventpoll *ep);
-static int ep_alloc(struct eventpoll **pep);
-static void ep_free(struct eventpoll *ep);
-static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
-static void ep_use_epitem(struct epitem *epi);
-static void ep_release_epitem(struct epitem *epi);
-static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
-                                poll_table *pt);
-static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi);
-static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
-                    struct file *tfile, int fd);
-static int ep_modify(struct eventpoll *ep, struct epitem *epi,
-                    struct epoll_event *event);
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi);
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi);
-static int ep_remove(struct eventpoll *ep, struct epitem *epi);
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key);
-static int ep_eventpoll_close(struct inode *inode, struct file *file);
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
-                         struct epoll_event __user *events, int maxevents);
-static int ep_events_transfer(struct eventpoll *ep,
-                             struct epoll_event __user *events,
-                             int maxevents);
-static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
-                  int maxevents, long timeout);
-static int eventpollfs_delete_dentry(struct dentry *dentry);
-static struct inode *ep_eventpoll_inode(void);
-static int eventpollfs_get_sb(struct file_system_type *fs_type,
-                             int flags, const char *dev_name,
-                             void *data, struct vfsmount *mnt);
-
 /*
  * This semaphore is used to serialize ep_free() and eventpoll_release_file().
  */
@@ -275,37 +233,6 @@ static struct kmem_cache *epi_cache __read_mostly;
 /* Slab cache used to allocate "struct eppoll_entry" */
 static struct kmem_cache *pwq_cache __read_mostly;
 
-/* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt __read_mostly;
-
-/* File callbacks that implement the eventpoll file behaviour */
-static const struct file_operations eventpoll_fops = {
-       .release        = ep_eventpoll_close,
-       .poll           = ep_eventpoll_poll
-};
-
-/*
- * This is used to register the virtual file system from where
- * eventpoll inodes are allocated.
- */
-static struct file_system_type eventpoll_fs_type = {
-       .name           = "eventpollfs",
-       .get_sb         = eventpollfs_get_sb,
-       .kill_sb        = kill_anon_super,
-};
-
-/* Very basic directory entry operations for the eventpoll virtual file system */
-static struct dentry_operations eventpollfs_dentry_operations = {
-       .d_delete       = eventpollfs_delete_dentry,
-};
-
-
-
-/* Fast test to see if the file is an evenpoll file */
-static inline int is_file_epoll(struct file *f)
-{
-       return f->f_op == &eventpoll_fops;
-}
 
 /* Setup the structure that is used as key for the rb-tree */
 static inline void ep_set_ffd(struct epoll_filefd *ffd,
@@ -374,7 +301,6 @@ static void ep_poll_safewake_init(struct poll_safewake *psw)
        spin_lock_init(&psw->lock);
 }
 
-
 /*
  * Perform a safe wake up of the poll wait list. The problem is that
  * with the new callback'd wake up system, it is possible that the
@@ -429,377 +355,264 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq)
        spin_unlock_irqrestore(&psw->lock, flags);
 }
 
-
 /*
- * 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.
+ * This function unregister poll callbacks from the associated file descriptor.
+ * Since this must be called without holding "ep->lock" the atomic exchange trick
+ * will protect us from multiple unregister.
  */
-void eventpoll_release_file(struct file *file)
+static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
 {
-       struct list_head *lsthead = &file->f_ep_links;
-       struct eventpoll *ep;
-       struct epitem *epi;
+       int nwait;
+       struct list_head *lsthead = &epi->pwqlist;
+       struct eppoll_entry *pwq;
 
-       /*
-        * 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.
-        * The only hit might come from ep_free() but by holding the semaphore
-        * will correctly serialize the operation. We do need to acquire
-        * "ep->sem" after "epmutex" because ep_remove() requires it when called
-        * from anywhere but ep_free().
-        */
-       mutex_lock(&epmutex);
+       /* This is called without locks, so we need the atomic exchange */
+       nwait = xchg(&epi->nwait, 0);
 
-       while (!list_empty(lsthead)) {
-               epi = list_first_entry(lsthead, struct epitem, fllink);
+       if (nwait) {
+               while (!list_empty(lsthead)) {
+                       pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
 
-               ep = epi->ep;
-               list_del_init(&epi->fllink);
-               down_write(&ep->sem);
-               ep_remove(ep, epi);
-               up_write(&ep->sem);
+                       list_del_init(&pwq->llink);
+                       remove_wait_queue(pwq->whead, &pwq->wait);
+                       kmem_cache_free(pwq_cache, pwq);
+               }
        }
-
-       mutex_unlock(&epmutex);
 }
 
-
 /*
- * It opens an eventpoll file descriptor by suggesting a storage of "size"
- * file descriptors. The size parameter is just an hint about how to size
- * data structures. It won't prevent the user to store more than "size"
- * file descriptors inside the epoll interface. It is the kernel part of
- * the userspace epoll_create(2).
+ * Unlink the "struct epitem" from all places it might have been hooked up.
+ * This function must be called with write IRQ lock on "ep->lock".
  */
-asmlinkage long sys_epoll_create(int size)
+static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
 {
-       int error, fd = -1;
-       struct eventpoll *ep;
-       struct inode *inode;
-       struct file *file;
+       int error;
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
-                    current, size));
+       /*
+        * It can happen that this one is called for an item already unlinked.
+        * The check protect us from doing a double unlink ( crash ).
+        */
+       error = -ENOENT;
+       if (!ep_rb_linked(&epi->rbn))
+               goto error_return;
 
        /*
-        * Sanity check on the size parameter, and create the internal data
-        * structure ( "struct eventpoll" ).
+        * Clear the event mask for the unlinked item. This will avoid item
+        * notifications to be sent after the unlink operation from inside
+        * the kernel->userspace event transfer loop.
         */
-       error = -EINVAL;
-       if (size <= 0 || (error = ep_alloc(&ep)) != 0)
-               goto eexit_1;
+       epi->event.events = 0;
 
        /*
-        * Creates all the items needed to setup an eventpoll file. That is,
-        * a file structure, and inode and a free file descriptor.
+        * At this point is safe to do the job, unlink the item from our rb-tree.
+        * This operation togheter with the above check closes the door to
+        * double unlinks.
         */
-       error = ep_getfd(&fd, &inode, &file, ep);
-       if (error)
-               goto eexit_2;
+       ep_rb_erase(&epi->rbn, &ep->rbr);
 
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-                    current, size, fd));
+       /*
+        * If the item we are going to remove is inside the ready file descriptors
+        * we want to remove it from this list to avoid stale events.
+        */
+       if (ep_is_linked(&epi->rdllink))
+               list_del_init(&epi->rdllink);
 
-       return fd;
+       error = 0;
+error_return:
+
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
+                    current, ep, epi->ffd.file, error));
 
-eexit_2:
-       ep_free(ep);
-       kfree(ep);
-eexit_1:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
-                    current, size, error));
        return error;
 }
 
-
 /*
- * The following function implements the controller interface for
- * the eventpoll file that enables the insertion/removal/change of
- * file descriptors inside the interest set.  It represents
- * the kernel part of the user space epoll_ctl(2).
+ * Increment the usage count of the "struct epitem" making it sure
+ * that the user will have a valid pointer to reference.
  */
-asmlinkage long
-sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
+static void ep_use_epitem(struct epitem *epi)
 {
-       int error;
-       struct file *file, *tfile;
-       struct eventpoll *ep;
-       struct epitem *epi;
-       struct epoll_event epds;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
-                    current, epfd, op, fd, event));
-
-       error = -EFAULT;
-       if (ep_op_has_event(op) &&
-           copy_from_user(&epds, event, sizeof(struct epoll_event)))
-               goto eexit_1;
-
-       /* Get the "struct file *" for the eventpoll file */
-       error = -EBADF;
-       file = fget(epfd);
-       if (!file)
-               goto eexit_1;
-
-       /* Get the "struct file *" for the target file */
-       tfile = fget(fd);
-       if (!tfile)
-               goto eexit_2;
+       atomic_inc(&epi->usecnt);
+}
 
-       /* The target file descriptor must support poll */
-       error = -EPERM;
-       if (!tfile->f_op || !tfile->f_op->poll)
-               goto eexit_3;
+/*
+ * Decrement ( release ) the usage count by signaling that the user
+ * has finished using the structure. It might lead to freeing the
+ * structure itself if the count goes to zero.
+ */
+static void ep_release_epitem(struct epitem *epi)
+{
+       if (atomic_dec_and_test(&epi->usecnt))
+               kmem_cache_free(epi_cache, epi);
+}
 
-       /*
-        * We have to check that the file structure underneath the file descriptor
-        * the user passed to us _is_ an eventpoll file. And also we do not permit
-        * adding an epoll file descriptor inside itself.
-        */
-       error = -EINVAL;
-       if (file == tfile || !is_file_epoll(file))
-               goto eexit_3;
+/*
+ * Removes a "struct epitem" from the eventpoll RB tree and deallocates
+ * all the associated resources.
+ */
+static int ep_remove(struct eventpoll *ep, struct epitem *epi)
+{
+       int error;
+       unsigned long flags;
+       struct file *file = epi->ffd.file;
 
        /*
-        * At this point it is safe to assume that the "private_data" contains
-        * our own data structure.
+        * Removes poll wait queue hooks. We _have_ to do this without holding
+        * the "ep->lock" otherwise a deadlock might occur. This because of the
+        * sequence of the lock acquisition. Here we do "ep->lock" then the wait
+        * queue head lock when unregistering the wait queue. The wakeup callback
+        * will run by holding the wait queue head lock and will call our callback
+        * that will try to get "ep->lock".
         */
-       ep = file->private_data;
+       ep_unregister_pollwait(ep, epi);
 
-       down_write(&ep->sem);
+       /* Remove the current item from the list of epoll hooks */
+       spin_lock(&file->f_ep_lock);
+       if (ep_is_linked(&epi->fllink))
+               list_del_init(&epi->fllink);
+       spin_unlock(&file->f_ep_lock);
 
-       /* Try to lookup the file inside our RB tree */
-       epi = ep_find(ep, tfile, fd);
+       /* We need to acquire the write IRQ lock before calling ep_unlink() */
+       write_lock_irqsave(&ep->lock, flags);
 
-       error = -EINVAL;
-       switch (op) {
-       case EPOLL_CTL_ADD:
-               if (!epi) {
-                       epds.events |= POLLERR | POLLHUP;
+       /* Really unlink the item from the RB tree */
+       error = ep_unlink(ep, epi);
 
-                       error = ep_insert(ep, &epds, tfile, fd);
-               } else
-                       error = -EEXIST;
-               break;
-       case EPOLL_CTL_DEL:
-               if (epi)
-                       error = ep_remove(ep, epi);
-               else
-                       error = -ENOENT;
-               break;
-       case EPOLL_CTL_MOD:
-               if (epi) {
-                       epds.events |= POLLERR | POLLHUP;
-                       error = ep_modify(ep, epi, &epds);
-               } else
-                       error = -ENOENT;
-               break;
-       }
+       write_unlock_irqrestore(&ep->lock, flags);
 
-       /*
-        * The function ep_find() increments the usage count of the structure
-        * so, if this is not NULL, we need to release it.
-        */
-       if (epi)
-               ep_release_epitem(epi);
+       if (error)
+               goto error_return;
 
-       up_write(&ep->sem);
+       /* At this point it is safe to free the eventpoll item */
+       ep_release_epitem(epi);
 
-eexit_3:
-       fput(tfile);
-eexit_2:
-       fput(file);
-eexit_1:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
-                    current, epfd, op, fd, event, error));
+       error = 0;
+error_return:
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
+                    current, ep, file, error));
 
        return error;
 }
 
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_wait(2).
- */
-asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
-                              int maxevents, int timeout)
+static void ep_free(struct eventpoll *ep)
 {
-       int error;
-       struct file *file;
-       struct eventpoll *ep;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
-                    current, epfd, events, maxevents, timeout));
-
-       /* The maximum number of event must be greater than zero */
-       if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
-               return -EINVAL;
-
-       /* Verify that the area passed by the user is writeable */
-       if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
-               error = -EFAULT;
-               goto eexit_1;
-       }
+       struct rb_node *rbp;
+       struct epitem *epi;
 
-       /* Get the "struct file *" for the eventpoll file */
-       error = -EBADF;
-       file = fget(epfd);
-       if (!file)
-               goto eexit_1;
+       /* We need to release all tasks waiting for these file */
+       if (waitqueue_active(&ep->poll_wait))
+               ep_poll_safewake(&psw, &ep->poll_wait);
 
        /*
-        * We have to check that the file structure underneath the fd
-        * the user passed to us _is_ an eventpoll file.
+        * We need to lock this because we could be hit by
+        * eventpoll_release_file() while we're freeing the "struct eventpoll".
+        * We do not need to hold "ep->sem" here because the epoll file
+        * is on the way to be removed and no one has references to it
+        * anymore. The only hit might come from eventpoll_release_file() but
+        * holding "epmutex" is sufficent here.
         */
-       error = -EINVAL;
-       if (!is_file_epoll(file))
-               goto eexit_2;
+       mutex_lock(&epmutex);
 
        /*
-        * At this point it is safe to assume that the "private_data" contains
-        * our own data structure.
+        * Walks through the whole tree by unregistering poll callbacks.
         */
-       ep = file->private_data;
+       for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+               epi = rb_entry(rbp, struct epitem, rbn);
 
-       /* Time to fish for events ... */
-       error = ep_poll(ep, events, maxevents, timeout);
+               ep_unregister_pollwait(ep, epi);
+       }
 
-eexit_2:
-       fput(file);
-eexit_1:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
-                    current, epfd, events, maxevents, timeout, error));
+       /*
+        * Walks through the whole tree by freeing each "struct epitem". At this
+        * point we are sure no poll callbacks will be lingering around, and also by
+        * write-holding "sem" we can be sure that no file cleanup code will hit
+        * us during this operation. So we can avoid the lock on "ep->lock".
+        */
+       while ((rbp = rb_first(&ep->rbr)) != 0) {
+               epi = rb_entry(rbp, struct epitem, rbn);
+               ep_remove(ep, epi);
+       }
 
-       return error;
+       mutex_unlock(&epmutex);
 }
 
-
-#ifdef TIF_RESTORE_SIGMASK
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_pwait(2).
- */
-asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
-               int maxevents, int timeout, const sigset_t __user *sigmask,
-               size_t sigsetsize)
+static int ep_eventpoll_release(struct inode *inode, struct file *file)
 {
-       int error;
-       sigset_t ksigmask, sigsaved;
+       struct eventpoll *ep = file->private_data;
 
-       /*
-        * If the caller wants a certain signal mask to be set during the wait,
-        * we apply it here.
-        */
-       if (sigmask) {
-               if (sigsetsize != sizeof(sigset_t))
-                       return -EINVAL;
-               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
-                       return -EFAULT;
-               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       if (ep) {
+               ep_free(ep);
+               kfree(ep);
        }
 
-       error = sys_epoll_wait(epfd, events, maxevents, timeout);
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
+       return 0;
+}
 
-       /*
-        * If we changed the signal mask, we need to restore the original one.
-        * In case we've got a signal while waiting, we do not restore the
-        * signal mask yet, and we allow do_signal() to deliver the signal on
-        * the way back to userspace, before the signal mask is restored.
-        */
-       if (sigmask) {
-               if (error == -EINTR) {
-                       memcpy(&current->saved_sigmask, &sigsaved,
-                               sizeof(sigsaved));
-                       set_thread_flag(TIF_RESTORE_SIGMASK);
-               } else
-                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-       }
+static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
+{
+       unsigned int pollflags = 0;
+       unsigned long flags;
+       struct eventpoll *ep = file->private_data;
 
-       return error;
+       /* Insert inside our poll wait queue */
+       poll_wait(file, &ep->poll_wait, wait);
+
+       /* Check our condition */
+       read_lock_irqsave(&ep->lock, flags);
+       if (!list_empty(&ep->rdllist))
+               pollflags = POLLIN | POLLRDNORM;
+       read_unlock_irqrestore(&ep->lock, flags);
+
+       return pollflags;
 }
 
-#endif /* #ifdef TIF_RESTORE_SIGMASK */
+/* File callbacks that implement the eventpoll file behaviour */
+static const struct file_operations eventpoll_fops = {
+       .release        = ep_eventpoll_release,
+       .poll           = ep_eventpoll_poll
+};
 
+/* Fast test to see if the file is an evenpoll file */
+static inline int is_file_epoll(struct file *f)
+{
+       return f->f_op == &eventpoll_fops;
+}
 
 /*
- * Creates the file descriptor to be used by the epoll 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.
  */
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
-                   struct eventpoll *ep)
+void eventpoll_release_file(struct file *file)
 {
-       struct qstr this;
-       char name[32];
-       struct dentry *dentry;
-       struct inode *inode;
-       struct file *file;
-       int error, fd;
-
-       /* Get an ready to use file */
-       error = -ENFILE;
-       file = get_empty_filp();
-       if (!file)
-               goto eexit_1;
-
-       /* Allocates an inode from the eventpoll file system */
-       inode = ep_eventpoll_inode();
-       if (IS_ERR(inode)) {
-               error = PTR_ERR(inode);
-               goto eexit_2;
-       }
-
-       /* Allocates a free descriptor to plug the file onto */
-       error = get_unused_fd();
-       if (error < 0)
-               goto eexit_3;
-       fd = error;
+       struct list_head *lsthead = &file->f_ep_links;
+       struct eventpoll *ep;
+       struct epitem *epi;
 
        /*
-        * Link the inode to a directory entry by creating a unique name
-        * using the inode number.
+        * 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.
+        * The only hit might come from ep_free() but by holding the semaphore
+        * will correctly serialize the operation. We do need to acquire
+        * "ep->sem" after "epmutex" because ep_remove() requires it when called
+        * from anywhere but ep_free().
         */
-       error = -ENOMEM;
-       sprintf(name, "[%lu]", inode->i_ino);
-       this.name = name;
-       this.len = strlen(name);
-       this.hash = inode->i_ino;
-       dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this);
-       if (!dentry)
-               goto eexit_4;
-       dentry->d_op = &eventpollfs_dentry_operations;
-       d_add(dentry, inode);
-       file->f_path.mnt = mntget(eventpoll_mnt);
-       file->f_path.dentry = dentry;
-       file->f_mapping = inode->i_mapping;
-
-       file->f_pos = 0;
-       file->f_flags = O_RDONLY;
-       file->f_op = &eventpoll_fops;
-       file->f_mode = FMODE_READ;
-       file->f_version = 0;
-       file->private_data = ep;
-
-       /* Install the new setup file into the allocated fd. */
-       fd_install(fd, file);
-
-       *efd = fd;
-       *einode = inode;
-       *efile = file;
-       return 0;
+       mutex_lock(&epmutex);
 
-eexit_4:
-       put_unused_fd(fd);
-eexit_3:
-       iput(inode);
-eexit_2:
-       put_filp(file);
-eexit_1:
-       return error;
-}
+       while (!list_empty(lsthead)) {
+               epi = list_first_entry(lsthead, struct epitem, fllink);
+
+               ep = epi->ep;
+               list_del_init(&epi->fllink);
+               down_write(&ep->sem);
+               ep_remove(ep, epi);
+               up_write(&ep->sem);
+       }
 
+       mutex_unlock(&epmutex);
+}
 
 static int ep_alloc(struct eventpoll **pep)
 {
@@ -822,50 +635,6 @@ static int ep_alloc(struct eventpoll **pep)
        return 0;
 }
 
-
-static void ep_free(struct eventpoll *ep)
-{
-       struct rb_node *rbp;
-       struct epitem *epi;
-
-       /* We need to release all tasks waiting for these file */
-       if (waitqueue_active(&ep->poll_wait))
-               ep_poll_safewake(&psw, &ep->poll_wait);
-
-       /*
-        * We need to lock this because we could be hit by
-        * eventpoll_release_file() while we're freeing the "struct eventpoll".
-        * We do not need to hold "ep->sem" here because the epoll file
-        * is on the way to be removed and no one has references to it
-        * anymore. The only hit might come from eventpoll_release_file() but
-        * holding "epmutex" is sufficent here.
-        */
-       mutex_lock(&epmutex);
-
-       /*
-        * Walks through the whole tree by unregistering poll callbacks.
-        */
-       for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
-               epi = rb_entry(rbp, struct epitem, rbn);
-
-               ep_unregister_pollwait(ep, epi);
-       }
-
-       /*
-        * Walks through the whole tree by freeing each "struct epitem". At this
-        * point we are sure no poll callbacks will be lingering around, and also by
-        * write-holding "sem" we can be sure that no file cleanup code will hit
-        * us during this operation. So we can avoid the lock on "ep->lock".
-        */
-       while ((rbp = rb_first(&ep->rbr)) != 0) {
-               epi = rb_entry(rbp, struct epitem, rbn);
-               ep_remove(ep, epi);
-       }
-
-       mutex_unlock(&epmutex);
-}
-
-
 /*
  * Search the file inside the eventpoll tree. It add usage count to
  * the returned item, so the caller must call ep_release_epitem()
@@ -902,30 +671,58 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd)
        return epir;
 }
 
-
 /*
- * Increment the usage count of the "struct epitem" making it sure
- * that the user will have a valid pointer to reference.
+ * This is the callback that is passed to the wait queue wakeup
+ * machanism. It is called by the stored file descriptors when they
+ * have events to report.
  */
-static void ep_use_epitem(struct epitem *epi)
+static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
 {
+       int pwake = 0;
+       unsigned long flags;
+       struct epitem *epi = ep_item_from_wait(wait);
+       struct eventpoll *ep = epi->ep;
 
-       atomic_inc(&epi->usecnt);
-}
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
+                    current, epi->ffd.file, epi, ep));
 
+       write_lock_irqsave(&ep->lock, flags);
 
-/*
- * Decrement ( release ) the usage count by signaling that the user
- * has finished using the structure. It might lead to freeing the
- * structure itself if the count goes to zero.
- */
-static void ep_release_epitem(struct epitem *epi)
-{
+       /*
+        * If the event mask does not contain any poll(2) event, we consider the
+        * descriptor to be disabled. This condition is likely the effect of the
+        * EPOLLONESHOT bit that disables the descriptor when an event is received,
+        * until the next EPOLL_CTL_MOD will be issued.
+        */
+       if (!(epi->event.events & ~EP_PRIVATE_BITS))
+               goto is_disabled;
 
-       if (atomic_dec_and_test(&epi->usecnt))
-               kmem_cache_free(epi_cache, epi);
-}
+       /* If this file is already in the ready list we exit soon */
+       if (ep_is_linked(&epi->rdllink))
+               goto is_linked;
 
+       list_add_tail(&epi->rdllink, &ep->rdllist);
+
+is_linked:
+       /*
+        * Wake up ( if active ) both the eventpoll wait list and the ->poll()
+        * wait list.
+        */
+       if (waitqueue_active(&ep->wq))
+               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+                                TASK_INTERRUPTIBLE);
+       if (waitqueue_active(&ep->poll_wait))
+               pwake++;
+
+is_disabled:
+       write_unlock_irqrestore(&ep->lock, flags);
+
+       /* We have to call this outside the lock */
+       if (pwake)
+               ep_poll_safewake(&psw, &ep->poll_wait);
+
+       return 1;
+}
 
 /*
  * This is the callback that is used to add our wait queue to the
@@ -950,7 +747,6 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
        }
 }
 
-
 static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
 {
        int kcmp;
@@ -970,7 +766,6 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
        rb_insert_color(&epi->rbn, &ep->rbr);
 }
 
-
 static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
                     struct file *tfile, int fd)
 {
@@ -981,7 +776,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        error = -ENOMEM;
        if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
-               goto eexit_1;
+               goto error_return;
 
        /* Item initialization follow here ... */
        ep_rb_initnode(&epi->rbn);
@@ -1011,7 +806,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
         * high memory pressure.
         */
        if (epi->nwait < 0)
-               goto eexit_2;
+               goto error_unregister;
 
        /* Add the current item to the list of active epoll hook for this file */
        spin_lock(&tfile->f_ep_lock);
@@ -1046,7 +841,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 
        return 0;
 
-eexit_2:
+error_unregister:
        ep_unregister_pollwait(ep, epi);
 
        /*
@@ -1059,11 +854,10 @@ eexit_2:
        write_unlock_irqrestore(&ep->lock, flags);
 
        kmem_cache_free(epi_cache, epi);
-eexit_1:
+error_return:
        return error;
 }
 
-
 /*
  * Modify the interest event mask by dropping an event if the new mask
  * has a match in the current file status.
@@ -1117,225 +911,15 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
                }
        }
 
-       write_unlock_irqrestore(&ep->lock, flags);
-
-       /* We have to call this outside the lock */
-       if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
-
-       return 0;
-}
-
-
-/*
- * This function unregister poll callbacks from the associated file descriptor.
- * Since this must be called without holding "ep->lock" the atomic exchange trick
- * will protect us from multiple unregister.
- */
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
-{
-       int nwait;
-       struct list_head *lsthead = &epi->pwqlist;
-       struct eppoll_entry *pwq;
-
-       /* This is called without locks, so we need the atomic exchange */
-       nwait = xchg(&epi->nwait, 0);
-
-       if (nwait) {
-               while (!list_empty(lsthead)) {
-                       pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
-
-                       list_del_init(&pwq->llink);
-                       remove_wait_queue(pwq->whead, &pwq->wait);
-                       kmem_cache_free(pwq_cache, pwq);
-               }
-       }
-}
-
-
-/*
- * Unlink the "struct epitem" from all places it might have been hooked up.
- * This function must be called with write IRQ lock on "ep->lock".
- */
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
-{
-       int error;
-
-       /*
-        * It can happen that this one is called for an item already unlinked.
-        * The check protect us from doing a double unlink ( crash ).
-        */
-       error = -ENOENT;
-       if (!ep_rb_linked(&epi->rbn))
-               goto eexit_1;
-
-       /*
-        * Clear the event mask for the unlinked item. This will avoid item
-        * notifications to be sent after the unlink operation from inside
-        * the kernel->userspace event transfer loop.
-        */
-       epi->event.events = 0;
-
-       /*
-        * At this point is safe to do the job, unlink the item from our rb-tree.
-        * This operation togheter with the above check closes the door to
-        * double unlinks.
-        */
-       ep_rb_erase(&epi->rbn, &ep->rbr);
-
-       /*
-        * If the item we are going to remove is inside the ready file descriptors
-        * we want to remove it from this list to avoid stale events.
-        */
-       if (ep_is_linked(&epi->rdllink))
-               list_del_init(&epi->rdllink);
-
-       error = 0;
-eexit_1:
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
-                    current, ep, epi->ffd.file, error));
-
-       return error;
-}
-
-
-/*
- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
- * all the associated resources.
- */
-static int ep_remove(struct eventpoll *ep, struct epitem *epi)
-{
-       int error;
-       unsigned long flags;
-       struct file *file = epi->ffd.file;
-
-       /*
-        * Removes poll wait queue hooks. We _have_ to do this without holding
-        * the "ep->lock" otherwise a deadlock might occur. This because of the
-        * sequence of the lock acquisition. Here we do "ep->lock" then the wait
-        * queue head lock when unregistering the wait queue. The wakeup callback
-        * will run by holding the wait queue head lock and will call our callback
-        * that will try to get "ep->lock".
-        */
-       ep_unregister_pollwait(ep, epi);
-
-       /* Remove the current item from the list of epoll hooks */
-       spin_lock(&file->f_ep_lock);
-       if (ep_is_linked(&epi->fllink))
-               list_del_init(&epi->fllink);
-       spin_unlock(&file->f_ep_lock);
-
-       /* We need to acquire the write IRQ lock before calling ep_unlink() */
-       write_lock_irqsave(&ep->lock, flags);
-
-       /* Really unlink the item from the RB tree */
-       error = ep_unlink(ep, epi);
-
-       write_unlock_irqrestore(&ep->lock, flags);
-
-       if (error)
-               goto eexit_1;
-
-       /* At this point it is safe to free the eventpoll item */
-       ep_release_epitem(epi);
-
-       error = 0;
-eexit_1:
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
-                    current, ep, file, error));
-
-       return error;
-}
-
-
-/*
- * This is the callback that is passed to the wait queue wakeup
- * machanism. It is called by the stored file descriptors when they
- * have events to report.
- */
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
-{
-       int pwake = 0;
-       unsigned long flags;
-       struct epitem *epi = ep_item_from_wait(wait);
-       struct eventpoll *ep = epi->ep;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
-                    current, epi->ffd.file, epi, ep));
-
-       write_lock_irqsave(&ep->lock, flags);
-
-       /*
-        * If the event mask does not contain any poll(2) event, we consider the
-        * descriptor to be disabled. This condition is likely the effect of the
-        * EPOLLONESHOT bit that disables the descriptor when an event is received,
-        * until the next EPOLL_CTL_MOD will be issued.
-        */
-       if (!(epi->event.events & ~EP_PRIVATE_BITS))
-               goto is_disabled;
-
-       /* If this file is already in the ready list we exit soon */
-       if (ep_is_linked(&epi->rdllink))
-               goto is_linked;
-
-       list_add_tail(&epi->rdllink, &ep->rdllist);
-
-is_linked:
-       /*
-        * Wake up ( if active ) both the eventpoll wait list and the ->poll()
-        * wait list.
-        */
-       if (waitqueue_active(&ep->wq))
-               __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
-                                TASK_INTERRUPTIBLE);
-       if (waitqueue_active(&ep->poll_wait))
-               pwake++;
-
-is_disabled:
-       write_unlock_irqrestore(&ep->lock, flags);
-
-       /* We have to call this outside the lock */
-       if (pwake)
-               ep_poll_safewake(&psw, &ep->poll_wait);
-
-       return 1;
-}
-
-
-static int ep_eventpoll_close(struct inode *inode, struct file *file)
-{
-       struct eventpoll *ep = file->private_data;
-
-       if (ep) {
-               ep_free(ep);
-               kfree(ep);
-       }
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
-       return 0;
-}
-
-
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
-{
-       unsigned int pollflags = 0;
-       unsigned long flags;
-       struct eventpoll *ep = file->private_data;
-
-       /* Insert inside our poll wait queue */
-       poll_wait(file, &ep->poll_wait, wait);
+       write_unlock_irqrestore(&ep->lock, flags);
 
-       /* Check our condition */
-       read_lock_irqsave(&ep->lock, flags);
-       if (!list_empty(&ep->rdllist))
-               pollflags = POLLIN | POLLRDNORM;
-       read_unlock_irqrestore(&ep->lock, flags);
+       /* We have to call this outside the lock */
+       if (pwake)
+               ep_poll_safewake(&psw, &ep->poll_wait);
 
-       return pollflags;
+       return 0;
 }
 
-
 /*
  * This function is called without holding the "ep->lock" since the call to
  * __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
@@ -1447,7 +1031,6 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
        return eventcnt == 0 ? error: eventcnt;
 }
 
-
 /*
  * Perform the transfer of events to user space.
  */
@@ -1483,7 +1066,6 @@ static int ep_events_transfer(struct eventpoll *ep,
        return eventcnt;
 }
 
-
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout)
 {
@@ -1553,52 +1135,262 @@ retry:
        return res;
 }
 
-static int eventpollfs_delete_dentry(struct dentry *dentry)
+/*
+ * It opens an eventpoll file descriptor by suggesting a storage of "size"
+ * file descriptors. The size parameter is just an hint about how to size
+ * data structures. It won't prevent the user to store more than "size"
+ * file descriptors inside the epoll interface. It is the kernel part of
+ * the userspace epoll_create(2).
+ */
+asmlinkage long sys_epoll_create(int size)
 {
+       int error, fd = -1;
+       struct eventpoll *ep;
+       struct inode *inode;
+       struct file *file;
 
-       return 1;
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
+                    current, size));
+
+       /*
+        * Sanity check on the size parameter, and create the internal data
+        * structure ( "struct eventpoll" ).
+        */
+       error = -EINVAL;
+       if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+               goto error_return;
+
+       /*
+        * Creates all the items needed to setup an eventpoll file. That is,
+        * a file structure, and inode and a free file descriptor.
+        */
+       error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
+                                &eventpoll_fops, ep);
+       if (error)
+               goto error_free;
+
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+                    current, size, fd));
+
+       return fd;
+
+error_free:
+       ep_free(ep);
+       kfree(ep);
+error_return:
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+                    current, size, error));
+       return error;
 }
 
-static struct inode *ep_eventpoll_inode(void)
+/*
+ * The following function implements the controller interface for
+ * the eventpoll file that enables the insertion/removal/change of
+ * file descriptors inside the interest set.  It represents
+ * the kernel part of the user space epoll_ctl(2).
+ */
+asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
+                             struct epoll_event __user *event)
 {
-       int error = -ENOMEM;
-       struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
+       int error;
+       struct file *file, *tfile;
+       struct eventpoll *ep;
+       struct epitem *epi;
+       struct epoll_event epds;
+
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
+                    current, epfd, op, fd, event));
+
+       error = -EFAULT;
+       if (ep_op_has_event(op) &&
+           copy_from_user(&epds, event, sizeof(struct epoll_event)))
+               goto error_return;
+
+       /* Get the "struct file *" for the eventpoll file */
+       error = -EBADF;
+       file = fget(epfd);
+       if (!file)
+               goto error_return;
+
+       /* Get the "struct file *" for the target file */
+       tfile = fget(fd);
+       if (!tfile)
+               goto error_fput;
+
+       /* The target file descriptor must support poll */
+       error = -EPERM;
+       if (!tfile->f_op || !tfile->f_op->poll)
+               goto error_tgt_fput;
+
+       /*
+        * We have to check that the file structure underneath the file descriptor
+        * the user passed to us _is_ an eventpoll file. And also we do not permit
+        * adding an epoll file descriptor inside itself.
+        */
+       error = -EINVAL;
+       if (file == tfile || !is_file_epoll(file))
+               goto error_tgt_fput;
+
+       /*
+        * At this point it is safe to assume that the "private_data" contains
+        * our own data structure.
+        */
+       ep = file->private_data;
+
+       down_write(&ep->sem);
 
-       if (!inode)
-               goto eexit_1;
+       /* Try to lookup the file inside our RB tree */
+       epi = ep_find(ep, tfile, fd);
 
-       inode->i_fop = &eventpoll_fops;
+       error = -EINVAL;
+       switch (op) {
+       case EPOLL_CTL_ADD:
+               if (!epi) {
+                       epds.events |= POLLERR | POLLHUP;
 
+                       error = ep_insert(ep, &epds, tfile, fd);
+               } else
+                       error = -EEXIST;
+               break;
+       case EPOLL_CTL_DEL:
+               if (epi)
+                       error = ep_remove(ep, epi);
+               else
+                       error = -ENOENT;
+               break;
+       case EPOLL_CTL_MOD:
+               if (epi) {
+                       epds.events |= POLLERR | POLLHUP;
+                       error = ep_modify(ep, epi, &epds);
+               } else
+                       error = -ENOENT;
+               break;
+       }
        /*
-        * Mark the inode dirty from the very beginning,
-        * that way it will never be moved to the dirty
-        * list because mark_inode_dirty() will think
-        * that it already _is_ on the dirty list.
+        * The function ep_find() increments the usage count of the structure
+        * so, if this is not NULL, we need to release it.
         */
-       inode->i_state = I_DIRTY;
-       inode->i_mode = S_IRUSR | S_IWUSR;
-       inode->i_uid = current->fsuid;
-       inode->i_gid = current->fsgid;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       return inode;
-
-eexit_1:
-       return ERR_PTR(error);
+       if (epi)
+               ep_release_epitem(epi);
+       up_write(&ep->sem);
+
+error_tgt_fput:
+       fput(tfile);
+error_fput:
+       fput(file);
+error_return:
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
+                    current, epfd, op, fd, event, error));
+
+       return error;
 }
 
-static int
-eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
-                  const char *dev_name, void *data, struct vfsmount *mnt)
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_wait(2).
+ */
+asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+                              int maxevents, int timeout)
 {
-       return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
-                            mnt);
+       int error;
+       struct file *file;
+       struct eventpoll *ep;
+
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
+                    current, epfd, events, maxevents, timeout));
+
+       /* The maximum number of event must be greater than zero */
+       if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
+               return -EINVAL;
+
+       /* Verify that the area passed by the user is writeable */
+       if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
+               error = -EFAULT;
+               goto error_return;
+       }
+
+       /* Get the "struct file *" for the eventpoll file */
+       error = -EBADF;
+       file = fget(epfd);
+       if (!file)
+               goto error_return;
+
+       /*
+        * We have to check that the file structure underneath the fd
+        * the user passed to us _is_ an eventpoll file.
+        */
+       error = -EINVAL;
+       if (!is_file_epoll(file))
+               goto error_fput;
+
+       /*
+        * At this point it is safe to assume that the "private_data" contains
+        * our own data structure.
+        */
+       ep = file->private_data;
+
+       /* Time to fish for events ... */
+       error = ep_poll(ep, events, maxevents, timeout);
+
+error_fput:
+       fput(file);
+error_return:
+       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
+                    current, epfd, events, maxevents, timeout, error));
+
+       return error;
 }
 
+#ifdef TIF_RESTORE_SIGMASK
 
-static int __init eventpoll_init(void)
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+               int maxevents, int timeout, const sigset_t __user *sigmask,
+               size_t sigsetsize)
 {
        int error;
+       sigset_t ksigmask, sigsaved;
+
+       /*
+        * If the caller wants a certain signal mask to be set during the wait,
+        * we apply it here.
+        */
+       if (sigmask) {
+               if (sigsetsize != sizeof(sigset_t))
+                       return -EINVAL;
+               if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+                       return -EFAULT;
+               sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+               sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+       }
+
+       error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+       /*
+        * If we changed the signal mask, we need to restore the original one.
+        * In case we've got a signal while waiting, we do not restore the
+        * signal mask yet, and we allow do_signal() to deliver the signal on
+        * the way back to userspace, before the signal mask is restored.
+        */
+       if (sigmask) {
+               if (error == -EINTR) {
+                       memcpy(&current->saved_sigmask, &sigsaved,
+                               sizeof(sigsaved));
+                       set_thread_flag(TIF_RESTORE_SIGMASK);
+               } else
+                       sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+       }
+
+       return error;
+}
+
+#endif /* #ifdef TIF_RESTORE_SIGMASK */
 
+static int __init eventpoll_init(void)
+{
        mutex_init(&epmutex);
 
        /* Initialize the structure used to perform safe poll wait head wake ups */
@@ -1614,39 +1406,7 @@ static int __init eventpoll_init(void)
                        sizeof(struct eppoll_entry), 0,
                        EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
 
-       /*
-        * Register the virtual file system that will be the source of inodes
-        * for the eventpoll files
-        */
-       error = register_filesystem(&eventpoll_fs_type);
-       if (error)
-               goto epanic;
-
-       /* Mount the above commented virtual file system */
-       eventpoll_mnt = kern_mount(&eventpoll_fs_type);
-       error = PTR_ERR(eventpoll_mnt);
-       if (IS_ERR(eventpoll_mnt))
-               goto epanic;
-
-       DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n",
-                       current));
        return 0;
-
-epanic:
-       panic("eventpoll_init() failed\n");
-}
-
-
-static void __exit eventpoll_exit(void)
-{
-       /* Undo all operations done inside eventpoll_init() */
-       unregister_filesystem(&eventpoll_fs_type);
-       mntput(eventpoll_mnt);
-       kmem_cache_destroy(pwq_cache);
-       kmem_cache_destroy(epi_cache);
 }
+fs_initcall(eventpoll_init);
 
-module_init(eventpoll_init);
-module_exit(eventpoll_exit);
-
-MODULE_LICENSE("GPL");
index 1ba85c7fc6af7e4290ac494563f3fc6c8d8587bd..955a8eb66d7061af552121766f9b1edc241d2ca6 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,6 +50,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
+#include <linux/signalfd.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -581,6 +582,13 @@ static int de_thread(struct task_struct *tsk)
        struct task_struct *leader = NULL;
        int count;
 
+       /*
+        * Tell all the sighand listeners that this sighand has
+        * been detached. The signalfd_detach() function grabs the
+        * sighand lock, if signal listeners are present on the sighand.
+        */
+       signalfd_detach(tsk);
+
        /*
         * If we don't share sighandlers, then we aren't sharing anything
         * and we can just re-use it all.
@@ -702,7 +710,7 @@ static int de_thread(struct task_struct *tsk)
                 */
                detach_pid(tsk, PIDTYPE_PID);
                tsk->pid = leader->pid;
-               attach_pid(tsk, PIDTYPE_PID,  tsk->pid);
+               attach_pid(tsk, PIDTYPE_PID,  find_pid(tsk->pid));
                transfer_pid(leader, tsk, PIDTYPE_PGID);
                transfer_pid(leader, tsk, PIDTYPE_SID);
                list_replace_rcu(&leader->tasks, &tsk->tasks);
@@ -757,8 +765,7 @@ no_thread_group:
                spin_unlock(&oldsighand->siglock);
                write_unlock_irq(&tasklist_lock);
 
-               if (atomic_dec_and_test(&oldsighand->count))
-                       kmem_cache_free(sighand_cachep, oldsighand);
+               __cleanup_sighand(oldsighand);
        }
 
        BUG_ON(!thread_group_leader(tsk));
index e1bb031719864e644cc55f7446c92efb83b5a0bc..a6cb6171c3af7af846769d8e9632ac92854b090e 100644 (file)
@@ -1767,7 +1767,6 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
        struct inode *inode = mapping->host;
        struct buffer_head *bh;
        int err = 0;
-       void *kaddr;
 
        blocksize = inode->i_sb->s_blocksize;
        length = blocksize - (offset & (blocksize - 1));
@@ -1779,10 +1778,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
         */
        if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
             ext3_should_writeback_data(inode) && PageUptodate(page)) {
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + offset, 0, length);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, offset, length, KM_USER0);
                set_page_dirty(page);
                goto unlock;
        }
@@ -1835,11 +1831,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
                        goto unlock;
        }
 
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, length);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
-
+       zero_user_page(page, offset, length, KM_USER0);
        BUFFER_TRACE(bh, "zeroed end of block");
 
        err = 0;
index 0208cc7ac5d0f0835ed0bceb206cce2baef5fae5..47552d4a6324effeb085c603c91dfcf945ed46f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd/checkpoint.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
index 11563fe2a52bed60eafe259d92ae3aedbfa64e98..2a5f4b833e353626d6b3d6199e6ea13f2989e3de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/recovery.c
+ * linux/fs/jbd/recovery.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
index a68cbb6050221078e721797c1fa9d817fa8b3af7..824e3b7d4ec15266e9f0825cccaeeb2231e5b54c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/revoke.c
+ * linux/fs/jbd/revoke.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
  *
index f9822fc07851ff44d7901906513a024512b2ceb0..772b6531a2a25fe09f5499dd9d2b359e8edf18bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/transaction.c
+ * linux/fs/jbd/transaction.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
  *
index 68039fa9a566be70de4fb9f89cd3dab25621f923..3fccde7ba008cb7b760f8128f9b571038e83b67c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd2/checkpoint.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
index 9f10acafaf70cee2482d68cad762e6e7dff59781..395c92a04ac93beea84b4c456c65670c6fe2e250 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/recovery.c
+ * linux/fs/jbd2/recovery.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
  *
index 1e864dcc49ea973b4bf193c3a78f962e57016292..9246e763da78f1491d53b9f0ae12d89579494eaf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/revoke.c
+ * linux/fs/jbd2/revoke.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
  *
index e347d8c078bc73e47c6f1f30b088d40b5e5868e3..7946ff43fc40b5d91290efe2d5401e3aa3bf0d07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/fs/transaction.c
+ * linux/fs/jbd2/transaction.c
  *
  * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
  *
diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h
deleted file mode 100644 (file)
index fa3dac1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER_MIPS 1043
-static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
index 6aff38930b50619475e4e2974341427f185298b8..4884d5edfe658282d626c6674497231a9ff4d20a 100644 (file)
@@ -219,9 +219,9 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                struct jffs2_tmp_dnode_info *tn)
 {
        uint32_t fn_end = tn->fn->ofs + tn->fn->size;
-       struct jffs2_tmp_dnode_info *insert_point = NULL, *this;
+       struct jffs2_tmp_dnode_info *this;
 
-       dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version);
+       dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
 
        /* If a node has zero dsize, we only have to keep if it if it might be the
           node with highest version -- i.e. the one which will end up as f->metadata.
@@ -240,23 +240,16 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
 
        /* Find the earliest node which _may_ be relevant to this one */
        this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
-       if (!this) {
-               /* First addition to empty tree. $DEITY how I love the easy cases */
-               rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node);
-               rb_insert_color(&tn->rb, &rii->tn_root);
-               dbg_readinode("keep new frag\n");
-               return 0;
-       }
-
-       /* If we add a new node it'll be somewhere under here. */
-       insert_point = this;
-
-       /* If the node is coincident with another at a lower address,
-          back up until the other node is found. It may be relevant */
-       while (tn->overlapped)
-               tn = tn_prev(tn);
+       if (this) {
+               /* If the node is coincident with another at a lower address,
+                  back up until the other node is found. It may be relevant */
+               while (this->overlapped)
+                       this = tn_prev(this);
 
-       dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+               /* First node should never be marked overlapped */
+               BUG_ON(!this);
+               dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+       }
 
        while (this) {
                if (this->fn->ofs > fn_end)
@@ -274,11 +267,10 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                return 0;
                        } else {
                                /* Who cares if the new one is good; keep it for now anyway. */
+                               dbg_readinode("Like new node. Throw away old\n");
                                rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-                               /* Same overlapping from in front and behind */
-                               tn->overlapped = this->overlapped;
                                jffs2_kill_tn(c, this);
-                               dbg_readinode("Like new node. Throw away old\n");
+                               /* Same overlapping from in front and behind */
                                return 0;
                        }
                }
@@ -291,13 +283,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                jffs2_kill_tn(c, tn);
                                return 0;
                        }
-                       /* ... and is good. Kill 'this'... */
-                       rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-                       tn->overlapped = this->overlapped;
-                       jffs2_kill_tn(c, this);
-                       /* ... and any subsequent nodes which are also overlapped */
-                       this = tn_next(tn);
-                       while (this && this->fn->ofs + this->fn->size < fn_end) {
+                       /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
+                       while (this && this->fn->ofs + this->fn->size <= fn_end) {
                                struct jffs2_tmp_dnode_info *next = tn_next(this);
                                if (this->version < tn->version) {
                                        tn_erase(this, &rii->tn_root);
@@ -308,8 +295,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                }
                                this = next;
                        }
-                       dbg_readinode("Done inserting new\n");
-                       return 0;
+                       dbg_readinode("Done killing overlapped nodes\n");
+                       continue;
                }
                if (this->version > tn->version &&
                    this->fn->ofs <= tn->fn->ofs &&
@@ -321,29 +308,21 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                return 0;
                        }
                        /* ... but 'this' was bad. Replace it... */
-                       rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
                        dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
+                       tn_erase(this, &rii->tn_root);
                        jffs2_kill_tn(c, this);
-                       return 0;
+                       break;
                }
-               /* We want to be inserted under the last node which is
-                  either at a lower offset _or_ has a smaller range */
-               if (this->fn->ofs < tn->fn->ofs ||
-                   (this->fn->ofs == tn->fn->ofs &&
-                    this->fn->size <= tn->fn->size))
-                       insert_point = this;
 
                this = tn_next(this);
        }
-       dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n",
-                     insert_point, insert_point->version, insert_point->fn->ofs,
-                     insert_point->fn->ofs+insert_point->fn->size,
-                     insert_point->overlapped);
+
        /* We neither completely obsoleted nor were completely
-          obsoleted by an earlier node. Insert under insert_point */
+          obsoleted by an earlier node. Insert into the tree */
        {
-               struct rb_node *parent = &insert_point->rb;
-               struct rb_node **link = &parent;
+               struct rb_node *parent;
+               struct rb_node **link = &rii->tn_root.rb_node;
+               struct jffs2_tmp_dnode_info *insert_point = NULL;
 
                while (*link) {
                        parent = *link;
@@ -359,6 +338,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                rb_link_node(&tn->rb, &insert_point->rb, link);
                rb_insert_color(&tn->rb, &rii->tn_root);
        }
+
        /* If there's anything behind that overlaps us, note it */
        this = tn_prev(tn);
        if (this) {
@@ -457,7 +437,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
        this = tn_last(&rii->tn_root);
        while (this) {
                dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs,
-                            this->fn->ofs+this->fn->size, this->overlapped);
+                             this->fn->ofs+this->fn->size, this->overlapped);
                this = tn_prev(this);
        }
 #endif
@@ -483,7 +463,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
                        vers_next = tn_prev(this);
                        eat_last(&ver_root, &this->rb);
                        if (check_tn_node(c, this)) {
-                               dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n",
+                               dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n",
                                             this->version, this->fn->ofs,
                                             this->fn->ofs+this->fn->size);
                                jffs2_kill_tn(c, this);
@@ -496,7 +476,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
                                        high_ver = this->version;
                                        rii->latest_ref = this->fn->raw;
                                }
-                               dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n",
+                               dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n",
                                             this, this->version, this->fn->ofs,
                                             this->fn->ofs+this->fn->size, this->overlapped);
 
@@ -850,7 +830,7 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                return ret;
        }
 #ifdef JFFS2_DBG_READINODE_MESSAGES
-       dbg_readinode("After adding ver %d:\n", tn->version);
+       dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));
        tn = tn_first(&rii->tn_root);
        while (tn) {
                dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",
index c556e85a565cea44fbceca308514fa51e5c80c3e..91d1d0f1c66c72c1d0c925d383f8e2a02973e2c4 100644 (file)
@@ -637,7 +637,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 
        memset(c->wbuf,0xff,c->wbuf_pagesize);
        /* adjust write buffer offset, else we get a non contiguous write bug */
-       c->wbuf_ofs += c->wbuf_pagesize;
+       if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize))
+               c->wbuf_ofs += c->wbuf_pagesize;
+       else
+               c->wbuf_ofs = 0xffffffff;
        c->wbuf_len = 0;
        return 0;
 }
index 82b0544bd76d197053d4f7f9557d5f5a87e06b95..f3b1ebb2228036ba4fbdb2a483f0b958323ca16a 100644 (file)
@@ -1507,7 +1507,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
                if (l2nb < budmin) {
 
                        /* search the lower level dmap control pages to get
-                        * the starting block number of the the dmap that
+                        * the starting block number of the dmap that
                         * contains or starts off the free space.
                         */
                        if ((rc =
index c465607be9913faa0aecd236b2e426076242cda6..c6530227cda66d10b2e18816c419a8f391b0a764 100644 (file)
@@ -386,7 +386,7 @@ int diRead(struct inode *ip)
                return -EIO;
        }
 
-       /* locate the the disk inode requested */
+       /* locate the disk inode requested */
        dp = (struct dinode *) mp->data;
        dp += rel_inode;
 
@@ -1407,7 +1407,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
        inum = pip->i_ino + 1;
        ino = inum & (INOSPERIAG - 1);
 
-       /* back off the the hint if it is outside of the iag */
+       /* back off the hint if it is outside of the iag */
        if (ino == 0)
                inum = pip->i_ino;
 
index 6a3f00dc8c833c18cc45439eb08fa41d6438705b..44a2f33cb98d5d7e3e81ebe7cb0f7c2a12270d29 100644 (file)
@@ -1960,7 +1960,7 @@ static void lbmfree(struct lbuf * bp)
 /*
  * NAME:       lbmRedrive
  *
- * FUNCTION:   add a log buffer to the the log redrive list
+ * FUNCTION:   add a log buffer to the log redrive list
  *
  * PARAMETER:
  *     bp      - log buffer
index 1247ee90253a96f954e1c0783066afe8889a9afc..5294de1f40c41ba3c2dfcd992c725202967b0dce 100644 (file)
@@ -159,7 +159,10 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
                                        continue;
 
                                spin_unlock(&dcache_lock);
-                               if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
+                               if (filldir(dirent, next->d_name.name, 
+                                           next->d_name.len, filp->f_pos, 
+                                           next->d_inode->i_ino, 
+                                           dt_type(next->d_inode)) < 0)
                                        return 0;
                                spin_lock(&dcache_lock);
                                /* next is still alive */
index 671a034dc999fffdf88856401694fda0cef87147..8ec16ab5ef7449222744b3c2829e37fbf8f6d88b 100644 (file)
@@ -669,7 +669,6 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
 
-       fl->fl_type = F_UNLCK;
        lock_kernel();
        for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
                if (!IS_POSIX(cfl))
@@ -681,7 +680,8 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                __locks_copy_lock(fl, cfl);
                unlock_kernel();
                return 1;
-       }
+       } else
+               fl->fl_type = F_UNLCK;
        unlock_kernel();
        return 0;
 }
@@ -1632,6 +1632,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
        flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
                fl->fl_end - fl->fl_start + 1;
        flock->l_whence = 0;
+       flock->l_type = fl->fl_type;
        return 0;
 }
 
index fa2441f57b4194fe498e9e35ba42fbd936029cad..c1698f2291aa2ee953b54f71a092b4908b4fb343 100644 (file)
@@ -284,11 +284,9 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
        }
 
        if (first_hole != blocks_per_page) {
-               char *kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + (first_hole << blkbits), 0,
-                               PAGE_CACHE_SIZE - (first_hole << blkbits));
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, first_hole << blkbits,
+                               PAGE_CACHE_SIZE - (first_hole << blkbits),
+                               KM_USER0);
                if (first_hole == 0) {
                        SetPageUptodate(page);
                        unlock_page(page);
@@ -456,11 +454,18 @@ EXPORT_SYMBOL(mpage_readpage);
  * written, so it can intelligently allocate a suitably-sized BIO.  For now,
  * just allocate full-size (16-page) BIOs.
  */
-static struct bio *
-__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
-       sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc,
-       writepage_t writepage_fn)
+struct mpage_data {
+       struct bio *bio;
+       sector_t last_block_in_bio;
+       get_block_t *get_block;
+       unsigned use_writepage;
+};
+
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
+                            void *data)
 {
+       struct mpage_data *mpd = data;
+       struct bio *bio = mpd->bio;
        struct address_space *mapping = page->mapping;
        struct inode *inode = page->mapping->host;
        const unsigned blkbits = inode->i_blkbits;
@@ -478,6 +483,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
        int length;
        struct buffer_head map_bh;
        loff_t i_size = i_size_read(inode);
+       int ret = 0;
 
        if (page_has_buffers(page)) {
                struct buffer_head *head = page_buffers(page);
@@ -540,7 +546,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
 
                map_bh.b_state = 0;
                map_bh.b_size = 1 << blkbits;
-               if (get_block(inode, block_in_file, &map_bh, 1))
+               if (mpd->get_block(inode, block_in_file, &map_bh, 1))
                        goto confused;
                if (buffer_new(&map_bh))
                        unmap_underlying_metadata(map_bh.b_bdev,
@@ -576,20 +582,17 @@ page_is_mapped:
                 * written out to the file."
                 */
                unsigned offset = i_size & (PAGE_CACHE_SIZE - 1);
-               char *kaddr;
 
                if (page->index > end_index || !offset)
                        goto confused;
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+                               KM_USER0);
        }
 
        /*
         * This page will go to BIO.  Do we need to send this BIO off first?
         */
-       if (bio && *last_block_in_bio != blocks[0] - 1)
+       if (bio && mpd->last_block_in_bio != blocks[0] - 1)
                bio = mpage_bio_submit(WRITE, bio);
 
 alloc_new:
@@ -646,7 +649,7 @@ alloc_new:
                                        boundary_block, 1 << blkbits);
                }
        } else {
-               *last_block_in_bio = blocks[blocks_per_page - 1];
+               mpd->last_block_in_bio = blocks[blocks_per_page - 1];
        }
        goto out;
 
@@ -654,18 +657,19 @@ confused:
        if (bio)
                bio = mpage_bio_submit(WRITE, bio);
 
-       if (writepage_fn) {
-               *ret = (*writepage_fn)(page, wbc);
+       if (mpd->use_writepage) {
+               ret = mapping->a_ops->writepage(page, wbc);
        } else {
-               *ret = -EAGAIN;
+               ret = -EAGAIN;
                goto out;
        }
        /*
         * The caller has a ref on the inode, so *mapping is stable
         */
-       mapping_set_error(mapping, *ret);
+       mapping_set_error(mapping, ret);
 out:
-       return bio;
+       mpd->bio = bio;
+       return ret;
 }
 
 /**
@@ -688,120 +692,27 @@ out:
  * the call was made get new I/O started against them.  If wbc->sync_mode is
  * WB_SYNC_ALL then we were called for data integrity and we must wait for
  * existing IO to complete.
- *
- * If you fix this you should check generic_writepages() also!
  */
 int
 mpage_writepages(struct address_space *mapping,
                struct writeback_control *wbc, get_block_t get_block)
 {
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
-       struct bio *bio = NULL;
-       sector_t last_block_in_bio = 0;
-       int ret = 0;
-       int done = 0;
-       int (*writepage)(struct page *page, struct writeback_control *wbc);
-       struct pagevec pvec;
-       int nr_pages;
-       pgoff_t index;
-       pgoff_t end;            /* Inclusive */
-       int scanned = 0;
-       int range_whole = 0;
-
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
-       writepage = NULL;
-       if (get_block == NULL)
-               writepage = mapping->a_ops->writepage;
-
-       pagevec_init(&pvec, 0);
-       if (wbc->range_cyclic) {
-               index = mapping->writeback_index; /* Start from prev offset */
-               end = -1;
-       } else {
-               index = wbc->range_start >> PAGE_CACHE_SHIFT;
-               end = wbc->range_end >> PAGE_CACHE_SHIFT;
-               if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
-                       range_whole = 1;
-               scanned = 1;
+       int ret;
+
+       if (!get_block)
+               ret = generic_writepages(mapping, wbc);
+       else {
+               struct mpage_data mpd = {
+                       .bio = NULL,
+                       .last_block_in_bio = 0,
+                       .get_block = get_block,
+                       .use_writepage = 1,
+               };
+
+               ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd);
+               if (mpd.bio)
+                       mpage_bio_submit(WRITE, mpd.bio);
        }
-retry:
-       while (!done && (index <= end) &&
-                       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-                       PAGECACHE_TAG_DIRTY,
-                       min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
-               unsigned i;
-
-               scanned = 1;
-               for (i = 0; i < nr_pages; i++) {
-                       struct page *page = pvec.pages[i];
-
-                       /*
-                        * At this point we hold neither mapping->tree_lock nor
-                        * lock on the page itself: the page may be truncated or
-                        * invalidated (changing page->mapping to NULL), or even
-                        * swizzled back from swapper_space to tmpfs file
-                        * mapping
-                        */
-
-                       lock_page(page);
-
-                       if (unlikely(page->mapping != mapping)) {
-                               unlock_page(page);
-                               continue;
-                       }
-
-                       if (!wbc->range_cyclic && page->index > end) {
-                               done = 1;
-                               unlock_page(page);
-                               continue;
-                       }
-
-                       if (wbc->sync_mode != WB_SYNC_NONE)
-                               wait_on_page_writeback(page);
-
-                       if (PageWriteback(page) ||
-                                       !clear_page_dirty_for_io(page)) {
-                               unlock_page(page);
-                               continue;
-                       }
-
-                       if (writepage) {
-                               ret = (*writepage)(page, wbc);
-                               mapping_set_error(mapping, ret);
-                       } else {
-                               bio = __mpage_writepage(bio, page, get_block,
-                                               &last_block_in_bio, &ret, wbc,
-                                               page->mapping->a_ops->writepage);
-                       }
-                       if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
-                               unlock_page(page);
-                       if (ret || (--(wbc->nr_to_write) <= 0))
-                               done = 1;
-                       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-                               wbc->encountered_congestion = 1;
-                               done = 1;
-                       }
-               }
-               pagevec_release(&pvec);
-               cond_resched();
-       }
-       if (!scanned && !done) {
-               /*
-                * We hit the last page and there is more work to be done: wrap
-                * back to the start of the file
-                */
-               scanned = 1;
-               index = 0;
-               goto retry;
-       }
-       if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
-               mapping->writeback_index = index;
-       if (bio)
-               mpage_bio_submit(WRITE, bio);
        return ret;
 }
 EXPORT_SYMBOL(mpage_writepages);
@@ -809,15 +720,15 @@ EXPORT_SYMBOL(mpage_writepages);
 int mpage_writepage(struct page *page, get_block_t get_block,
        struct writeback_control *wbc)
 {
-       int ret = 0;
-       struct bio *bio;
-       sector_t last_block_in_bio = 0;
-
-       bio = __mpage_writepage(NULL, page, get_block,
-                       &last_block_in_bio, &ret, wbc, NULL);
-       if (bio)
-               mpage_bio_submit(WRITE, bio);
-
+       struct mpage_data mpd = {
+               .bio = NULL,
+               .last_block_in_bio = 0,
+               .get_block = get_block,
+               .use_writepage = 0,
+       };
+       int ret = __mpage_writepage(page, wbc, &mpd);
+       if (mpd.bio)
+               mpage_bio_submit(WRITE, mpd.bio);
        return ret;
 }
 EXPORT_SYMBOL(mpage_writepage);
index 856b2f5da51d74928108430bf0f6b96d14d8394f..b3780e3fc88ea18f2b7f5a2666702312f501b8b5 100644 (file)
@@ -1152,14 +1152,12 @@ static int fastcall do_path_lookup(int dfd, const char *name,
 
                fput_light(file, fput_needed);
        }
-       current->total_link_count = 0;
-       retval = link_path_walk(name, nd);
+
+       retval = path_walk(name, nd);
 out:
-       if (likely(retval == 0)) {
-               if (unlikely(!audit_dummy_context() && nd && nd->dentry &&
+       if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
                                nd->dentry->d_inode))
                audit_inode(name, nd->dentry->d_inode);
-       }
 out_fail:
        return retval;
 
index 625d8e5fb39ddfb7b27d15892e1986d6e080f0cd..3df4288165591e40d67f647cf13fb353d543cc0a 100644 (file)
@@ -38,7 +38,6 @@
 #include "delegation.h"
 #include "iostat.h"
 
-#define NFS_PARANOIA 1
 /* #define NFS_DEBUG_VERBOSE 1 */
 
 static int nfs_opendir(struct inode *, struct file *);
@@ -650,12 +649,15 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
  */
 static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
 {
+       unsigned long verf;
+
        if (IS_ROOT(dentry))
                return 1;
-       if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0
-                       || nfs_attribute_timeout(dir))
+       verf = (unsigned long)dentry->d_fsdata;
+       if (nfs_caches_unstable(dir)
+                       || verf != NFS_I(dir)->cache_change_attribute)
                return 0;
-       return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
+       return 1;
 }
 
 static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
@@ -665,8 +667,7 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
 
 static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
 {
-       if (time_after(verf, (unsigned long)dentry->d_fsdata))
-               nfs_set_verifier(dentry, verf);
+       nfs_set_verifier(dentry, verf);
 }
 
 /*
@@ -765,6 +766,10 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
        nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
        inode = dentry->d_inode;
 
+       /* Revalidate parent directory attribute cache */
+       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+               goto out_zap_parent;
+
        if (!inode) {
                if (nfs_neg_need_reval(dir, dentry, nd))
                        goto out_bad;
@@ -778,10 +783,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
                goto out_bad;
        }
 
-       /* Revalidate parent directory attribute cache */
-       if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
-               goto out_zap_parent;
-
        /* Force a full look up iff the parent directory has changed */
        if (nfs_check_verifier(dir, dentry)) {
                if (nfs_lookup_verify_inode(inode, nd))
@@ -1360,11 +1361,6 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
                atomic_read(&dentry->d_count));
        nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
 
-#ifdef NFS_PARANOIA
-if (!dentry->d_inode)
-printk("NFS: silly-renaming %s/%s, negative dentry??\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
        /*
         * We don't allow a dentry to be silly-renamed twice.
         */
@@ -1681,16 +1677,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        new_inode = NULL;
                        /* instantiate the replacement target */
                        d_instantiate(new_dentry, NULL);
-               } else if (atomic_read(&new_dentry->d_count) > 1) {
-               /* dentry still busy? */
-#ifdef NFS_PARANOIA
-                       printk("nfs_rename: target %s/%s busy, d_count=%d\n",
-                              new_dentry->d_parent->d_name.name,
-                              new_dentry->d_name.name,
-                              atomic_read(&new_dentry->d_count));
-#endif
+               } else if (atomic_read(&new_dentry->d_count) > 1)
+                       /* dentry still busy? */
                        goto out;
-               }
        } else
                drop_nlink(new_inode);
 
index 234778576f096359ade33cf319633b33cf168702..d1cbf0a0fbb2d457c92c964958e96dc2d9f56839 100644 (file)
@@ -41,7 +41,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
-#define NFS_PARANOIA 1
 
 /*
  * get an NFS2/NFS3 root dentry from the root filehandle
index 9d4a6b2d199672c67388262b808a67adef72e433..d11eb055265cbd80dbb5f280d0f9d118c8fe64d5 100644 (file)
@@ -272,7 +272,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
        set_current_state(TASK_UNINTERRUPTIBLE);
        mutex_unlock(&idmap->idmap_im_lock);
        schedule();
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&idmap->idmap_wq, &wq);
        mutex_lock(&idmap->idmap_im_lock);
 
@@ -333,7 +333,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
        set_current_state(TASK_UNINTERRUPTIBLE);
        mutex_unlock(&idmap->idmap_im_lock);
        schedule();
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&idmap->idmap_wq, &wq);
        mutex_lock(&idmap->idmap_im_lock);
 
index 1e9a915d1feae09507b4ddf29a3cd44dd968976d..2a3fd9573207ac81faa4b34ad22a269a8f11b36a 100644 (file)
@@ -48,7 +48,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_VFS
-#define NFS_PARANOIA 1
 
 static void nfs_invalidate_inode(struct inode *);
 static int nfs_update_inode(struct inode *, struct nfs_fattr *);
@@ -1075,10 +1074,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        /*
         * Big trouble! The inode has become a different object.
         */
-#ifdef NFS_PARANOIA
        printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
                        __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
-#endif
  out_err:
        /*
         * No need to worry about unhashing the dentry, as the
index abd9f8b48943997f5b30a4b500da26955013e863..cd3ca7b5d3dbfd0dda765505fe086f7288f37d32 100644 (file)
@@ -26,7 +26,6 @@
 #include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
-/* #define NFS_PARANOIA 1 */
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO                EIO
index b8c28f2380a5bcf2aacb48cb45294df65379d21d..938f37166788d97643c14b6112318d091b412398 100644 (file)
@@ -224,7 +224,8 @@ static int nfs4_stat_to_errno(int);
                                 encode_getattr_maxsz)
 #define NFS4_dec_setattr_sz     (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 3)
+                                op_decode_hdr_maxsz + 3 + \
+                                nfs4_fattr_maxsz)
 #define NFS4_enc_fsinfo_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_fsinfo_maxsz)
@@ -2079,9 +2080,11 @@ out:
 
 #define READ_BUF(nbytes)  do { \
        p = xdr_inline_decode(xdr, nbytes); \
-       if (!p) { \
-               printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \
-                               __FUNCTION__, __LINE__); \
+       if (unlikely(!p)) { \
+               printk(KERN_INFO "%s: prematurely hit end of receive" \
+                               " buffer\n", __FUNCTION__); \
+               printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
+                               __FUNCTION__, xdr->p, nbytes, xdr->end); \
                return -EIO; \
        } \
 } while (0)
index 388950118f59ae5b30c90b64dfc5d618aa7fd33f..e12054c86d0dd349dd0750e4dd92e44c6f2e9399 100644 (file)
@@ -20,8 +20,6 @@
 
 #include "internal.h"
 
-#define NFS_PARANOIA 1
-
 static struct kmem_cache *nfs_page_cachep;
 
 static inline struct nfs_page *
@@ -167,11 +165,6 @@ nfs_release_request(struct nfs_page *req)
        if (!atomic_dec_and_test(&req->wb_count))
                return;
 
-#ifdef NFS_PARANOIA
-       BUG_ON (!list_empty(&req->wb_list));
-       BUG_ON (NFS_WBACK_BUSY(req));
-#endif
-
        /* Release struct file or cached credential */
        nfs_clear_request(req);
        put_nfs_open_context(req->wb_context);
index ce341dc76d5ec6366d48c94844f4809a2560ab58..9b118ee2019371e151b69089061b67c3722b52c6 100644 (file)
@@ -11,4 +11,3 @@ nfsd-$(CONFIG_NFSD_V3)        += nfs3proc.o nfs3xdr.o
 nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
 nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
                           nfs4acl.o nfs4callback.o nfs4recover.o
-nfsd-objs              := $(nfsd-y)
index 6f24768272a1f05dcdd9657d3bb22755c06e9dce..79bd03b8bbf868e7638b1e85f90977b7727c88e6 100644 (file)
@@ -469,6 +469,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
        nd.dentry = NULL;
        exp.ex_path = NULL;
 
+       /* fs locations */
+       exp.ex_fslocs.locations = NULL;
+       exp.ex_fslocs.locations_count = 0;
+       exp.ex_fslocs.migrated = 0;
+
+       exp.ex_uuid = NULL;
+
        if (mesg[mlen-1] != '\n')
                return -EINVAL;
        mesg[mlen-1] = 0;
@@ -509,13 +516,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
        if (exp.h.expiry_time == 0)
                goto out;
 
-       /* fs locations */
-       exp.ex_fslocs.locations = NULL;
-       exp.ex_fslocs.locations_count = 0;
-       exp.ex_fslocs.migrated = 0;
-
-       exp.ex_uuid = NULL;
-
        /* flags */
        err = get_int(&mesg, &an_int);
        if (err == -ENOENT)
index 7f5bad0393b197915e203004b78dbb79d0eae4b9..eac82830bfd71ea3887c68081479cac4929ba618 100644 (file)
@@ -177,7 +177,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
        if (max_blocksize < resp->count)
                resp->count = max_blocksize;
 
-       svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
+       svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
        fh_copy(&resp->fh, &argp->fh);
        nfserr = nfsd_read(rqstp, &resp->fh, NULL,
index 7e4bb0af24d7d48d70a61feae9e5930efbde3e59..10f6e7dcf6336b48746cd6c16d7ed5c1d04cae28 100644 (file)
@@ -239,7 +239,7 @@ static __be32 *
 encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 {
        struct dentry *dentry = fhp->fh_dentry;
-       if (dentry && dentry->d_inode != NULL) {
+       if (dentry && dentry->d_inode) {
                int err;
                struct kstat stat;
 
@@ -300,9 +300,9 @@ int
 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_sattrargs *args)
 {
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = decode_sattr3(p, &args->attrs)))
+       if (!(p = decode_fh(p, &args->fh)))
                return 0;
+       p = decode_sattr3(p, &args->attrs);
 
        if ((args->check_guard = ntohl(*p++)) != 0) { 
                struct timespec time; 
@@ -343,9 +343,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
        int v,pn;
        u32 max_blocksize = svc_max_payload(rqstp);
 
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = xdr_decode_hyper(p, &args->offset)))
+       if (!(p = decode_fh(p, &args->fh)))
                return 0;
+       p = xdr_decode_hyper(p, &args->offset);
 
        len = args->count = ntohl(*p++);
 
@@ -369,28 +369,44 @@ int
 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_writeargs *args)
 {
-       unsigned int len, v, hdr;
+       unsigned int len, v, hdr, dlen;
        u32 max_blocksize = svc_max_payload(rqstp);
 
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = xdr_decode_hyper(p, &args->offset)))
+       if (!(p = decode_fh(p, &args->fh)))
                return 0;
+       p = xdr_decode_hyper(p, &args->offset);
 
        args->count = ntohl(*p++);
        args->stable = ntohl(*p++);
        len = args->len = ntohl(*p++);
+       /*
+        * The count must equal the amount of data passed.
+        */
+       if (args->count != args->len)
+               return 0;
 
+       /*
+        * Check to make sure that we got the right number of
+        * bytes.
+        */
        hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
-       if (rqstp->rq_arg.len < hdr ||
-           rqstp->rq_arg.len - hdr < len)
+       dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+               - hdr;
+       /*
+        * Round the length of the data which was specified up to
+        * the next multiple of XDR units and then compare that
+        * against the length which was actually received.
+        */
+       if (dlen != XDR_QUADLEN(len)*4)
                return 0;
 
+       if (args->count > max_blocksize) {
+               args->count = max_blocksize;
+               len = args->len = max_blocksize;
+       }
        rqstp->rq_vec[0].iov_base = (void*)p;
        rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
-
-       if (len > max_blocksize)
-               len = max_blocksize;
-       v=  0;
+       v = 0;
        while (len > rqstp->rq_vec[v].iov_len) {
                len -= rqstp->rq_vec[v].iov_len;
                v++;
@@ -398,9 +414,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
                rqstp->rq_vec[v].iov_len = PAGE_SIZE;
        }
        rqstp->rq_vec[v].iov_len = len;
-       args->vlen = v+1;
-
-       return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
+       args->vlen = v + 1;
+       return 1;
 }
 
 int
@@ -414,8 +429,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
        switch (args->createmode = ntohl(*p++)) {
        case NFS3_CREATE_UNCHECKED:
        case NFS3_CREATE_GUARDED:
-               if (!(p = decode_sattr3(p, &args->attrs)))
-                       return 0;
+               p = decode_sattr3(p, &args->attrs);
                break;
        case NFS3_CREATE_EXCLUSIVE:
                args->verf = p;
@@ -431,10 +445,10 @@ int
 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_createargs *args)
 {
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = decode_filename(p, &args->name, &args->len))
-        || !(p = decode_sattr3(p, &args->attrs)))
+       if (!(p = decode_fh(p, &args->fh)) ||
+           !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
+       p = decode_sattr3(p, &args->attrs);
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -448,11 +462,12 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
        char *old, *new;
        struct kvec *vec;
 
-       if (!(p = decode_fh(p, &args->ffh))
-        || !(p = decode_filename(p, &args->fname, &args->flen))
-        || !(p = decode_sattr3(p, &args->attrs))
+       if (!(p = decode_fh(p, &args->ffh)) ||
+           !(p = decode_filename(p, &args->fname, &args->flen))
                )
                return 0;
+       p = decode_sattr3(p, &args->attrs);
+
        /* now decode the pathname, which might be larger than the first page.
         * As we have to check for nul's anyway, we copy it into a new page
         * This page appears in the rq_res.pages list, but as pages_len is always
@@ -502,10 +517,8 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
        args->ftype = ntohl(*p++);
 
        if (args->ftype == NF3BLK  || args->ftype == NF3CHR
-        || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
-               if (!(p = decode_sattr3(p, &args->attrs)))
-                       return 0;
-       }
+        || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
+               p = decode_sattr3(p, &args->attrs);
 
        if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
                args->major = ntohl(*p++);
index 673a53c014a3f4d3ad81c7a7bb9b22730b9b6bf9..cc3b7badd4869299f6c86dd14342f42177768acb 100644 (file)
@@ -137,7 +137,6 @@ struct ace_container {
 static short ace2type(struct nfs4_ace *);
 static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
                                unsigned int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
 
 struct nfs4_acl *
 nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
@@ -785,21 +784,6 @@ nfs4_acl_new(int n)
        return acl;
 }
 
-void
-nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
-               int whotype, uid_t who)
-{
-       struct nfs4_ace *ace = acl->aces + acl->naces;
-
-       ace->type = type;
-       ace->flag = flag;
-       ace->access_mask = access_mask;
-       ace->whotype = whotype;
-       ace->who = who;
-
-       acl->naces++;
-}
-
 static struct {
        char *string;
        int   stringlen;
@@ -851,6 +835,5 @@ nfs4_acl_write_who(int who, char *p)
 }
 
 EXPORT_SYMBOL(nfs4_acl_new);
-EXPORT_SYMBOL(nfs4_acl_add_ace);
 EXPORT_SYMBOL(nfs4_acl_get_whotype);
 EXPORT_SYMBOL(nfs4_acl_write_who);
index 678f3be88ac04e7cf319e1819835f8a394b53291..3cc8ce422ab1a245a746cc15401be505031f17c2 100644 (file)
@@ -1326,8 +1326,6 @@ do_recall(void *__dp)
 {
        struct nfs4_delegation *dp = __dp;
 
-       daemonize("nfsv4-recall");
-
        nfsd4_cb_recall(dp);
        return 0;
 }
index 739dd3c5c3b2bc0871587de2d07736fd902c53b9..6ca2d24fc216d6cf5ccf6f293955b0ad27accb73 100644 (file)
@@ -323,7 +323,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
         *
         */
 
-       u8 version = 1;
+       u8 version;
        u8 fsid_type = 0;
        struct inode * inode = dentry->d_inode;
        struct dentry *parent = dentry->d_parent;
@@ -341,15 +341,59 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
         * the reference filehandle (if it is in the same export)
         * or the export options.
         */
+ retry:
+       version = 1;
        if (ref_fh && ref_fh->fh_export == exp) {
                version = ref_fh->fh_handle.fh_version;
-               if (version == 0xca)
+               fsid_type = ref_fh->fh_handle.fh_fsid_type;
+
+               if (ref_fh == fhp)
+                       fh_put(ref_fh);
+               ref_fh = NULL;
+
+               switch (version) {
+               case 0xca:
                        fsid_type = FSID_DEV;
-               else
-                       fsid_type = ref_fh->fh_handle.fh_fsid_type;
-               /* We know this version/type works for this export
-                * so there is no need for further checks.
+                       break;
+               case 1:
+                       break;
+               default:
+                       goto retry;
+               }
+
+               /* Need to check that this type works for this
+                * export point.  As the fsid -> filesystem mapping
+                * was guided by user-space, there is no guarantee
+                * that the filesystem actually supports that fsid
+                * type. If it doesn't we loop around again without
+                * ref_fh set.
                 */
+               switch(fsid_type) {
+               case FSID_DEV:
+                       if (!old_valid_dev(ex_dev))
+                               goto retry;
+                       /* FALL THROUGH */
+               case FSID_MAJOR_MINOR:
+               case FSID_ENCODE_DEV:
+                       if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags
+                             & FS_REQUIRES_DEV))
+                               goto retry;
+                       break;
+               case FSID_NUM:
+                       if (! (exp->ex_flags & NFSEXP_FSID))
+                               goto retry;
+                       break;
+               case FSID_UUID8:
+               case FSID_UUID16:
+                       if (!root_export)
+                               goto retry;
+                       /* fall through */
+               case FSID_UUID4_INUM:
+               case FSID_UUID16_INUM:
+                       if (exp->ex_uuid == NULL)
+                               goto retry;
+                       break;
+               }
        } else if (exp->ex_uuid) {
                if (fhp->fh_maxsize >= 64) {
                        if (root_export)
index 5cc2eec981b8763012794ef1f4da0ab5cc50df3d..b2c7147aa921414c9243012a513861dbea3c8133 100644 (file)
@@ -155,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
                                argp->count);
                argp->count = NFSSVC_MAXBLKSIZE_V2;
        }
-       svc_reserve(rqstp, (19<<2) + argp->count + 4);
+       svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
 
        resp->count = argp->count;
        nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
index 0c24b9e24fe866683a357f1a9e8b08bcb2fbe30c..cb3e7fadb772127975898e14a43c6bd3dd4c4d92 100644 (file)
@@ -231,9 +231,10 @@ int
 nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd_sattrargs *args)
 {
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = decode_sattr(p, &args->attrs)))
+       p = decode_fh(p, &args->fh);
+       if (!p)
                return 0;
+       p = decode_sattr(p, &args->attrs);
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -284,8 +285,9 @@ int
 nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd_writeargs *args)
 {
-       unsigned int len;
+       unsigned int len, hdr, dlen;
        int v;
+
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
 
@@ -293,11 +295,30 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
        args->offset = ntohl(*p++);     /* offset */
        p++;                            /* totalcount */
        len = args->len = ntohl(*p++);
-       rqstp->rq_vec[0].iov_base = (void*)p;
-       rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
-                               (((void*)p) - rqstp->rq_arg.head[0].iov_base);
+       /*
+        * The protocol specifies a maximum of 8192 bytes.
+        */
        if (len > NFSSVC_MAXBLKSIZE_V2)
-               len = NFSSVC_MAXBLKSIZE_V2;
+               return 0;
+
+       /*
+        * Check to make sure that we got the right number of
+        * bytes.
+        */
+       hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+       dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+               - hdr;
+
+       /*
+        * Round the length of the data which was specified up to
+        * the next multiple of XDR units and then compare that
+        * against the length which was actually received.
+        */
+       if (dlen != XDR_QUADLEN(len)*4)
+               return 0;
+
+       rqstp->rq_vec[0].iov_base = (void*)p;
+       rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
        v = 0;
        while (len > rqstp->rq_vec[v].iov_len) {
                len -= rqstp->rq_vec[v].iov_len;
@@ -306,18 +327,18 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
                rqstp->rq_vec[v].iov_len = PAGE_SIZE;
        }
        rqstp->rq_vec[v].iov_len = len;
-       args->vlen = v+1;
-       return rqstp->rq_vec[0].iov_len > 0;
+       args->vlen = v + 1;
+       return 1;
 }
 
 int
 nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd_createargs *args)
 {
-       if (!(p = decode_fh(p, &args->fh))
-        || !(p = decode_filename(p, &args->name, &args->len))
-        || !(p = decode_sattr(p, &args->attrs)))
+       if (   !(p = decode_fh(p, &args->fh))
+           || !(p = decode_filename(p, &args->name, &args->len)))
                return 0;
+       p = decode_sattr(p, &args->attrs);
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -361,11 +382,11 @@ int
 nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd_symlinkargs *args)
 {
-       if (!(p = decode_fh(p, &args->ffh))
-        || !(p = decode_filename(p, &args->fname, &args->flen))
-        || !(p = decode_pathname(p, &args->tname, &args->tlen))
-        || !(p = decode_sattr(p, &args->attrs)))
+       if (   !(p = decode_fh(p, &args->ffh))
+           || !(p = decode_filename(p, &args->fname, &args->flen))
+           || !(p = decode_pathname(p, &args->tname, &args->tlen)))
                return 0;
+       p = decode_sattr(p, &args->attrs);
 
        return xdr_argsize_check(rqstp, p);
 }
index 2e975c0a35e1c24179e6225e483bcb88f188e033..a93620ce4aca80e7444ca01cffd24ee45b16b359 100644 (file)
@@ -144,7 +144,8 @@ static struct kobj_type mlog_ktype = {
 };
 
 static struct kset mlog_kset = {
-       .kobj   = {.name = "logmask", .ktype = &mlog_ktype},
+       .kobj  = {.name = "logmask"},
+       .ktype = &mlog_ktype
 };
 
 int mlog_sys_init(struct kset *o2cb_subsys)
@@ -157,7 +158,7 @@ int mlog_sys_init(struct kset *o2cb_subsys)
        }
        mlog_attr_ptrs[i] = NULL;
 
-       kobj_set_kset_s(&mlog_kset, o2cb_subsys);
+       kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
        return kset_register(&mlog_kset);
 }
 
index ca9981c4a658247bb6e29aaaaad8fa88f4d99dd8..0d515d1619747b00e724471a407f2a6cf6ea51d7 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -210,6 +210,9 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
                newattrs.ia_valid |= ATTR_FILE;
        }
 
+       /* Remove suid/sgid on truncate too */
+       newattrs.ia_valid |= should_remove_suid(dentry);
+
        mutex_lock(&dentry->d_inode->i_mutex);
        err = notify_change(dentry, &newattrs);
        mutex_unlock(&dentry->d_inode->i_mutex);
index 01207042048b993201b0799b82c6a198ab73001f..7638a1c42a7dfa462a910525c9c21470a87e1284 100644 (file)
@@ -239,7 +239,7 @@ config EFI_PARTITION
 
 config SYSV68_PARTITION
        bool "SYSV68 partition table support" if PARTITION_ADVANCED
-       default y if M68K
+       default y if VME
        help
          Say Y here if you would like to be able to read the hard disk
          partition table format used by Motorola Delta machines (using
index 1bea610078b35c34808245cc2214947bd369d672..e7b07006bc4173c5489c3bb1532f01e0473e4bf1 100644 (file)
@@ -152,7 +152,7 @@ last_lba(struct block_device *bdev)
 }
 
 static inline int
-pmbr_part_valid(struct partition *part, u64 lastlba)
+pmbr_part_valid(struct partition *part)
 {
         if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
             le32_to_cpu(part->start_sect) == 1UL)
@@ -163,7 +163,6 @@ pmbr_part_valid(struct partition *part, u64 lastlba)
 /**
  * is_pmbr_valid(): test Protective MBR for validity
  * @mbr: pointer to a legacy mbr structure
- * @lastlba: last_lba for the whole device
  *
  * Description: Returns 1 if PMBR is valid, 0 otherwise.
  * Validity depends on two things:
@@ -171,13 +170,13 @@ pmbr_part_valid(struct partition *part, u64 lastlba)
  *  2) One partition of type 0xEE is found
  */
 static int
-is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
+is_pmbr_valid(legacy_mbr *mbr)
 {
        int i;
        if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
                 return 0;
        for (i = 0; i < 4; i++)
-               if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
+               if (pmbr_part_valid(&mbr->partition_record[i]))
                         return 1;
        return 0;
 }
@@ -516,7 +515,7 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
        int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
        gpt_header *pgpt = NULL, *agpt = NULL;
        gpt_entry *pptes = NULL, *aptes = NULL;
-       legacy_mbr *legacymbr = NULL;
+       legacy_mbr *legacymbr;
        u64 lastlba;
        if (!bdev || !gpt || !ptes)
                return 0;
@@ -528,9 +527,8 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
                 if (legacymbr) {
                         read_lba(bdev, 0, (u8 *) legacymbr,
                                  sizeof (*legacymbr));
-                        good_pmbr = is_pmbr_valid(legacymbr, lastlba);
+                        good_pmbr = is_pmbr_valid(legacymbr);
                         kfree(legacymbr);
-                        legacymbr=NULL;
                 }
                 if (!good_pmbr)
                         goto fail;
index 3c41149dea8875ba1431d25acb969ec75f197770..a5fa1fdafc4e6df68df2cc87626f0d8d85bd95a6 100644 (file)
@@ -708,6 +708,7 @@ static const struct file_operations proc_oom_adjust_operations = {
        .write          = oom_adjust_write,
 };
 
+#ifdef CONFIG_MMU
 static ssize_t clear_refs_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
@@ -741,6 +742,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
 static struct file_operations proc_clear_refs_operations = {
        .write          = clear_refs_write,
 };
+#endif
 
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
index ab45db529c80b982c4b7b918c003e0a1ed9ad2b1..9e451a68580f6eef3ab4ba8c6eb729ae843d071b 100644 (file)
@@ -1059,20 +1059,12 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
           maping blocks, since there is none, so we just zero out remaining
           parts of first and last pages in write area (if needed) */
        if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) {
-               if (from != 0) {        /* First page needs to be partially zeroed */
-                       char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
-                       memset(kaddr, 0, from);
-                       kunmap_atomic(kaddr, KM_USER0);
-                       flush_dcache_page(prepared_pages[0]);
-               }
-               if (to != PAGE_CACHE_SIZE) {    /* Last page needs to be partially zeroed */
-                       char *kaddr =
-                           kmap_atomic(prepared_pages[num_pages - 1],
-                                       KM_USER0);
-                       memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
-                       kunmap_atomic(kaddr, KM_USER0);
-                       flush_dcache_page(prepared_pages[num_pages - 1]);
-               }
+               if (from != 0)          /* First page needs to be partially zeroed */
+                       zero_user_page(prepared_pages[0], 0, from, KM_USER0);
+
+               if (to != PAGE_CACHE_SIZE)      /* Last page needs to be partially zeroed */
+                       zero_user_page(prepared_pages[num_pages-1], to,
+                                       PAGE_CACHE_SIZE - to, KM_USER0);
 
                /* Since all blocks are new - use already calculated value */
                return blocks;
@@ -1199,13 +1191,9 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
                                        ll_rw_block(READ, 1, &bh);
                                        *wait_bh++ = bh;
                                } else {        /* Not mapped, zero it */
-                                       char *kaddr =
-                                           kmap_atomic(prepared_pages[0],
-                                                       KM_USER0);
-                                       memset(kaddr + block_start, 0,
-                                              from - block_start);
-                                       kunmap_atomic(kaddr, KM_USER0);
-                                       flush_dcache_page(prepared_pages[0]);
+                                       zero_user_page(prepared_pages[0],
+                                                      block_start,
+                                                      from - block_start, KM_USER0);
                                        set_buffer_uptodate(bh);
                                }
                        }
@@ -1237,13 +1225,8 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
                                        ll_rw_block(READ, 1, &bh);
                                        *wait_bh++ = bh;
                                } else {        /* Not mapped, zero it */
-                                       char *kaddr =
-                                           kmap_atomic(prepared_pages
-                                                       [num_pages - 1],
-                                                       KM_USER0);
-                                       memset(kaddr + to, 0, block_end - to);
-                                       kunmap_atomic(kaddr, KM_USER0);
-                                       flush_dcache_page(prepared_pages[num_pages - 1]);
+                                       zero_user_page(prepared_pages[num_pages-1],
+                                                       to, block_end - to, KM_USER0);
                                        set_buffer_uptodate(bh);
                                }
                        }
index 9fcbfe3169776516162b7a68bfbf845975adb639..1272d11399fb26509f60eef52561b12002a8ecee 100644 (file)
@@ -2148,13 +2148,8 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
                length = offset & (blocksize - 1);
                /* if we are not on a block boundary */
                if (length) {
-                       char *kaddr;
-
                        length = blocksize - length;
-                       kaddr = kmap_atomic(page, KM_USER0);
-                       memset(kaddr + offset, 0, length);
-                       flush_dcache_page(page);
-                       kunmap_atomic(kaddr, KM_USER0);
+                       zero_user_page(page, offset, length, KM_USER0);
                        if (buffer_mapped(bh) && bh->b_blocknr != 0) {
                                mark_buffer_dirty(bh);
                        }
@@ -2370,7 +2365,6 @@ static int reiserfs_write_full_page(struct page *page,
         ** last byte in the file
         */
        if (page->index >= end_index) {
-               char *kaddr;
                unsigned last_offset;
 
                last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
@@ -2379,10 +2373,7 @@ static int reiserfs_write_full_page(struct page *page,
                        unlock_page(page);
                        return 0;
                }
-               kaddr = kmap_atomic(page, KM_USER0);
-               memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset);
-               flush_dcache_page(page);
-               kunmap_atomic(kaddr, KM_USER0);
+               zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0);
        }
        bh = head;
        block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
index e073fd86cf603c35a12de2d8a2a7c5949c404306..f25086aeef5f450afa6c4aa604787cd168ae299f 100644 (file)
@@ -1110,7 +1110,7 @@ static int flush_commit_list(struct super_block *s,
        if (!barrier) {
                /* If there was a write error in the journal - we can't commit
                 * this transaction - it will be invalid and, if successful,
-                * will just end up propogating the write error out to
+                * will just end up propagating the write error out to
                 * the file system. */
                if (likely(!retval && !reiserfs_is_journal_aborted (journal))) {
                        if (buffer_dirty(jl->j_commit_bh))
@@ -1125,7 +1125,7 @@ static int flush_commit_list(struct super_block *s,
 
        /* If there was a write error in the journal - we can't commit this
         * transaction - it will be invalid and, if successful, will just end
-        * up propogating the write error out to the filesystem. */
+        * up propagating the write error out to the filesystem. */
        if (unlikely(!buffer_uptodate(jl->j_commit_bh))) {
 #ifdef CONFIG_REISERFS_CHECK
                reiserfs_warning(s, "journal-615: buffer write failed");
index d86224154decc41c56fa395e71f74dfb6e405e73..a974082b0824a8a9935abd42c3471b50a9755410 100644 (file)
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(poll_initwait);
 
 static void free_poll_entry(struct poll_table_entry *entry)
 {
-       remove_wait_queue(entry->wait_address,&entry->wait);
+       remove_wait_queue(entry->wait_address, &entry->wait);
        fput(entry->filp);
 }
 
@@ -128,7 +128,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
        entry->filp = filp;
        entry->wait_address = wait_address;
        init_waitqueue_entry(&entry->wait, current);
-       add_wait_queue(wait_address,&entry->wait);
+       add_wait_queue(wait_address, &entry->wait);
 }
 
 #define FDS_IN(fds, n)         (fds->in + n)
diff --git a/fs/signalfd.c b/fs/signalfd.c
new file mode 100644 (file)
index 0000000..7cfeab4
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ *  fs/signalfd.c
+ *
+ *  Copyright (C) 2003  Linus Torvalds
+ *
+ *  Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org>
+ *      Changed ->read() to return a siginfo strcture instead of signal number.
+ *      Fixed locking in ->poll().
+ *      Added sighand-detach notification.
+ *      Added fd re-use in sys_signalfd() syscall.
+ *      Now using anonymous inode source.
+ *      Thanks to Oleg Nesterov for useful code review and suggestions.
+ *      More comments and suggestions from Arnd Bergmann.
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/list.h>
+#include <linux/anon_inodes.h>
+#include <linux/signalfd.h>
+
+struct signalfd_ctx {
+       struct list_head lnk;
+       wait_queue_head_t wqh;
+       sigset_t sigmask;
+       struct task_struct *tsk;
+};
+
+struct signalfd_lockctx {
+       struct task_struct *tsk;
+       unsigned long flags;
+};
+
+/*
+ * Tries to acquire the sighand lock. We do not increment the sighand
+ * use count, and we do not even pin the task struct, so we need to
+ * do it inside an RCU read lock, and we must be prepared for the
+ * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand
+ * being detached. We return 0 if the sighand has been detached, or
+ * 1 if we were able to pin the sighand lock.
+ */
+static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
+{
+       struct sighand_struct *sighand = NULL;
+
+       rcu_read_lock();
+       lk->tsk = rcu_dereference(ctx->tsk);
+       if (likely(lk->tsk != NULL))
+               sighand = lock_task_sighand(lk->tsk, &lk->flags);
+       rcu_read_unlock();
+
+       if (sighand && !ctx->tsk) {
+               unlock_task_sighand(lk->tsk, &lk->flags);
+               sighand = NULL;
+       }
+
+       return sighand != NULL;
+}
+
+static void signalfd_unlock(struct signalfd_lockctx *lk)
+{
+       unlock_task_sighand(lk->tsk, &lk->flags);
+}
+
+/*
+ * This must be called with the sighand lock held.
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig)
+{
+       struct sighand_struct *sighand = tsk->sighand;
+       struct signalfd_ctx *ctx, *tmp;
+
+       BUG_ON(!sig);
+       list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) {
+               /*
+                * We use a negative signal value as a way to broadcast that the
+                * sighand has been orphaned, so that we can notify all the
+                * listeners about this. Remember the ctx->sigmask is inverted,
+                * so if the user is interested in a signal, that corresponding
+                * bit will be zero.
+                */
+               if (sig < 0) {
+                       if (ctx->tsk == tsk) {
+                               ctx->tsk = NULL;
+                               list_del_init(&ctx->lnk);
+                               wake_up(&ctx->wqh);
+                       }
+               } else {
+                       if (!sigismember(&ctx->sigmask, sig))
+                               wake_up(&ctx->wqh);
+               }
+       }
+}
+
+static void signalfd_cleanup(struct signalfd_ctx *ctx)
+{
+       struct signalfd_lockctx lk;
+
+       /*
+        * This is tricky. If the sighand is gone, we do not need to remove
+        * context from the list, the list itself won't be there anymore.
+        */
+       if (signalfd_lock(ctx, &lk)) {
+               list_del(&ctx->lnk);
+               signalfd_unlock(&lk);
+       }
+       kfree(ctx);
+}
+
+static int signalfd_release(struct inode *inode, struct file *file)
+{
+       signalfd_cleanup(file->private_data);
+       return 0;
+}
+
+static unsigned int signalfd_poll(struct file *file, poll_table *wait)
+{
+       struct signalfd_ctx *ctx = file->private_data;
+       unsigned int events = 0;
+       struct signalfd_lockctx lk;
+
+       poll_wait(file, &ctx->wqh, wait);
+
+       /*
+        * Let the caller get a POLLIN in this case, ala socket recv() when
+        * the peer disconnects.
+        */
+       if (signalfd_lock(ctx, &lk)) {
+               if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 ||
+                   next_signal(&lk.tsk->signal->shared_pending,
+                               &ctx->sigmask) > 0)
+                       events |= POLLIN;
+               signalfd_unlock(&lk);
+       } else
+               events |= POLLIN;
+
+       return events;
+}
+
+/*
+ * Copied from copy_siginfo_to_user() in kernel/signal.c
+ */
+static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
+                            siginfo_t const *kinfo)
+{
+       long err;
+
+       BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
+
+       /*
+        * Unused memebers should be zero ...
+        */
+       err = __clear_user(uinfo, sizeof(*uinfo));
+
+       /*
+        * If you change siginfo_t structure, please be sure
+        * this code is fixed accordingly.
+        */
+       err |= __put_user(kinfo->si_signo, &uinfo->signo);
+       err |= __put_user(kinfo->si_errno, &uinfo->err);
+       err |= __put_user((short)kinfo->si_code, &uinfo->code);
+       switch (kinfo->si_code & __SI_MASK) {
+       case __SI_KILL:
+               err |= __put_user(kinfo->si_pid, &uinfo->pid);
+               err |= __put_user(kinfo->si_uid, &uinfo->uid);
+               break;
+       case __SI_TIMER:
+                err |= __put_user(kinfo->si_tid, &uinfo->tid);
+                err |= __put_user(kinfo->si_overrun, &uinfo->overrun);
+                err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+               break;
+       case __SI_POLL:
+               err |= __put_user(kinfo->si_band, &uinfo->band);
+               err |= __put_user(kinfo->si_fd, &uinfo->fd);
+               break;
+       case __SI_FAULT:
+               err |= __put_user((long)kinfo->si_addr, &uinfo->addr);
+#ifdef __ARCH_SI_TRAPNO
+               err |= __put_user(kinfo->si_trapno, &uinfo->trapno);
+#endif
+               break;
+       case __SI_CHLD:
+               err |= __put_user(kinfo->si_pid, &uinfo->pid);
+               err |= __put_user(kinfo->si_uid, &uinfo->uid);
+               err |= __put_user(kinfo->si_status, &uinfo->status);
+               err |= __put_user(kinfo->si_utime, &uinfo->utime);
+               err |= __put_user(kinfo->si_stime, &uinfo->stime);
+               break;
+       case __SI_RT: /* This is not generated by the kernel as of now. */
+       case __SI_MESGQ: /* But this is */
+               err |= __put_user(kinfo->si_pid, &uinfo->pid);
+               err |= __put_user(kinfo->si_uid, &uinfo->uid);
+               err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+               break;
+       default: /* this is just in case for now ... */
+               err |= __put_user(kinfo->si_pid, &uinfo->pid);
+               err |= __put_user(kinfo->si_uid, &uinfo->uid);
+               break;
+       }
+
+       return err ? -EFAULT: sizeof(*uinfo);
+}
+
+/*
+ * Returns either the size of a "struct signalfd_siginfo", or zero if the
+ * sighand we are attached to, has been orphaned. The "count" parameter
+ * must be at least the size of a "struct signalfd_siginfo".
+ */
+static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       struct signalfd_ctx *ctx = file->private_data;
+       ssize_t res = 0;
+       int locked, signo;
+       siginfo_t info;
+       struct signalfd_lockctx lk;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count < sizeof(struct signalfd_siginfo))
+               return -EINVAL;
+       locked = signalfd_lock(ctx, &lk);
+       if (!locked)
+               return 0;
+       res = -EAGAIN;
+       signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+       if (signo == 0 && !(file->f_flags & O_NONBLOCK)) {
+               add_wait_queue(&ctx->wqh, &wait);
+               for (;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+                       if (signo != 0)
+                               break;
+                       if (signal_pending(current)) {
+                               res = -ERESTARTSYS;
+                               break;
+                       }
+                       signalfd_unlock(&lk);
+                       schedule();
+                       locked = signalfd_lock(ctx, &lk);
+                       if (unlikely(!locked)) {
+                               /*
+                                * Let the caller read zero byte, ala socket
+                                * recv() when the peer disconnect. This test
+                                * must be done before doing a dequeue_signal(),
+                                * because if the sighand has been orphaned,
+                                * the dequeue_signal() call is going to crash.
+                                */
+                               res = 0;
+                               break;
+                       }
+               }
+               remove_wait_queue(&ctx->wqh, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+       if (likely(locked))
+               signalfd_unlock(&lk);
+       if (likely(signo))
+               res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf,
+                                       &info);
+
+       return res;
+}
+
+static const struct file_operations signalfd_fops = {
+       .release        = signalfd_release,
+       .poll           = signalfd_poll,
+       .read           = signalfd_read,
+};
+
+/*
+ * Create a file descriptor that is associated with our signal
+ * state. We can pass it around to others if we want to, but
+ * it will always be _our_ signal state.
+ */
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
+{
+       int error;
+       sigset_t sigmask;
+       struct signalfd_ctx *ctx;
+       struct sighand_struct *sighand;
+       struct file *file;
+       struct inode *inode;
+       struct signalfd_lockctx lk;
+
+       if (sizemask != sizeof(sigset_t) ||
+           copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
+               return error = -EINVAL;
+       sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+       signotset(&sigmask);
+
+       if (ufd == -1) {
+               ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               init_waitqueue_head(&ctx->wqh);
+               ctx->sigmask = sigmask;
+               ctx->tsk = current;
+
+               sighand = current->sighand;
+               /*
+                * Add this fd to the list of signal listeners.
+                */
+               spin_lock_irq(&sighand->siglock);
+               list_add_tail(&ctx->lnk, &sighand->signalfd_list);
+               spin_unlock_irq(&sighand->siglock);
+
+               /*
+                * When we call this, the initialization must be complete, since
+                * anon_inode_getfd() will install the fd.
+                */
+               error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
+                                        &signalfd_fops, ctx);
+               if (error)
+                       goto err_fdalloc;
+       } else {
+               file = fget(ufd);
+               if (!file)
+                       return -EBADF;
+               ctx = file->private_data;
+               if (file->f_op != &signalfd_fops) {
+                       fput(file);
+                       return -EINVAL;
+               }
+               /*
+                * We need to be prepared of the fact that the sighand this fd
+                * is attached to, has been detched. In that case signalfd_lock()
+                * will return 0, and we'll just skip setting the new mask.
+                */
+               if (signalfd_lock(ctx, &lk)) {
+                       ctx->sigmask = sigmask;
+                       signalfd_unlock(&lk);
+               }
+               wake_up(&ctx->wqh);
+               fput(file);
+       }
+
+       return ufd;
+
+err_fdalloc:
+       signalfd_cleanup(ctx);
+       return error;
+}
+
index 0e637adc2b872c31d43aecae810c767c31b79e56..b502c7197ec063777d90af4c49f038e95acd0c9e 100644 (file)
@@ -111,36 +111,6 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
        return ret;
 }
 
-
-/**
- *     flush_read_buffer - push buffer to userspace.
- *     @buffer:        data buffer for file.
- *     @buf:           user-passed buffer.
- *     @count:         number of bytes requested.
- *     @ppos:          file position.
- *
- *     Copy the buffer we filled in fill_read_buffer() to userspace.
- *     This is done at the reader's leisure, copying and advancing 
- *     the amount they specify each time.
- *     This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf,
-                            size_t count, loff_t * ppos)
-{
-       int error;
-
-       if (*ppos > buffer->count)
-               return 0;
-
-       if (count > (buffer->count - *ppos))
-               count = buffer->count - *ppos;
-
-       error = copy_to_user(buf,buffer->page + *ppos,count);
-       if (!error)
-               *ppos += count;
-       return error ? -EFAULT : count;
-}
-
 /**
  *     sysfs_read_file - read an attribute. 
  *     @file:  file pointer.
@@ -177,7 +147,8 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        }
        pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
                 __FUNCTION__, count, *ppos, buffer->page);
-       retval = flush_read_buffer(buffer,buf,count,ppos);
+       retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+                                        buffer->count);
 out:
        up(&buffer->sem);
        return retval;
diff --git a/fs/timerfd.c b/fs/timerfd.c
new file mode 100644 (file)
index 0000000..e329e37
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ *
+ *  Thanks to Thomas Gleixner for code reviews and useful comments.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/anon_inodes.h>
+#include <linux/timerfd.h>
+
+struct timerfd_ctx {
+       struct hrtimer tmr;
+       ktime_t tintv;
+       spinlock_t lock;
+       wait_queue_head_t wqh;
+       int expired;
+};
+
+/*
+ * This gets called when the timer event triggers. We set the "expired"
+ * flag, but we do not re-arm the timer (in case it's necessary,
+ * tintv.tv64 != 0) until the timer is read.
+ */
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
+{
+       struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->lock, flags);
+       ctx->expired = 1;
+       wake_up_locked(&ctx->wqh);
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       return HRTIMER_NORESTART;
+}
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+                         const struct itimerspec *ktmr)
+{
+       enum hrtimer_mode htmode;
+       ktime_t texp;
+
+       htmode = (flags & TFD_TIMER_ABSTIME) ?
+               HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
+
+       texp = timespec_to_ktime(ktmr->it_value);
+       ctx->expired = 0;
+       ctx->tintv = timespec_to_ktime(ktmr->it_interval);
+       hrtimer_init(&ctx->tmr, clockid, htmode);
+       ctx->tmr.expires = texp;
+       ctx->tmr.function = timerfd_tmrproc;
+       if (texp.tv64 != 0)
+               hrtimer_start(&ctx->tmr, texp, htmode);
+}
+
+static int timerfd_release(struct inode *inode, struct file *file)
+{
+       struct timerfd_ctx *ctx = file->private_data;
+
+       hrtimer_cancel(&ctx->tmr);
+       kfree(ctx);
+       return 0;
+}
+
+static unsigned int timerfd_poll(struct file *file, poll_table *wait)
+{
+       struct timerfd_ctx *ctx = file->private_data;
+       unsigned int events = 0;
+       unsigned long flags;
+
+       poll_wait(file, &ctx->wqh, wait);
+
+       spin_lock_irqsave(&ctx->lock, flags);
+       if (ctx->expired)
+               events |= POLLIN;
+       spin_unlock_irqrestore(&ctx->lock, flags);
+
+       return events;
+}
+
+static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       struct timerfd_ctx *ctx = file->private_data;
+       ssize_t res;
+       u32 ticks = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count < sizeof(ticks))
+               return -EINVAL;
+       spin_lock_irq(&ctx->lock);
+       res = -EAGAIN;
+       if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
+               __add_wait_queue(&ctx->wqh, &wait);
+               for (res = 0;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (ctx->expired) {
+                               res = 0;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               res = -ERESTARTSYS;
+                               break;
+                       }
+                       spin_unlock_irq(&ctx->lock);
+                       schedule();
+                       spin_lock_irq(&ctx->lock);
+               }
+               __remove_wait_queue(&ctx->wqh, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+       if (ctx->expired) {
+               ctx->expired = 0;
+               if (ctx->tintv.tv64 != 0) {
+                       /*
+                        * If tintv.tv64 != 0, this is a periodic timer that
+                        * needs to be re-armed. We avoid doing it in the timer
+                        * callback to avoid DoS attacks specifying a very
+                        * short timer period.
+                        */
+                       ticks = (u32)
+                               hrtimer_forward(&ctx->tmr,
+                                               hrtimer_cb_get_time(&ctx->tmr),
+                                               ctx->tintv);
+                       hrtimer_restart(&ctx->tmr);
+               } else
+                       ticks = 1;
+       }
+       spin_unlock_irq(&ctx->lock);
+       if (ticks)
+               res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
+       return res;
+}
+
+static const struct file_operations timerfd_fops = {
+       .release        = timerfd_release,
+       .poll           = timerfd_poll,
+       .read           = timerfd_read,
+};
+
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+                           const struct itimerspec __user *utmr)
+{
+       int error;
+       struct timerfd_ctx *ctx;
+       struct file *file;
+       struct inode *inode;
+       struct itimerspec ktmr;
+
+       if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
+               return -EFAULT;
+
+       if (clockid != CLOCK_MONOTONIC &&
+           clockid != CLOCK_REALTIME)
+               return -EINVAL;
+       if (!timespec_valid(&ktmr.it_value) ||
+           !timespec_valid(&ktmr.it_interval))
+               return -EINVAL;
+
+       if (ufd == -1) {
+               ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               init_waitqueue_head(&ctx->wqh);
+               spin_lock_init(&ctx->lock);
+
+               timerfd_setup(ctx, clockid, flags, &ktmr);
+
+               /*
+                * When we call this, the initialization must be complete, since
+                * anon_inode_getfd() will install the fd.
+                */
+               error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
+                                        &timerfd_fops, ctx);
+               if (error)
+                       goto err_tmrcancel;
+       } else {
+               file = fget(ufd);
+               if (!file)
+                       return -EBADF;
+               ctx = file->private_data;
+               if (file->f_op != &timerfd_fops) {
+                       fput(file);
+                       return -EINVAL;
+               }
+               /*
+                * We need to stop the existing timer before reprogramming
+                * it to the new values.
+                */
+               for (;;) {
+                       spin_lock_irq(&ctx->lock);
+                       if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
+                               break;
+                       spin_unlock_irq(&ctx->lock);
+                       cpu_relax();
+               }
+               /*
+                * Re-program the timer to the new value ...
+                */
+               timerfd_setup(ctx, clockid, flags, &ktmr);
+
+               spin_unlock_irq(&ctx->lock);
+               fput(file);
+       }
+
+       return ufd;
+
+err_tmrcancel:
+       hrtimer_cancel(&ctx->tmr);
+       kfree(ctx);
+       return error;
+}
+
index 7775ddc0b3c6b105449bef21a3954741533129f4..e725ddd3de5f1d23bf7b1f8d0e81057ede6ac956 100644 (file)
@@ -809,7 +809,7 @@ xfs_inumbers(
                                xfs_buf_relse(agbp);
                                agbp = NULL;
                                /*
-                                * Move up the the last inode in the current
+                                * Move up the last inode in the current
                                 * chunk.  The lookup_ge will always get
                                 * us the first inode in the next chunk.
                                 */
index f5aa3ef855fbb5e793d4d7f8eeecb507a5dc99fa..a96bde6df96d13cb61a92708aff156ad6b282e97 100644 (file)
@@ -1734,11 +1734,13 @@ xfs_icsb_cpu_notify(
                        per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                /* Easy Case - initialize the area and locks, and
                 * then rebalance when online does everything else for us. */
                memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                xfs_icsb_lock(mp);
                xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
                xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
@@ -1746,6 +1748,7 @@ xfs_icsb_cpu_notify(
                xfs_icsb_unlock(mp);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                /* Disable all the counters, then fold the dead cpu's
                 * count into the total on the global superblock and
                 * re-enable the counters. */
index cb8d2868c8ac3520ba07a12cbf9c93101c53c634..7f690bb0f02f1c8e8d2356c8ca2daa26b2e9e2af 100644 (file)
@@ -290,12 +290,9 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state);
 acpi_status
 acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state);
 
-struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
-                                                 union acpi_parse_object
-                                                 *origin,
-                                                 union acpi_operand_object
-                                                 *mth_desc,
-                                                 struct acpi_thread_state
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+                                                 *origin, union acpi_operand_object
+                                                 *mth_desc, struct acpi_thread_state
                                                  *thread);
 
 acpi_status
index 24c3f05ab367ce92adf664a369c780550d2e5315..347a911d8237828d4e49b154a2d594081d789f4b 100644 (file)
@@ -319,7 +319,7 @@ ACPI_EXTERN struct acpi_fixed_event_handler
     acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
 ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
 ACPI_EXTERN struct acpi_gpe_block_info
-    *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
 
 /*****************************************************************************
  *
index 440983019993def8c5e3352b091892be11c6d288..ce7c9d653910598c29cce2baa2dcbb28b8cbb83b 100644 (file)
@@ -253,8 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 
 void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
 
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
-                         struct acpi_thread_state *thread);
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc);
 
 /*
  * exprep - ACPI AML execution - prep utilities
@@ -446,10 +445,14 @@ acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc,
 /*
  * exutils - interpreter/scanner utilities
  */
-acpi_status acpi_ex_enter_interpreter(void);
+void acpi_ex_enter_interpreter(void);
 
 void acpi_ex_exit_interpreter(void);
 
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
 void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
 
 u8 acpi_ex_acquire_global_lock(u32 rule);
index 6f83ddbed3af75117c84c741548556344462e389..202cd4242ba19bd135ac64877a954376e16f79c7 100644 (file)
@@ -630,7 +630,7 @@ ACPI_PARSE_COMMON};
  * and bytelists.
  */
 struct acpi_parse_obj_named {
-       ACPI_PARSE_COMMON u8 * path;
+       ACPI_PARSE_COMMON u8 *path;
        u8 *data;               /* AML body or bytelist data */
        u32 length;             /* AML length */
        u32 name;               /* 4-byte name or zero if no name */
index 535b7e1c41bcc12657d768136470901ca9184dd7..5ef38a6c8a6154c3c4dc0a29c347a6e10b98079e 100644 (file)
@@ -100,10 +100,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
                       acpi_walk_callback user_function,
                       void *context, void **return_value);
 
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
-                                                 struct acpi_namespace_node
-                                                 *parent,
-                                                 struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
+                                                 *parent, struct acpi_namespace_node
                                                  *child);
 
 /*
index 5206d61d74a6039eac0852145eb956b842554d6a..7e1211a8b8faf5f84710586a7130d8abfb0fa673 100644 (file)
@@ -155,7 +155,7 @@ struct acpi_object_event {
 struct acpi_object_mutex {
        ACPI_OBJECT_COMMON_HEADER u8 sync_level;        /* 0-15, specified in Mutex() call */
        u16 acquisition_depth;  /* Allow multiple Acquires, same thread */
-       acpi_thread_id owner_thread_id; /* Current owner of the mutex */
+       struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
        acpi_mutex os_mutex;    /* Actual OS synchronization object */
        union acpi_operand_object *prev;        /* Link for list of acquired mutexes */
        union acpi_operand_object *next;        /* Link for list of acquired mutexes */
@@ -216,7 +216,7 @@ struct acpi_object_processor {
            /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
        u8 proc_id;
        u8 length;
-        ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
+       ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
 };
 
 struct acpi_object_thermal_zone {
index 9cfd5b1a48eb8e9a42df7bb02009d4d3abb0eca8..c6fa5e023bc78289b92cb4d5b5da5d94f3df0266 100644 (file)
@@ -91,7 +91,8 @@ typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
 typedef int (*acpi_op_lock) (struct acpi_device * device, int type);
 typedef int (*acpi_op_start) (struct acpi_device * device);
 typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
-typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state);
+typedef int (*acpi_op_suspend) (struct acpi_device * device,
+                               pm_message_t state);
 typedef int (*acpi_op_resume) (struct acpi_device * device);
 typedef int (*acpi_op_scan) (struct acpi_device * device);
 typedef int (*acpi_op_bind) (struct acpi_device * device);
@@ -296,7 +297,7 @@ struct acpi_device {
        void *driver_data;
        struct device dev;
        struct acpi_bus_ops bus_ops;    /* workaround for different code path for hotplug */
-       enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
+       enum acpi_bus_removal_type removal_type;        /* indicate for different removal type */
 };
 
 #define acpi_driver_data(d)    ((d)->driver_data)
@@ -338,7 +339,7 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
                 acpi_handle handle, int type);
 int acpi_bus_trim(struct acpi_device *start, int rmdevice);
 int acpi_bus_start(struct acpi_device *device);
-acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd);
+acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
 int acpi_match_ids(struct acpi_device *device, char *ids);
 int acpi_create_dir(struct acpi_device *);
 void acpi_remove_dir(struct acpi_device *);
@@ -363,6 +364,6 @@ acpi_handle acpi_get_child(acpi_handle, acpi_integer);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
 
-#endif /* CONFIG_ACPI */
+#endif                         /* CONFIG_ACPI */
 
 #endif /*__ACPI_BUS_H__*/
index f6275b0e66dd34bbd5e3fde2be186eeda43ebba4..553515912c0bf3356b8b2185b2dba76a380e1d49 100644 (file)
@@ -113,7 +113,8 @@ extern int is_dock_device(acpi_handle handle);
 extern int register_dock_notifier(struct notifier_block *nb);
 extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
-       acpi_notify_handler handler, void *context);
+                                       acpi_notify_handler handler,
+                                       void *context);
 extern void unregister_hotplug_dock_device(acpi_handle handle);
 #else
 static inline int is_dock_device(acpi_handle handle)
@@ -128,7 +129,8 @@ static inline void unregister_dock_notifier(struct notifier_block *nb)
 {
 }
 static inline int register_hotplug_dock_device(acpi_handle handle,
-                               acpi_notify_handler handler, void *context)
+                                              acpi_notify_handler handler,
+                                              void *context)
 {
        return -ENODEV;
 }
index 1049f2a0a6dbf6f7a25b514ac0b08ba8bdb99095..f9d2bde9a7bbac44dd46fde43eff9e95bc4e4e2f 100644 (file)
@@ -8,7 +8,7 @@
 #if MAX_NUMNODES > 256
 #define MAX_PXM_DOMAINS MAX_NUMNODES
 #else
-#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */
+#define MAX_PXM_DOMAINS (256)  /* Old pxm spec is defined 8 bit */
 #endif
 
 extern int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS];
index 2785058c82ab0621991b54a243473e49ff3bc2a8..5e07db0d46e9997752161028ed0e4e4dc26e2219 100644 (file)
@@ -143,7 +143,8 @@ void acpi_os_release_mutex(acpi_mutex handle);
  */
 void *acpi_os_allocate(acpi_size size);
 
-void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length);
+void __iomem *acpi_os_map_memory(acpi_physical_address where,
+                                acpi_native_uint length);
 
 void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
 
index 56bf492e7acc819e7718e6cc13dd85b3b206560a..fe8abc2764370ed22204a0c05e7eeee1faea138a 100644 (file)
@@ -344,7 +344,7 @@ typedef u32 acpi_integer;
 
 /* 64-bit integers */
 
-typedef unsigned long long              acpi_integer;
+typedef unsigned long long acpi_integer;
 #define ACPI_INTEGER_MAX                ACPI_UINT64_MAX
 #define ACPI_INTEGER_BIT_SIZE           64
 #define ACPI_MAX_DECIMAL_DIGITS         20     /* 2^64 = 18,446,744,073,709,551,616 */
index 883ffe92148ff1651f2b2e36aadc0628f76f57ec..15a838862cd4c33a6646f5dd6e1ef6ae1e34aa4f 100644 (file)
@@ -498,7 +498,8 @@ acpi_ut_display_init_pathname(u8 type,
 acpi_status
 acpi_ut_walk_aml_resources(u8 * aml,
                           acpi_size aml_length,
-                          acpi_walk_aml_callback user_function, void **context);
+                          acpi_walk_aml_callback user_function,
+                          void **context);
 
 acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index);
 
index 5f532d2ac180518fdd3c9c579f43e70b5f2d73a2..a568717f98c6dcbbeb1808fc329b167caafacf7b 100644 (file)
 
 #define acpi_thread_id struct task_struct *
 
-static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; }
+static inline acpi_thread_id acpi_os_get_thread_id(void)
+{
+       return current;
+}
 
 /*
  * The irqs_disabled() check is for resume from RAM.
@@ -112,15 +115,19 @@ static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; }
  * to quiet __might_sleep() in kmalloc() and resume does not.
  */
 #include <acpi/actypes.h>
-static inline void *acpi_os_allocate(acpi_size size) {
-       return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_allocate(acpi_size size)
+{
+       return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
 }
-static inline void *acpi_os_allocate_zeroed(acpi_size size) {
-       return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_allocate_zeroed(acpi_size size)
+{
+       return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
 }
 
-static inline void *acpi_os_acquire_object(acpi_cache_t * cache) {
-        return kmem_cache_zalloc(cache, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_acquire_object(acpi_cache_t * cache)
+{
+       return kmem_cache_zalloc(cache,
+                                irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
 }
 
 #define ACPI_ALLOCATE(a)       acpi_os_allocate(a)
index 916c0102db5be85430791c1b5c575cbee888be98..b4b0ffdab098f50c5e1bb44f12400150e8ff923c 100644 (file)
@@ -18,7 +18,7 @@
 
 #define ACPI_PDC_REVISION_ID           0x1
 
-#define ACPI_PSD_REV0_REVISION         0 /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_PSD_REV0_REVISION         0       /* Support for _PSD as in ACPI 3.0 */
 #define ACPI_PSD_REV0_ENTRIES          5
 
 /*
@@ -189,8 +189,9 @@ struct acpi_processor_errata {
        } piix4;
 };
 
-extern int acpi_processor_preregister_performance(
-               struct acpi_processor_performance **performance);
+extern int acpi_processor_preregister_performance(struct
+                                                 acpi_processor_performance
+                                                 **performance);
 
 extern int acpi_processor_register_performance(struct acpi_processor_performance
                                               *performance, unsigned int cpu);
@@ -213,7 +214,8 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
 void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
                                        unsigned int cpu);
 int acpi_processor_ffh_cstate_probe(unsigned int cpu,
-               struct acpi_processor_cx *cx, struct acpi_power_register *reg);
+                                   struct acpi_processor_cx *cx,
+                                   struct acpi_power_register *reg);
 void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
 #else
 static inline void acpi_processor_power_init_bm_check(struct
@@ -224,12 +226,14 @@ static inline void acpi_processor_power_init_bm_check(struct
        return;
 }
 static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
-               struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+                                                 struct acpi_processor_cx *cx,
+                                                 struct acpi_power_register
+                                                 *reg)
 {
        return -1;
 }
-static inline void acpi_processor_ffh_cstate_enter(
-               struct acpi_processor_cx *cstate)
+static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
+                                                  *cstate)
 {
        return;
 }
index 76f89356b6a759d82e69ee6d15148c0b03098b39..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,25 +1 @@
-#ifndef __ALPHA_POLL_H
-#define __ALPHA_POLL_H
-
-#define POLLIN         (1 << 0)
-#define POLLPRI                (1 << 1)
-#define POLLOUT                (1 << 2)
-#define POLLERR                (1 << 3)
-#define POLLHUP                (1 << 4)
-#define POLLNVAL       (1 << 5)
-#define POLLRDNORM     (1 << 6)
-#define POLLRDBAND     (1 << 7)
-#define POLLWRNORM     (1 << 8)
-#define POLLWRBAND     (1 << 9)
-#define POLLMSG                (1 << 10)
-#define POLLREMOVE     (1 << 12)
-#define POLLRDHUP       (1 << 13)
-
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index a1a1eca6be45b0e3ebe72d9d236071719ba979d9..286e1d844f635e53c1903ab452ef283be423d75e 100644 (file)
@@ -51,6 +51,7 @@ int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, in
 
 #else /* CONFIG_SMP */
 
+#define hard_smp_processor_id()                0
 #define smp_call_function_on_cpu(func,info,retry,wait,cpu)    ({ 0; })
 
 #endif /* CONFIG_SMP */
index eeb3bef91e116b7fe95c4f7b17ee02ea25538285..f4defc2bd3fb246e225717c527e7c7e5c855ee4a 100644 (file)
@@ -97,7 +97,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
                                 1 << TIF_UAC_SIGBUS)
 
 #define SET_UNALIGN_CTL(task,value)    ({                                   \
-       (task)->thread_info->flags = (((task)->thread_info->flags &          \
+       task_thread_info(task)->flags = ((task_thread_info(task)->flags &    \
                ~ALPHA_UAC_MASK)                                             \
                | (((value) << ALPHA_UAC_SHIFT)       & (1<<TIF_UAC_NOPRINT))\
                | (((value) << (ALPHA_UAC_SHIFT + 1)) & (1<<TIF_UAC_SIGBUS)) \
@@ -105,11 +105,11 @@ register struct thread_info *__current_thread_info __asm__("$8");
        0; })
 
 #define GET_UNALIGN_CTL(task,value)    ({                              \
-       put_user(((task)->thread_info->flags & (1 << TIF_UAC_NOPRINT))  \
+       put_user((task_thread_info(task)->flags & (1 << TIF_UAC_NOPRINT))\
                  >> ALPHA_UAC_SHIFT                                    \
-                | ((task)->thread_info->flags & (1 << TIF_UAC_SIGBUS)) \
+                | (task_thread_info(task)->flags & (1 << TIF_UAC_SIGBUS))\
                 >> (ALPHA_UAC_SHIFT + 1)                               \
-                | ((task)->thread_info->flags & (1 << TIF_UAC_NOFIX))  \
+                | (task_thread_info(task)->flags & (1 << TIF_UAC_NOFIX))\
                 >> (ALPHA_UAC_SHIFT - 1),                              \
                 (int __user *)(value));                                \
        })
index a12ac8ab2ad081992349b924169c9c5148da1238..802891a9cd81d76089c980ae1ea02df5fa969e3f 100644 (file)
 #define AT91RM9200_UHP_BASE    0x00300000      /* USB Host controller */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_MISO          (1 <<  0)       /* A: SPI Master-In Slave-Out */
-#define AT91_PA0_PCK3          (1 <<  0)       /* B: PMC Programmable Clock Output 3 */
-#define AT91_PA1_MOSI          (1 <<  1)       /* A: SPI Master-Out Slave-In */
-#define AT91_PA1_PCK0          (1 <<  1)       /* B: PMC Programmable Clock Output 0 */
-#define AT91_PA2_SPCK          (1 <<  2)       /* A: SPI Serial Clock */
-#define AT91_PA2_IRQ4          (1 <<  2)       /* B: External Interrupt 4 */
-#define AT91_PA3_NPCS0         (1 <<  3)       /* A: SPI Peripheral Chip Select 0 */
-#define AT91_PA3_IRQ5          (1 <<  3)       /* B: External Interrupt 5 */
-#define AT91_PA4_NPCS1         (1 <<  4)       /* A: SPI Peripheral Chip Select 1 */
-#define AT91_PA4_PCK1          (1 <<  4)       /* B: PMC Programmable Clock Output 1 */
-#define AT91_PA5_NPCS2         (1 <<  5)       /* A: SPI Peripheral Chip Select 2 */
-#define AT91_PA5_TXD3          (1 <<  5)       /* B: USART Transmit Data 3 */
-#define AT91_PA6_NPCS3         (1 <<  6)       /* A: SPI Peripheral Chip Select 3 */
-#define AT91_PA6_RXD3          (1 <<  6)       /* B: USART Receive Data 3 */
-#define AT91_PA7_ETXCK_EREFCK  (1 <<  7)       /* A: Ethernet Reference Clock / Transmit Clock */
-#define AT91_PA7_PCK2          (1 <<  7)       /* B: PMC Programmable Clock Output 2 */
-#define AT91_PA8_ETXEN         (1 <<  8)       /* A: Ethernet Transmit Enable */
-#define AT91_PA8_MCCDB         (1 <<  8)       /* B: MMC Multimedia Card B Command */
-#define AT91_PA9_ETX0          (1 <<  9)       /* A: Ethernet Transmit Data 0 */
-#define AT91_PA9_MCDB0         (1 <<  9)       /* B: MMC Multimedia Card B Data 0 */
-#define AT91_PA10_ETX1         (1 << 10)       /* A: Ethernet Transmit Data 1 */
-#define AT91_PA10_MCDB1                (1 << 10)       /* B: MMC Multimedia Card B Data 1 */
-#define AT91_PA11_ECRS_ECRSDV  (1 << 11)       /* A: Ethernet Carrier Sense / Data Valid */
-#define AT91_PA11_MCDB2                (1 << 11)       /* B: MMC Multimedia Card B Data 2 */
-#define AT91_PA12_ERX0         (1 << 12)       /* A: Ethernet Receive Data 0 */
-#define AT91_PA12_MCDB3                (1 << 12)       /* B: MMC Multimedia Card B Data 3 */
-#define AT91_PA13_ERX1         (1 << 13)       /* A: Ethernet Receive Data 1 */
-#define AT91_PA13_TCLK0                (1 << 13)       /* B: TC External Clock Input 0 */
-#define AT91_PA14_ERXER                (1 << 14)       /* A: Ethernet Receive Error */
-#define AT91_PA14_TCLK1                (1 << 14)       /* B: TC External Clock Input 1 */
-#define AT91_PA15_EMDC         (1 << 15)       /* A: Ethernet Management Data Clock */
-#define AT91_PA15_TCLK2                (1 << 15)       /* B: TC External Clock Input 2 */
-#define AT91_PA16_EMDIO                (1 << 16)       /* A: Ethernet Management Data I/O */
-#define AT91_PA16_IRQ6         (1 << 16)       /* B: External Interrupt 6 */
-#define AT91_PA17_TXD0         (1 << 17)       /* A: USART Transmit Data 0 */
-#define AT91_PA17_TIOA0                (1 << 17)       /* B: TC I/O Line A 0 */
-#define AT91_PA18_RXD0         (1 << 18)       /* A: USART Receive Data 0 */
-#define AT91_PA18_TIOB0                (1 << 18)       /* B: TC I/O Line B 0 */
-#define AT91_PA19_SCK0         (1 << 19)       /* A: USART Serial Clock 0 */
-#define AT91_PA19_TIOA1                (1 << 19)       /* B: TC I/O Line A 1 */
-#define AT91_PA20_CTS0         (1 << 20)       /* A: USART Clear To Send 0 */
-#define AT91_PA20_TIOB1                (1 << 20)       /* B: TC I/O Line B 1 */
-#define AT91_PA21_RTS0         (1 << 21)       /* A: USART Ready To Send 0 */
-#define AT91_PA21_TIOA2                (1 << 21)       /* B: TC I/O Line A 2 */
-#define AT91_PA22_RXD2         (1 << 22)       /* A: USART Receive Data 2 */
-#define AT91_PA22_TIOB2                (1 << 22)       /* B: TC I/O Line B 2 */
-#define AT91_PA23_TXD2         (1 << 23)       /* A: USART Transmit Data 2 */
-#define AT91_PA23_IRQ3         (1 << 23)       /* B: External Interrupt 3 */
-#define AT91_PA24_SCK2         (1 << 24)       /* A: USART Serial Clock 2 */
-#define AT91_PA24_PCK1         (1 << 24)       /* B: PMC Programmable Clock Output 1 */
-#define AT91_PA25_TWD          (1 << 25)       /* A: TWI Two-wire Serial Data */
-#define AT91_PA25_IRQ2         (1 << 25)       /* B: External Interrupt 2 */
-#define AT91_PA26_TWCK         (1 << 26)       /* A: TWI Two-wire Serial Clock */
-#define AT91_PA26_IRQ1         (1 << 26)       /* B: External Interrupt 1 */
-#define AT91_PA27_MCCK         (1 << 27)       /* A: MMC Multimedia Card Clock */
-#define AT91_PA27_TCLK3                (1 << 27)       /* B: TC External Clock Input 3 */
-#define AT91_PA28_MCCDA                (1 << 28)       /* A: MMC Multimedia Card A Command */
-#define AT91_PA28_TCLK4                (1 << 28)       /* B: TC External Clock Input 4 */
-#define AT91_PA29_MCDA0                (1 << 29)       /* A: MMC Multimedia Card A Data 0 */
-#define AT91_PA29_TCLK5                (1 << 29)       /* B: TC External Clock Input 5 */
-#define AT91_PA30_DRXD         (1 << 30)       /* A: DBGU Receive Data */
-#define AT91_PA30_CTS2         (1 << 30)       /* B: USART Clear To Send 2 */
-#define AT91_PA31_DTXD         (1 << 31)       /* A: DBGU Transmit Data */
-#define AT91_PA31_RTS2         (1 << 31)       /* B: USART Ready To Send 2 */
-
-#define AT91_PB0_TF0           (1 <<  0)       /* A: SSC Transmit Frame Sync 0 */
-#define AT91_PB0_RTS3          (1 <<  0)       /* B: USART Ready To Send 3 */
-#define AT91_PB1_TK0           (1 <<  1)       /* A: SSC Transmit Clock 0 */
-#define AT91_PB1_CTS3          (1 <<  1)       /* B: USART Clear To Send 3 */
-#define AT91_PB2_TD0           (1 <<  2)       /* A: SSC Transmit Data 0 */
-#define AT91_PB2_SCK3          (1 <<  2)       /* B: USART Serial Clock 3 */
-#define AT91_PB3_RD0           (1 <<  3)       /* A: SSC Receive Data 0 */
-#define AT91_PB3_MCDA1         (1 <<  3)       /* B: MMC Multimedia Card A Data 1 */
-#define AT91_PB4_RK0           (1 <<  4)       /* A: SSC Receive Clock 0 */
-#define AT91_PB4_MCDA2         (1 <<  4)       /* B: MMC Multimedia Card A Data 2 */
-#define AT91_PB5_RF0           (1 <<  5)       /* A: SSC Receive Frame Sync 0 */
-#define AT91_PB5_MCDA3         (1 <<  5)       /* B: MMC Multimedia Card A Data 3 */
-#define AT91_PB6_TF1           (1 <<  6)       /* A: SSC Transmit Frame Sync 1 */
-#define AT91_PB6_TIOA3         (1 <<  6)       /* B: TC I/O Line A 3 */
-#define AT91_PB7_TK1           (1 <<  7)       /* A: SSC Transmit Clock 1 */
-#define AT91_PB7_TIOB3         (1 <<  7)       /* B: TC I/O Line B 3 */
-#define AT91_PB8_TD1           (1 <<  8)       /* A: SSC Transmit Data 1 */
-#define AT91_PB8_TIOA4         (1 <<  8)       /* B: TC I/O Line A 4 */
-#define AT91_PB9_RD1           (1 <<  9)       /* A: SSC Receive Data 1 */
-#define AT91_PB9_TIOB4         (1 <<  9)       /* B: TC I/O Line B 4 */
-#define AT91_PB10_RK1          (1 << 10)       /* A: SSC Receive Clock 1 */
-#define AT91_PB10_TIOA5                (1 << 10)       /* B: TC I/O Line A 5 */
-#define AT91_PB11_RF1          (1 << 11)       /* A: SSC Receive Frame Sync 1 */
-#define AT91_PB11_TIOB5                (1 << 11)       /* B: TC I/O Line B 5 */
-#define AT91_PB12_TF2          (1 << 12)       /* A: SSC Transmit Frame Sync 2 */
-#define AT91_PB12_ETX2         (1 << 12)       /* B: Ethernet Transmit Data 2 */
-#define AT91_PB13_TK2          (1 << 13)       /* A: SSC Transmit Clock 3 */
-#define AT91_PB13_ETX3         (1 << 13)       /* B: Ethernet Transmit Data 3 */
-#define AT91_PB14_TD2          (1 << 14)       /* A: SSC Transmit Data 2 */
-#define AT91_PB14_ETXER                (1 << 14)       /* B: Ethernet Transmit Coding Error */
-#define AT91_PB15_RD2          (1 << 15)       /* A: SSC Receive Data 2 */
-#define AT91_PB15_ERX2         (1 << 15)       /* B: Ethernet Receive Data 2 */
-#define AT91_PB16_RK2          (1 << 16)       /* A: SSC Receive Clock 2 */
-#define AT91_PB16_ERX3         (1 << 16)       /* B: Ethernet Receive Data 3 */
-#define AT91_PB17_RF2          (1 << 17)       /* A: SSC Receive Frame Sync 2 */
-#define AT91_PB17_ERXDV                (1 << 17)       /* B: Ethernet Receive Data Valid */
-#define AT91_PB18_RI1          (1 << 18)       /* A: USART Ring Indicator 1 */
-#define AT91_PB18_ECOL         (1 << 18)       /* B: Ethernet Collision Detected */
-#define AT91_PB19_DTR1         (1 << 19)       /* A: USART Data Terminal Ready 1 */
-#define AT91_PB19_ERXCK                (1 << 19)       /* B: Ethernet Receive Clock */
-#define AT91_PB20_TXD1         (1 << 20)       /* A: USART Transmit Data 1 */
-#define AT91_PB21_RXD1         (1 << 21)       /* A: USART Receive Data 1 */
-#define AT91_PB22_SCK1         (1 << 22)       /* A: USART Serial Clock 1 */
-#define AT91_PB23_DCD1         (1 << 23)       /* A: USART Data Carrier Detect 1 */
-#define AT91_PB24_CTS1         (1 << 24)       /* A: USART Clear To Send 1 */
-#define AT91_PB25_DSR1         (1 << 25)       /* A: USART Data Set Ready 1 */
-#define AT91_PB25_EF100                (1 << 25)       /* B: Ethernet Force 100 Mbit */
-#define AT91_PB26_RTS1         (1 << 26)       /* A: USART Ready To Send 1 */
-#define AT91_PB27_PCK0         (1 << 27)       /* B: PMC Programmable Clock Output 0 */
-#define AT91_PB28_FIQ          (1 << 28)       /* A: Fast Interrupt */
-#define AT91_PB29_IRQ0         (1 << 29)       /* A: External Interrupt 0 */
-
-#define AT91_PC0_BFCK          (1 <<  0)       /* A: Burst Flash Clock */
-#define AT91_PC1_BFRDY_SMOE    (1 <<  1)       /* A: Burst Flash Ready / SmartMedia Output Enable */
-#define AT91_PC2_BFAVD         (1 <<  2)       /* A: Burst Flash Address Valid */
-#define AT91_PC3_BFBAA_SMWE    (1 <<  3)       /* A: Burst Flash Address Advance / SmartMedia Write Enable */
-#define AT91_PC4_BFOE          (1 <<  4)       /* A: Burst Flash Output Enable */
-#define AT91_PC5_BFWE          (1 <<  5)       /* A: Burst Flash Write Enable */
-#define AT91_PC6_NWAIT         (1 <<  6)       /* A: SMC Wait Signal */
-#define AT91_PC7_A23           (1 <<  7)       /* A: Address Bus 23 */
-#define AT91_PC8_A24           (1 <<  8)       /* A: Address Bus 24 */
-#define AT91_PC9_A25_CFRNW     (1 <<  9)       /* A: Address Bus 25 / Compact Flash Read Not Write */
-#define AT91_PC10_NCS4_CFCS    (1 << 10)       /* A: SMC Chip Select 4 / Compact Flash Chip Select */
-#define AT91_PC11_NCS5_CFCE1   (1 << 11)       /* A: SMC Chip Select 5 / Compact Flash Chip Enable 1 */
-#define AT91_PC12_NCS6_CFCE2   (1 << 12)       /* A: SMC Chip Select 6 / Compact Flash Chip Enable 2 */
-#define AT91_PC13_NCS7         (1 << 13)       /* A: Chip Select 7 */
-
-#define AT91_PD0_ETX0          (1 <<  0)       /* A: Ethernet Transmit Data 0 */
-#define AT91_PD1_ETX1          (1 <<  1)       /* A: Ethernet Transmit Data 1 */
-#define AT91_PD2_ETX2          (1 <<  2)       /* A: Ethernet Transmit Data 2 */
-#define AT91_PD3_ETX3          (1 <<  3)       /* A: Ethernet Transmit Data 3 */
-#define AT91_PD4_ETXEN         (1 <<  4)       /* A: Ethernet Transmit Enable */
-#define AT91_PD5_ETXER         (1 <<  5)       /* A: Ethernet Transmit Coding Error */
-#define AT91_PD6_DTXD          (1 <<  6)       /* A: DBGU Transmit Data */
-#define AT91_PD7_PCK0          (1 <<  7)       /* A: PMC Programmable Clock Output 0 */
-#define AT91_PD7_TSYNC         (1 <<  7)       /* B: ETM Trace Synchronization Signal */
-#define AT91_PD8_PCK1          (1 <<  8)       /* A: PMC Programmable Clock Output 1 */
-#define AT91_PD8_TCLK          (1 <<  8)       /* B: ETM Trace Clock */
-#define AT91_PD9_PCK2          (1 <<  9)       /* A: PMC Programmable Clock Output 2 */
-#define AT91_PD9_TPS0          (1 <<  9)       /* B: ETM Trace ARM Pipeline Status 0 */
-#define AT91_PD10_PCK3         (1 << 10)       /* A: PMC Programmable Clock Output 3 */
-#define AT91_PD10_TPS1         (1 << 10)       /* B: ETM Trace ARM Pipeline Status 1 */
-#define AT91_PD11_TPS2         (1 << 11)       /* B: ETM Trace ARM Pipeline Status 2 */
-#define AT91_PD12_TPK0         (1 << 12)       /* B: ETM Trace Packet Port 0 */
-#define AT91_PD13_TPK1         (1 << 13)       /* B: ETM Trace Packet Port 1 */
-#define AT91_PD14_TPK2         (1 << 14)       /* B: ETM Trace Packet Port 2 */
-#define AT91_PD15_TD0          (1 << 15)       /* A: SSC Transmit Data 0 */
-#define AT91_PD15_TPK3         (1 << 15)       /* B: ETM Trace Packet Port 3 */
-#define AT91_PD16_TD1          (1 << 16)       /* A: SSC Transmit Data 1 */
-#define AT91_PD16_TPK4         (1 << 16)       /* B: ETM Trace Packet Port 4 */
-#define AT91_PD17_TD2          (1 << 17)       /* A: SSC Transmit Data 2 */
-#define AT91_PD17_TPK5         (1 << 17)       /* B: ETM Trace Packet Port 5 */
-#define AT91_PD18_NPCS1                (1 << 18)       /* A: SPI Peripheral Chip Select 1 */
-#define AT91_PD18_TPK6         (1 << 18)       /* B: ETM Trace Packet Port 6 */
-#define AT91_PD19_NPCS2                (1 << 19)       /* A: SPI Peripheral Chip Select 2 */
-#define AT91_PD19_TPK7         (1 << 19)       /* B: ETM Trace Packet Port 7 */
-#define AT91_PD20_NPCS3                (1 << 20)       /* A: SPI Peripheral Chip Select 3 */
-#define AT91_PD20_TPK8         (1 << 20)       /* B: ETM Trace Packet Port 8 */
-#define AT91_PD21_RTS0         (1 << 21)       /* A: USART Ready To Send 0 */
-#define AT91_PD21_TPK9         (1 << 21)       /* B: ETM Trace Packet Port 9 */
-#define AT91_PD22_RTS1         (1 << 22)       /* A: USART Ready To Send 1 */
-#define AT91_PD22_TPK10                (1 << 22)       /* B: ETM Trace Packet Port 10 */
-#define AT91_PD23_RTS2         (1 << 23)       /* A: USART Ready To Send 2 */
-#define AT91_PD23_TPK11                (1 << 23)       /* B: ETM Trace Packet Port 11 */
-#define AT91_PD24_RTS3         (1 << 24)       /* A: USART Ready To Send 3 */
-#define AT91_PD24_TPK12                (1 << 24)       /* B: ETM Trace Packet Port 12 */
-#define AT91_PD25_DTR1         (1 << 25)       /* A: USART Data Terminal Ready 1 */
-#define AT91_PD25_TPK13                (1 << 25)       /* B: ETM Trace Packet Port 13 */
-#define AT91_PD26_TPK14                (1 << 26)       /* B: ETM Trace Packet Port 14 */
-#define AT91_PD27_TPK15                (1 << 27)       /* B: ETM Trace Packet Port 15 */
-#endif
-
 #endif
index 2cadebc36af70fc233fa35c143c52167df5d86ec..0427f8698c07a8e8f43ec675929b1fd907ebb033 100644 (file)
 #define AT91SAM9XE_SRAM_BASE   0x00300000      /* Internal SRAM base address */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
-
 #endif
index 01b58ffe2e27c2c86c2502e0bcef41abd95f1516..9eb4595703307832b8cc2224fcab032f1a45ee08 100644 (file)
 #define AT91SAM9261_LCDC_BASE  0x00600000      /* LDC controller */
 
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_SPI0_MISO     (1 <<  0)       /* A: SPI0 Master In Slave */
-#define AT91_PA0_MCDA0         (1 <<  0)       /* B: Multimedia Card A Data 0 */
-#define AT91_PA1_SPI0_MOSI     (1 <<  1)       /* A: SPI0 Master Out Slave */
-#define AT91_PA1_MCCDA         (1 <<  1)       /* B: Multimedia Card A Command */
-#define AT91_PA2_SPI0_SPCK     (1 <<  2)       /* A: SPI0 Serial Clock */
-#define AT91_PA2_MCCK          (1 <<  2)       /* B: Multimedia Card Clock */
-#define AT91_PA3_SPI0_NPCS0    (1 <<  3)       /* A: SPI0 Peripheral Chip Select 0 */
-#define AT91_PA4_SPI0_NPCS1    (1 <<  4)       /* A: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA4_MCDA1         (1 <<  4)       /* B: Multimedia Card A Data 1 */
-#define AT91_PA5_SPI0_NPCS2    (1 <<  5)       /* A: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA5_MCDA2         (1 <<  5)       /* B: Multimedia Card A Data 2 */
-#define AT91_PA6_SPI0_NPCS3    (1 <<  6)       /* A: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA6_MCDA3         (1 <<  6)       /* B: Multimedia Card A Data 3 */
-#define AT91_PA7_TWD           (1 <<  7)       /* A: TWI Two-wire Serial Data */
-#define AT91_PA7_PCK0          (1 <<  7)       /* B: PMC Programmable clock Output 0 */
-#define AT91_PA8_TWCK          (1 <<  8)       /* A: TWI Two-wire Serial Clock */
-#define AT91_PA8_PCK1          (1 <<  8)       /* B: PMC Programmable clock Output 1 */
-#define AT91_PA9_DRXD          (1 <<  9)       /* A: DBGU Debug Receive Data */
-#define AT91_PA9_PCK2          (1 <<  9)       /* B: PMC Programmable clock Output 2 */
-#define AT91_PA10_DTXD         (1 << 10)       /* A: DBGU Debug Transmit Data */
-#define AT91_PA10_PCK3         (1 << 10)       /* B: PMC Programmable clock Output 3 */
-#define AT91_PA11_TSYNC                (1 << 11)       /* A: Trace Synchronization Signal */
-#define AT91_PA11_SCK1         (1 << 11)       /* B: USART1 Serial Clock */
-#define AT91_PA12_TCLK         (1 << 12)       /* A: Trace Clock */
-#define AT91_PA12_RTS1         (1 << 12)       /* B: USART1 Ready To Send */
-#define AT91_PA13_TPS0         (1 << 13)       /* A: Trace ARM Pipeline Status 0 */
-#define AT91_PA13_CTS1         (1 << 13)       /* B: USART1 Clear To Send */
-#define AT91_PA14_TPS1         (1 << 14)       /* A: Trace ARM Pipeline Status 1 */
-#define AT91_PA14_SCK2         (1 << 14)       /* B: USART2 Serial Clock */
-#define AT91_PA15_TPS2         (1 << 15)       /* A: Trace ARM Pipeline Status 2 */
-#define AT91_PA15_RTS2         (1 << 15)       /* B: USART2 Ready To Send */
-#define AT91_PA16_TPK0         (1 << 16)       /* A: Trace Packet Port 0 */
-#define AT91_PA16_CTS2         (1 << 16)       /* B: USART2 Clear To Send */
-#define AT91_PA17_TPK1         (1 << 17)       /* A: Trace Packet Port 1 */
-#define AT91_PA17_TF1          (1 << 17)       /* B: SSC1 Transmit Frame Sync */
-#define AT91_PA18_TPK2         (1 << 18)       /* A: Trace Packet Port 2 */
-#define AT91_PA18_TK1          (1 << 18)       /* B: SSC1 Transmit Clock */
-#define AT91_PA19_TPK3         (1 << 19)       /* A: Trace Packet Port 3 */
-#define AT91_PA19_TD1          (1 << 19)       /* B: SSC1 Transmit Data */
-#define AT91_PA20_TPK4         (1 << 20)       /* A: Trace Packet Port 4 */
-#define AT91_PA20_RD1          (1 << 20)       /* B: SSC1 Receive Data */
-#define AT91_PA21_TPK5         (1 << 21)       /* A: Trace Packet Port 5 */
-#define AT91_PA21_RK1          (1 << 21)       /* B: SSC1 Receive Clock */
-#define AT91_PA22_TPK6         (1 << 22)       /* A: Trace Packet Port 6 */
-#define AT91_PA22_RF1          (1 << 22)       /* B: SSC1 Receive Frame Sync */
-#define AT91_PA23_TPK7         (1 << 23)       /* A: Trace Packet Port 7 */
-#define AT91_PA23_RTS0         (1 << 23)       /* B: USART0 Ready To Send */
-#define AT91_PA24_TPK8         (1 << 24)       /* A: Trace Packet Port 8 */
-#define AT91_PA24_SPI1_NPCS1   (1 << 24)       /* B: SPI1 Peripheral Chip Select 1 */
-#define AT91_PA25_TPK9         (1 << 25)       /* A: Trace Packet Port 9 */
-#define AT91_PA25_SPI1_NPCS2   (1 << 25)       /* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PA26_TPK10                (1 << 26)       /* A: Trace Packet Port 10 */
-#define AT91_PA26_SPI1_NPCS3   (1 << 26)       /* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PA27_TPK11                (1 << 27)       /* A: Trace Packet Port 11 */
-#define AT91_PA27_SPI0_NPCS1   (1 << 27)       /* B: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA28_TPK12                (1 << 28)       /* A: Trace Packet Port 12 */
-#define AT91_PA28_SPI0_NPCS2   (1 << 28)       /* B: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA29_TPK13                (1 << 29)       /* A: Trace Packet Port 13 */
-#define AT91_PA29_SPI0_NPCS3   (1 << 29)       /* B: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA30_TPK14                (1 << 30)       /* A: Trace Packet Port 14 */
-#define AT91_PA30_A23          (1 << 30)       /* B: Address Bus bit 23 */
-#define AT91_PA31_TPK15                (1 << 31)       /* A: Trace Packet Port 15 */
-#define AT91_PA31_A24          (1 << 31)       /* B: Address Bus bit 24 */
-
-#define AT91_PB0_LCDVSYNC      (1 <<  0)       /* A: LCD Vertical Synchronization */
-#define AT91_PB1_LCDHSYNC      (1 <<  1)       /* A: LCD Horizontal Synchronization */
-#define AT91_PB2_LCDDOTCK      (1 <<  2)       /* A: LCD Dot Clock */
-#define AT91_PB2_PCK0          (1 <<  2)       /* B: PMC Programmable clock Output 0 */
-#define AT91_PB3_LCDDEN                (1 <<  3)       /* A: LCD Data Enable */
-#define AT91_PB4_LCDCC         (1 <<  4)       /* A: LCD Contrast Control */
-#define AT91_PB4_LCDD2         (1 <<  4)       /* B: LCD Data Bus Bit 2 */
-#define AT91_PB5_LCDD0         (1 <<  5)       /* A: LCD Data Bus Bit 0 */
-#define AT91_PB5_LCDD3         (1 <<  5)       /* B: LCD Data Bus Bit 3 */
-#define AT91_PB6_LCDD1         (1 <<  6)       /* A: LCD Data Bus Bit 1 */
-#define AT91_PB6_LCDD4         (1 <<  6)       /* B: LCD Data Bus Bit 4 */
-#define AT91_PB7_LCDD2         (1 <<  7)       /* A: LCD Data Bus Bit 2 */
-#define AT91_PB7_LCDD5         (1 <<  7)       /* B: LCD Data Bus Bit 5 */
-#define AT91_PB8_LCDD3         (1 <<  8)       /* A: LCD Data Bus Bit 3 */
-#define AT91_PB8_LCDD6         (1 <<  8)       /* B: LCD Data Bus Bit 6 */
-#define AT91_PB9_LCDD4         (1 <<  9)       /* A: LCD Data Bus Bit 4 */
-#define AT91_PB9_LCDD7         (1 <<  9)       /* B: LCD Data Bus Bit 7 */
-#define AT91_PB10_LCDD5                (1 << 10)       /* A: LCD Data Bus Bit 5 */
-#define AT91_PB10_LCDD10       (1 << 10)       /* B: LCD Data Bus Bit 10 */
-#define AT91_PB11_LCDD6                (1 << 11)       /* A: LCD Data Bus Bit 6 */
-#define AT91_PB11_LCDD11       (1 << 11)       /* B: LCD Data Bus Bit 11 */
-#define AT91_PB12_LCDD7                (1 << 12)       /* A: LCD Data Bus Bit 7 */
-#define AT91_PB12_LCDD12       (1 << 12)       /* B: LCD Data Bus Bit 12 */
-#define AT91_PB13_LCDD8                (1 << 13)       /* A: LCD Data Bus Bit 8 */
-#define AT91_PB13_LCDD13       (1 << 13)       /* B: LCD Data Bus Bit 13 */
-#define AT91_PB14_LCDD9                (1 << 14)       /* A: LCD Data Bus Bit 9 */
-#define AT91_PB14_LCDD14       (1 << 14)       /* B: LCD Data Bus Bit 14 */
-#define AT91_PB15_LCDD10       (1 << 15)       /* A: LCD Data Bus Bit 10 */
-#define AT91_PB15_LCDD15       (1 << 15)       /* B: LCD Data Bus Bit 15 */
-#define AT91_PB16_LCDD11       (1 << 16)       /* A: LCD Data Bus Bit 11 */
-#define AT91_PB16_LCDD19       (1 << 16)       /* B: LCD Data Bus Bit 19 */
-#define AT91_PB17_LCDD12       (1 << 17)       /* A: LCD Data Bus Bit 12 */
-#define AT91_PB17_LCDD20       (1 << 17)       /* B: LCD Data Bus Bit 20 */
-#define AT91_PB18_LCDD13       (1 << 18)       /* A: LCD Data Bus Bit 13 */
-#define AT91_PB18_LCDD21       (1 << 18)       /* B: LCD Data Bus Bit 21 */
-#define AT91_PB19_LCDD14       (1 << 19)       /* A: LCD Data Bus Bit 14 */
-#define AT91_PB19_LCDD22       (1 << 19)       /* B: LCD Data Bus Bit 22 */
-#define AT91_PB20_LCDD15       (1 << 20)       /* A: LCD Data Bus Bit 15 */
-#define AT91_PB20_LCDD23       (1 << 20)       /* B: LCD Data Bus Bit 23 */
-#define AT91_PB21_TF0          (1 << 21)       /* A: SSC0 Transmit Frame Sync */
-#define AT91_PB21_LCDD16       (1 << 21)       /* B: LCD Data Bus Bit 16 */
-#define AT91_PB22_TK0          (1 << 22)       /* A: SSC0 Transmit Clock */
-#define AT91_PB22_LCDD17       (1 << 22)       /* B: LCD Data Bus Bit 17 */
-#define AT91_PB23_TD0          (1 << 23)       /* A: SSC0 Transmit Data */
-#define AT91_PB23_LCDD18       (1 << 23)       /* B: LCD Data Bus Bit 18 */
-#define AT91_PB24_RD0          (1 << 24)       /* A: SSC0 Receive Data */
-#define AT91_PB24_LCDD19       (1 << 24)       /* B: LCD Data Bus Bit 19 */
-#define AT91_PB25_RK0          (1 << 25)       /* A: SSC0 Receive Clock */
-#define AT91_PB25_LCDD20       (1 << 25)       /* B: LCD Data Bus Bit 20 */
-#define AT91_PB26_RF0          (1 << 26)       /* A: SSC0 Receive Frame Sync */
-#define AT91_PB26_LCDD21       (1 << 26)       /* B: LCD Data Bus Bit 21 */
-#define AT91_PB27_SPI1_NPCS1   (1 << 27)       /* A: SPI1 Peripheral Chip Select 1 */
-#define AT91_PB27_LCDD22       (1 << 27)       /* B: LCD Data Bus Bit 22 */
-#define AT91_PB28_SPI1_NPCS0   (1 << 28)       /* A: SPI1 Peripheral Chip Select 0 */
-#define AT91_PB28_LCDD23       (1 << 28)       /* B: LCD Data Bus Bit 23 */
-#define AT91_PB29_SPI1_SPCK    (1 << 29)       /* A: SPI1 Serial Clock */
-#define AT91_PB29_IRQ2         (1 << 29)       /* B: Interrupt input 2 */
-#define AT91_PB30_SPI1_MISO    (1 << 30)       /* A: SPI1 Master In Slave */
-#define AT91_PB30_IRQ1         (1 << 30)       /* B: Interrupt input 1 */
-#define AT91_PB31_SPI1_MOSI    (1 << 31)       /* A: SPI1 Master Out Slave */
-#define AT91_PB31_PCK2         (1 << 31)       /* B: PMC Programmable clock Output 2 */
-
-#define AT91_PC0_SMOE          (1 << 0)        /* A: SmartMedia Output Enable */
-#define AT91_PC0_NCS6          (1 << 0)        /* B: Chip Select 6 */
-#define AT91_PC1_SMWE          (1 << 1)        /* A: SmartMedia Write Enable */
-#define AT91_PC1_NCS7          (1 << 1)        /* B: Chip Select 7 */
-#define AT91_PC2_NWAIT         (1 << 2)        /* A: NWAIT */
-#define AT91_PC2_IRQ0          (1 << 2)        /* B: Interrupt input 0 */
-#define AT91_PC3_A25_CFRNW     (1 << 3)        /* A: Address Bus[25] / Compact Flash Read Not Write */
-#define AT91_PC4_NCS4_CFCS0    (1 << 4)        /* A: Chip Select 4 / CompactFlash Chip Select 0 */
-#define AT91_PC5_NCS5_CFCS1    (1 << 5)        /* A: Chip Select 5 / CompactFlash Chip Select 1 */
-#define AT91_PC6_CFCE1         (1 << 6)        /* A: CompactFlash Chip Enable 1 */
-#define AT91_PC7_CFCE2         (1 << 7)        /* A: CompactFlash Chip Enable 2 */
-#define AT91_PC8_TXD0          (1 << 8)        /* A: USART0 Transmit Data */
-#define AT91_PC8_PCK2          (1 << 8)        /* B: PMC Programmable clock Output 2 */
-#define AT91_PC9_RXD0          (1 << 9)        /* A: USART0 Receive Data */
-#define AT91_PC9_PCK3          (1 << 9)        /* B: PMC Programmable clock Output 3 */
-#define AT91_PC10_RTS0         (1 << 10)       /* A: USART0 Ready To Send */
-#define AT91_PC10_SCK0         (1 << 10)       /* B: USART0 Serial Clock */
-#define AT91_PC11_CTS0         (1 << 11)       /* A: USART0 Clear To Send */
-#define AT91_PC11_FIQ          (1 << 11)       /* B: AIC Fast Interrupt Input */
-#define AT91_PC12_TXD1         (1 << 12)       /* A: USART1 Transmit Data */
-#define AT91_PC12_NCS6         (1 << 12)       /* B: Chip Select 6 */
-#define AT91_PC13_RXD1         (1 << 13)       /* A: USART1 Receive Data */
-#define AT91_PC13_NCS7         (1 << 13)       /* B: Chip Select 7 */
-#define AT91_PC14_TXD2         (1 << 14)       /* A: USART2 Transmit Data */
-#define AT91_PC14_SPI1_NPCS2   (1 << 14)       /* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PC15_RXD2         (1 << 15)       /* A: USART2 Receive Data */
-#define AT91_PC15_SPI1_NPCS3   (1 << 15)       /* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PC16_D16          (1 << 16)       /* A: Data Bus [16] */
-#define AT91_PC16_TCLK0                (1 << 16)       /* B: Timer Counter 0 external clock input */
-#define AT91_PC17_D17          (1 << 17)       /* A: Data Bus [17] */
-#define AT91_PC17_TCLK1                (1 << 17)       /* B: Timer Counter 1 external clock input */
-#define AT91_PC18_D18          (1 << 18)       /* A: Data Bus [18] */
-#define AT91_PC18_TCLK2                (1 << 18)       /* B: Timer Counter 2 external clock input */
-#define AT91_PC19_D19          (1 << 19)       /* A: Data Bus [19] */
-#define AT91_PC19_TIOA0                (1 << 19)       /* B: Timer Counter 0 Multipurpose Timer I/O Pin A */
-#define AT91_PC20_D20          (1 << 20)       /* A: Data Bus [20] */
-#define AT91_PC20_TIOB0                (1 << 20)       /* B: Timer Counter 0 Multipurpose Timer I/O Pin B */
-#define AT91_PC21_D21          (1 << 21)       /* A: Data Bus [21] */
-#define AT91_PC21_TIOA1                (1 << 21)       /* B: Timer Counter 1 Multipurpose Timer I/O Pin A */
-#define AT91_PC22_D22          (1 << 22)       /* A: Data Bus [22] */
-#define AT91_PC22_TIOB1                (1 << 22)       /* B: Timer Counter 1 Multipurpose Timer I/O Pin B */
-#define AT91_PC23_D23          (1 << 23)       /* A: Data Bus [23] */
-#define AT91_PC23_TIOA2                (1 << 23)       /* B: Timer Counter 2 Multipurpose Timer I/O Pin A */
-#define AT91_PC24_D24          (1 << 24)       /* A: Data Bus [24] */
-#define AT91_PC24_TIOB2                (1 << 24)       /* B: Timer Counter 2 Multipurpose Timer I/O Pin B */
-#define AT91_PC25_D25          (1 << 25)       /* A: Data Bus [25] */
-#define AT91_PC25_TF2          (1 << 25)       /* B: SSC2 Transmit Frame Sync */
-#define AT91_PC26_D26          (1 << 26)       /* A: Data Bus [26] */
-#define AT91_PC26_TK2          (1 << 26)       /* B: SSC2 Transmit Clock */
-#define AT91_PC27_D27          (1 << 27)       /* A: Data Bus [27] */
-#define AT91_PC27_TD2          (1 << 27)       /* B: SSC2 Transmit Data */
-#define AT91_PC28_D28          (1 << 28)       /* A: Data Bus [28] */
-#define AT91_PC28_RD2          (1 << 28)       /* B: SSC2 Receive Data */
-#define AT91_PC29_D29          (1 << 29)       /* A: Data Bus [29] */
-#define AT91_PC29_RK2          (1 << 29)       /* B: SSC2 Receive Clock */
-#define AT91_PC30_D30          (1 << 30)       /* A: Data Bus [30] */
-#define AT91_PC30_RF2          (1 << 30)       /* B: SSC2 Receive Frame Sync */
-#define AT91_PC31_D31          (1 << 31)       /* A: Data Bus [31] */
-#define AT91_PC31_PCK1         (1 << 31)       /* B: PMC Programmable clock Output 1 */
-#endif
-
 #endif
index f4af68ae0ea93f7cbbf427323096d302338944ac..115c47ac7ebb0b22b75d00e1ddcfeaf1dee25a21 100644 (file)
 #define AT91SAM9263_DMAC_BASE  0x00800000      /* DMA Controller */
 #define AT91SAM9263_UHP_BASE   0x00a00000      /* USB Host controller */
 
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
 
 #endif
index 7a34a5b1fed0dfa4be4c1de940098b32e070cb51..0ce6ee98ed0be0beb1231e20e3b6ea468e7c059e 100644 (file)
@@ -121,7 +121,7 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
  /* AC97 */
 struct atmel_ac97_data {
        u8              reset_pin;      /* reset */
-}
+};
 extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
 
  /* LEDs */
index d464ca58cdbc07e427180d235f590953c13a2fc1..7ef4eebe9f8e9e358f2cc3304d00238c6eece3e7 100644 (file)
@@ -68,4 +68,10 @@ static inline unsigned long at91_arch_identify(void)
 #define cpu_is_at91sam9263()   (0)
 #endif
 
+/*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at32ap7000()    (0)
+
 #endif
index de6494a4dc6bc7d8cb92760778fdd20261b35385..30de404c61f5ef71e1243e0dada38cbed8e277c9 100644 (file)
 #define SAR(x)  __REG2( IMX_DMAC_BASE + 0x80, (x) << 6)        /* Source Address Registers */
 #define DAR(x)  __REG2( IMX_DMAC_BASE + 0x84, (x) << 6)        /* Destination Address Registers */
 #define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6)        /* Count Registers */
-#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)        /* Control Registers */
+#define CCR(x)  __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6)        /* Control Registers */
 #define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6)        /* Request source select Registers */
 #define BLR(x)  __REG2( IMX_DMAC_BASE + 0x94, (x) << 6)        /* Burst length Registers */
 #define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6)        /* Request timeout Registers */
index 96ad3d2a66d1ead1ce639fb47569e642ebbb6050..83c4c1ceb411dc2615003c3f0304a9b9b8e9e04d 100644 (file)
@@ -17,7 +17,7 @@
  *                 from .s file by awk -f s2h.awk
  */
 /**************************************************************************
- * * Copyright © ARM Limited 1998.  All rights reserved.
+ * * Copyright Â© ARM Limited 1998.  All rights reserved.
  * ***********************************************************************/
 /* ************************************************************************
  *
index 3b065618dd0009d79eb53c43b098d037d45bba3e..bf0665acc1c13bb47b9a3b18e326a20210281169 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm/arch-iop32x/glantank.h
+ * include/asm-arm/arch-iop32x/glantank.h
  *
  * IO-Data GLAN Tank board registers
  */
index fed31a648425845aa2a3dd2f4c42f239f6afef41..77a8af47662975dedf99c486f41ae0cc66d939ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm/arch-iop32x/n2100.h
+ * include/asm-arm/arch-iop32x/n2100.h
  *
  * Thecus N2100 board registers
  */
index 6513065941d0872753ba5ded51dec517f82393de..aec2d65636229a5a49b05e970481eaf2386986db 100644 (file)
 #define TLV320AIC23ID1                  (0x1a) // cs low
 #define TLV320AIC23ID2                  (0x1b) // cs high
 
-void tlv320aic23_power_up(void);
-void tlv320aic23_power_down(void);
+void aic23_power_up(void);
+void aic23_power_down(void);
 
 #endif /* __ASM_ARCH_AIC23_H */
index de0c5b792c5852aa2190f2cc099e51a8410cc64c..dcb587b311f18fa038b21c38ff0044861a6a9bab 100644 (file)
 #define __ASM_ARCH_OMAP_APOLLON_H
 
 /* Placeholder for APOLLON specific defines */
-/* GPMC CS0 */
-#define APOLLON_CS0_BASE               0x00000000
-/* GPMC CS1 */
-#define APOLLON_CS1_BASE               0x08000000
-#define APOLLON_ETHR_START             (APOLLON_CS1_BASE + 0x300)
 #define APOLLON_ETHR_GPIO_IRQ          74
-/* GPMC CS2 - reserved for OneNAND */
-#define APOLLON_CS2_BASE               0x10000000
-/* GPMC CS3 - reserved for NOR or NAND */
-#define APOLLON_CS3_BASE               0x18000000
 
 #endif /*  __ASM_ARCH_OMAP_APOLLON_H */
 
index 7ef664bc9e330c4b284cdd81042ca38bb670066a..7e0efef4bb65a178d310cf3a107856b85ca5a354 100644 (file)
@@ -30,9 +30,6 @@
 #define __ASM_ARCH_OMAP_H4_H
 
 /* Placeholder for H4 specific defines */
-/* GPMC CS1 */
-#define OMAP24XX_ETHR_START             0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ         92
-#define H4_CS0_BASE                    0x04000000
 #endif /*  __ASM_ARCH_OMAP_H4_H */
 
index edf1dc6ad919b45ec807807762c1cdcd37c487e8..031672c563777667b6f9f37baadea56137b74b43 100644 (file)
@@ -4,7 +4,7 @@
  *  Information structures for board-specific data
  *
  *  Copyright (C) 2004 Nokia Corporation
- *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *  Written by Juha Yrjölä <juha.yrjola@nokia.com>
  */
 
 #ifndef _OMAP_BOARD_H
@@ -12,6 +12,8 @@
 
 #include <linux/types.h>
 
+#include <asm/arch/gpio-switch.h>
+
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK         0x4f01
 #define OMAP_TAG_MMC           0x4f02
@@ -99,26 +101,31 @@ struct omap_usb_config {
 struct omap_lcd_config {
        char panel_name[16];
        char ctrl_name[16];
+       s16  nreset_gpio;
+       u8   data_lines;
+};
+
+struct device;
+struct fb_info;
+struct omap_backlight_config {
+       int default_intensity;
+       int (*set_power)(struct device *dev, int state);
+       int (*check_fb)(struct fb_info *fb);
 };
 
 struct omap_fbmem_config {
-       u32 fb_sram_start;
-       u32 fb_sram_size;
-       u32 fb_sdram_start;
-       u32 fb_sdram_size;
-};
-
-/* Cover:
- *      high -> closed
- *      low  -> open
- * Connection:
- *      high -> connected
- *      low  -> disconnected
- */
-#define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
-#define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED         0x0001
-#define OMAP_GPIO_SWITCH_FLAG_OUTPUT           0x0002
+       u32 start;
+       u32 size;
+};
+
+struct omap_pwm_led_platform_data {
+       const char *name;
+       int intensity_timer;
+       int blink_timer;
+       void (*set_power)(struct omap_pwm_led_platform_data *self, int on_off);
+};
+
+/* See include/asm-arm/arch-omap/gpio-switch.h for definitions */
 struct omap_gpio_switch_config {
        char name[12];
        u16 gpio;
index d591d0585bbab64f7cb944788ac02c5f957d258c..f7774192a41e7aae5fd716e16e2204e47b0c6bd8 100644 (file)
@@ -2,7 +2,7 @@
  *  linux/include/asm-arm/arch-omap/dma.h
  *
  *  Copyright (C) 2003 Nokia Corporation
- *  Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *  Author: Juha Yrjölä <juha.yrjola@nokia.com>
  *
  * 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
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
deleted file mode 100644 (file)
index 06dad83..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * linux/include/asm-arm/arch-omap/dsp.h
- *
- * Header for OMAP DSP driver
- *
- * Copyright (C) 2002-2005 Nokia Corporation
- *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- *
- * 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
- *
- * 2005/06/01:  DSP Gateway version 3.3
- */
-
-#ifndef ASM_ARCH_DSP_H
-#define ASM_ARCH_DSP_H
-
-
-/*
- * for /dev/dspctl/ctl
- */
-#define OMAP_DSP_IOCTL_RESET                   1
-#define OMAP_DSP_IOCTL_RUN                     2
-#define OMAP_DSP_IOCTL_SETRSTVECT              3
-#define OMAP_DSP_IOCTL_CPU_IDLE                        4
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON                5
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF       6
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON                7
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF       8
-#define OMAP_DSP_IOCTL_GBL_IDLE                        9
-#define OMAP_DSP_IOCTL_DSPCFG                  10
-#define OMAP_DSP_IOCTL_DSPUNCFG                        11
-#define OMAP_DSP_IOCTL_TASKCNT                 12
-#define OMAP_DSP_IOCTL_POLL                    13
-#define OMAP_DSP_IOCTL_REGMEMR                 40
-#define OMAP_DSP_IOCTL_REGMEMW                 41
-#define OMAP_DSP_IOCTL_REGIOR                  42
-#define OMAP_DSP_IOCTL_REGIOW                  43
-#define OMAP_DSP_IOCTL_GETVAR                  44
-#define OMAP_DSP_IOCTL_SETVAR                  45
-#define OMAP_DSP_IOCTL_RUNLEVEL                        50
-#define OMAP_DSP_IOCTL_SUSPEND                 51
-#define OMAP_DSP_IOCTL_RESUME                  52
-#define OMAP_DSP_IOCTL_FBEN                    53
-#define OMAP_DSP_IOCTL_FBDIS                   54
-#define OMAP_DSP_IOCTL_MBSEND                  99
-
-/*
- * for taskdev
- * (ioctls below should be >= 0x10000)
- */
-#define OMAP_DSP_TASK_IOCTL_BFLSH      0x10000
-#define OMAP_DSP_TASK_IOCTL_SETBSZ     0x10001
-#define OMAP_DSP_TASK_IOCTL_LOCK       0x10002
-#define OMAP_DSP_TASK_IOCTL_UNLOCK     0x10003
-#define OMAP_DSP_TASK_IOCTL_GETNAME    0x10004
-
-/*
- * for /dev/dspctl/mem
- */
-#define OMAP_DSP_MEM_IOCTL_EXMAP       1
-#define OMAP_DSP_MEM_IOCTL_EXUNMAP     2
-#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3
-#define OMAP_DSP_MEM_IOCTL_FBEXPORT    5
-#define OMAP_DSP_MEM_IOCTL_MMUITACK    7
-#define OMAP_DSP_MEM_IOCTL_MMUINIT     9
-#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE        11
-#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE        12
-
-struct omap_dsp_mapinfo {
-       unsigned long dspadr;
-       unsigned long size;
-};
-
-/*
- * for /dev/dspctl/twch
- */
-#define OMAP_DSP_TWCH_IOCTL_MKDEV      1
-#define OMAP_DSP_TWCH_IOCTL_RMDEV      2
-#define OMAP_DSP_TWCH_IOCTL_TADD       11
-#define OMAP_DSP_TWCH_IOCTL_TDEL       12
-#define OMAP_DSP_TWCH_IOCTL_TKILL      13
-
-#define OMAP_DSP_DEVSTATE_NOTASK       0x00000001
-#define OMAP_DSP_DEVSTATE_ATTACHED     0x00000002
-#define OMAP_DSP_DEVSTATE_GARBAGE      0x00000004
-#define OMAP_DSP_DEVSTATE_INVALID      0x00000008
-#define OMAP_DSP_DEVSTATE_ADDREQ       0x00000100
-#define OMAP_DSP_DEVSTATE_DELREQ       0x00000200
-#define OMAP_DSP_DEVSTATE_ADDFAIL      0x00001000
-#define OMAP_DSP_DEVSTATE_ADDING       0x00010000
-#define OMAP_DSP_DEVSTATE_DELING       0x00020000
-#define OMAP_DSP_DEVSTATE_KILLING      0x00040000
-#define OMAP_DSP_DEVSTATE_STATE_MASK   0x7fffffff
-#define OMAP_DSP_DEVSTATE_STALE                0x80000000
-
-struct omap_dsp_taddinfo {
-       unsigned char minor;
-       unsigned long taskadr;
-};
-#define OMAP_DSP_TADD_ABORTADR 0xffffffff
-
-
-/*
- * error cause definition (for error detection device)
- */
-#define OMAP_DSP_ERRDT_WDT     0x00000001
-#define OMAP_DSP_ERRDT_MMU     0x00000002
-
-
-/*
- * mailbox protocol definitions
- */
-
-struct omap_dsp_mailbox_cmd {
-       unsigned short cmd;
-       unsigned short data;
-};
-
-struct omap_dsp_reginfo {
-       unsigned short adr;
-       unsigned short val;
-};
-
-struct omap_dsp_varinfo {
-       unsigned char varid;
-       unsigned short val[0];
-};
-
-#define OMAP_DSP_MBPROT_REVISION       0x0019
-
-#define OMAP_DSP_MBCMD_WDSND   0x10
-#define OMAP_DSP_MBCMD_WDREQ   0x11
-#define OMAP_DSP_MBCMD_BKSND   0x20
-#define OMAP_DSP_MBCMD_BKREQ   0x21
-#define OMAP_DSP_MBCMD_BKYLD   0x23
-#define OMAP_DSP_MBCMD_BKSNDP  0x24
-#define OMAP_DSP_MBCMD_BKREQP  0x25
-#define OMAP_DSP_MBCMD_TCTL    0x30
-#define OMAP_DSP_MBCMD_TCTLDATA        0x31
-#define OMAP_DSP_MBCMD_POLL    0x32
-#define OMAP_DSP_MBCMD_WDT     0x50    /* v3.3: obsolete */
-#define OMAP_DSP_MBCMD_RUNLEVEL        0x51
-#define OMAP_DSP_MBCMD_PM      0x52
-#define OMAP_DSP_MBCMD_SUSPEND 0x53
-#define OMAP_DSP_MBCMD_KFUNC   0x54
-#define OMAP_DSP_MBCMD_TCFG    0x60
-#define OMAP_DSP_MBCMD_TADD    0x62
-#define OMAP_DSP_MBCMD_TDEL    0x63
-#define OMAP_DSP_MBCMD_TSTOP   0x65
-#define OMAP_DSP_MBCMD_DSPCFG  0x70
-#define OMAP_DSP_MBCMD_REGRW   0x72
-#define OMAP_DSP_MBCMD_GETVAR  0x74
-#define OMAP_DSP_MBCMD_SETVAR  0x75
-#define OMAP_DSP_MBCMD_ERR     0x78
-#define OMAP_DSP_MBCMD_DBG     0x79
-
-#define OMAP_DSP_MBCMD_TCTL_TINIT      0x0000
-#define OMAP_DSP_MBCMD_TCTL_TEN                0x0001
-#define OMAP_DSP_MBCMD_TCTL_TDIS       0x0002
-#define OMAP_DSP_MBCMD_TCTL_TCLR       0x0003
-#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004
-
-#define OMAP_DSP_MBCMD_RUNLEVEL_USER           0x01
-#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER          0x0e
-#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY       0x10
-
-#define OMAP_DSP_MBCMD_PM_DISABLE      0x00
-#define OMAP_DSP_MBCMD_PM_ENABLE       0x01
-
-#define OMAP_DSP_MBCMD_KFUNC_FBCTL     0x00
-#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01
-
-#define OMAP_DSP_MBCMD_FBCTL_UPD       0x0000
-#define OMAP_DSP_MBCMD_FBCTL_ENABLE    0x0002
-#define OMAP_DSP_MBCMD_FBCTL_DISABLE   0x0003
-
-#define OMAP_DSP_MBCMD_AUDIO_PWR_UP    0x0000
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002
-
-#define OMAP_DSP_MBCMD_TDEL_SAFE       0x0000
-#define OMAP_DSP_MBCMD_TDEL_KILL       0x0001
-
-#define OMAP_DSP_MBCMD_DSPCFG_REQ      0x00
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH  0x28
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL  0x29
-#define OMAP_DSP_MBCMD_DSPCFG_PROTREV  0x70
-#define OMAP_DSP_MBCMD_DSPCFG_ABORT    0x78
-#define OMAP_DSP_MBCMD_DSPCFG_LAST     0x80
-
-#define OMAP_DSP_MBCMD_REGRW_MEMR      0x00
-#define OMAP_DSP_MBCMD_REGRW_MEMW      0x01
-#define OMAP_DSP_MBCMD_REGRW_IOR       0x02
-#define OMAP_DSP_MBCMD_REGRW_IOW       0x03
-#define OMAP_DSP_MBCMD_REGRW_DATA      0x04
-
-#define OMAP_DSP_MBCMD_VARID_ICRMASK   0x00
-#define OMAP_DSP_MBCMD_VARID_LOADINFO  0x01
-
-#define OMAP_DSP_TTYP_ARCV     0x0001
-#define OMAP_DSP_TTYP_ASND     0x0002
-#define OMAP_DSP_TTYP_BKMD     0x0004
-#define OMAP_DSP_TTYP_BKDM     0x0008
-#define OMAP_DSP_TTYP_PVMD     0x0010
-#define OMAP_DSP_TTYP_PVDM     0x0020
-
-#define OMAP_DSP_EID_BADTID    0x10
-#define OMAP_DSP_EID_BADTCN    0x11
-#define OMAP_DSP_EID_BADBID    0x20
-#define OMAP_DSP_EID_BADCNT    0x21
-#define OMAP_DSP_EID_NOTLOCKED 0x22
-#define OMAP_DSP_EID_STVBUF    0x23
-#define OMAP_DSP_EID_BADADR    0x24
-#define OMAP_DSP_EID_BADTCTL   0x30
-#define OMAP_DSP_EID_BADPARAM  0x50
-#define OMAP_DSP_EID_FATAL     0x58
-#define OMAP_DSP_EID_NOMEM     0xc0
-#define OMAP_DSP_EID_NORES     0xc1
-#define OMAP_DSP_EID_IPBFULL   0xc2
-#define OMAP_DSP_EID_WDT       0xd0
-#define OMAP_DSP_EID_TASKNOTRDY        0xe0
-#define OMAP_DSP_EID_TASKBSY   0xe1
-#define OMAP_DSP_EID_TASKERR   0xef
-#define OMAP_DSP_EID_BADCFGTYP 0xf0
-#define OMAP_DSP_EID_DEBUG     0xf8
-#define OMAP_DSP_EID_BADSEQ    0xfe
-#define OMAP_DSP_EID_BADCMD    0xff
-
-#define OMAP_DSP_TNM_LEN       16
-
-#define OMAP_DSP_TID_FREE      0xff
-#define OMAP_DSP_TID_ANON      0xfe
-
-#define OMAP_DSP_BID_NULL      0xffff
-#define OMAP_DSP_BID_PVT       0xfffe
-
-#endif /* ASM_ARCH_DSP_H */
index 16a459dfa714ab770da53bff8680d90a36a70d6c..c61f868f24ee8de1590c0cb0743f7a0ce8452475 100644 (file)
@@ -1,38 +1,34 @@
 /*
- * linux/include/asm-arm/arch-omap/dsp_common.h
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
  *
- * Header for OMAP DSP subsystem control
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
  *
- * Copyright (C) 2004,2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
  *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * 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.
  *
- * 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.
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  *
- * 2005/06/03:  DSP Gateway version 3.3
  */
 
 #ifndef ASM_ARCH_DSP_COMMON_H
 #define ASM_ARCH_DSP_COMMON_H
 
+#ifdef CONFIG_ARCH_OMAP1
 extern void omap_dsp_request_mpui(void);
 extern void omap_dsp_release_mpui(void);
 extern int omap_dsp_request_mem(void);
 extern int omap_dsp_release_mem(void);
-
-extern void (*omap_dsp_audio_pwr_up_request)(int stage);
-extern void (*omap_dsp_audio_pwr_down_request)(int stage);
+#endif
 
 #endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/gpio-switch.h b/include/asm-arm/arch-omap/gpio-switch.h
new file mode 100644 (file)
index 0000000..10da0e0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * GPIO switch definitions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPIO_SWITCH_H
+#define __ASM_ARCH_OMAP_GPIO_SWITCH_H
+
+#include <linux/types.h>
+
+/* Cover:
+ *     high -> closed
+ *     low  -> open
+ * Connection:
+ *     high -> connected
+ *     low  -> disconnected
+ * Activity:
+ *     high -> active
+ *     low  -> inactive
+ *
+ */
+#define OMAP_GPIO_SWITCH_TYPE_COVER            0x0000
+#define OMAP_GPIO_SWITCH_TYPE_CONNECTION       0x0001
+#define OMAP_GPIO_SWITCH_TYPE_ACTIVITY         0x0002
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED         0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT           0x0002
+
+struct omap_gpio_switch {
+       const char *name;
+       s16 gpio;
+       unsigned flags:4;
+       unsigned type:4;
+
+       /* Time in ms to debounce when transitioning from
+        * inactive state to active state. */
+       u16 debounce_rising;
+       /* Same for transition from active to inactive state. */
+       u16 debounce_falling;
+
+       /* notify board-specific code about state changes */
+       void (* notify)(void *data, int state);
+       void *notify_data;
+};
+
+/* Call at init time only */
+extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+                                       int count);
+
+#endif
index 590917efc94acdecca3be6fad273f31b24a9ef41..97b397dd7e87934dda0d57d68f37897fbbc7496e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2003-2005 Nokia Corporation
  *
- * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
  *
  * 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
index 7c03ef6c14c4f6e7d4391bb5275ef9be61045aec..995cc83482eb3d71e2624faac2b4acbb34695c7f 100644 (file)
@@ -87,5 +87,7 @@ extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
 extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
 extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
 extern void gpmc_cs_free(int cs);
+extern int gpmc_cs_set_reserved(int cs, int reserved);
+extern int gpmc_cs_reserved(int cs);
 
 #endif
index 481048d65214815d85b22568b742995f3ea3269d..e225f4f39b34920c6c29ee182dcbe47e02798766 100644 (file)
 #define OMAP_LPG2_LCR                  (OMAP_LPG2_BASE + 0x00)
 #define OMAP_LPG2_PMR                  (OMAP_LPG2_BASE + 0x04)
 
+/*
+ * ----------------------------------------------------------------------------
+ * Pulse-Width Light
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_PWL_BASE                  0xfffb5800
+#define OMAP_PWL_ENABLE                        (OMAP_PWL_BASE + 0x00)
+#define OMAP_PWL_CLK_ENABLE            (OMAP_PWL_BASE + 0x04)
+
 /*
  * ---------------------------------------------------------------------------
  * Processor specific defines
diff --git a/include/asm-arm/arch-omap/hwa742.h b/include/asm-arm/arch-omap/hwa742.h
new file mode 100644 (file)
index 0000000..577f492
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _HWA742_H
+#define _HWA742_H
+
+struct hwa742_platform_data {
+       void            (*power_up)(struct device *dev);
+       void            (*power_down)(struct device *dev);
+       unsigned long   (*get_clock_rate)(struct device *dev);
+
+       unsigned        te_connected:1;
+};
+
+#endif
index 78f68e6a4f0c59a24407cd7fbe8c905dea0b97ec..4aca7e3d7566c1b9619e9ce60ec598fde09e8a82 100644 (file)
 #define io_p2v(pa)     ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
 #define io_v2p(va)     ((va) - IO_OFFSET)      /* Works for L3 and L4 */
 
+/* DSP */
+#define DSP_MEM_24XX_PHYS      OMAP24XX_DSP_MEM_BASE   /* 0x58000000 */
+#define DSP_MEM_24XX_VIRT      0xe0000000
+#define DSP_MEM_24XX_SIZE      0x28000
+#define DSP_IPI_24XX_PHYS      OMAP24XX_DSP_IPI_BASE   /* 0x59000000 */
+#define DSP_IPI_24XX_VIRT      0xe1000000
+#define DSP_IPI_24XX_SIZE      SZ_4K
+#define DSP_MMU_24XX_PHYS      OMAP24XX_DSP_MMU_BASE   /* 0x5a000000 */
+#define DSP_MMU_24XX_VIRT      0xe2000000
+#define DSP_MMU_24XX_SIZE      SZ_4K
+
 #endif
 
 #ifndef __ASSEMBLER__
index c5bb05a69b81ec815c405d79b8b3bd553e29abc3..3ede58b51db28f36688e451d173b51b1fffc12ab 100644 (file)
@@ -37,8 +37,6 @@
 #define INT_DSP_MMU_ABORT      7
 #define INT_HOST               8
 #define INT_ABORT              9
-#define INT_DSP_MAILBOX1       10
-#define INT_DSP_MAILBOX2       11
 #define INT_BRIDGE_PRIV                13
 #define INT_GPIO_BANK1         14
 #define INT_UART3              15
@@ -63,6 +61,8 @@
 #define INT_1510_RES2          2
 #define INT_1510_SPI_TX                4
 #define INT_1510_SPI_RX                5
+#define INT_1510_DSP_MAILBOX1  10
+#define INT_1510_DSP_MAILBOX2  11
 #define INT_1510_RES12         12
 #define INT_1510_LB_MMU                17
 #define INT_1510_RES18         18
@@ -75,6 +75,8 @@
 #define INT_1610_IH2_FIQ       2
 #define INT_1610_McBSP2_TX     4
 #define INT_1610_McBSP2_RX     5
+#define INT_1610_DSP_MAILBOX1  10
+#define INT_1610_DSP_MAILBOX2  11
 #define INT_1610_LCD_LINE      12
 #define INT_1610_GPTIMER1      17
 #define INT_1610_GPTIMER2      18
 #define INT_RTC_TIMER          (25 + IH2_BASE)
 #define INT_RTC_ALARM          (26 + IH2_BASE)
 #define INT_MEM_STICK          (27 + IH2_BASE)
-#define INT_DSP_MMU            (28 + IH2_BASE)
 
 /*
  * OMAP-1510 specific IRQ numbers for interrupt handler 2
  */
+#define INT_1510_DSP_MMU       (28 + IH2_BASE)
 #define INT_1510_COM_SPI_RO    (31 + IH2_BASE)
 
 /*
 #define INT_1610_USB_OTG       (8 + IH2_BASE)
 #define INT_1610_SoSSI         (9 + IH2_BASE)
 #define INT_1610_SoSSI_MATCH   (19 + IH2_BASE)
+#define INT_1610_DSP_MMU       (28 + IH2_BASE)
 #define INT_1610_McBSP2RX_OF   (31 + IH2_BASE)
 #define INT_1610_STI           (32 + IH2_BASE)
 #define INT_1610_STI_WAKEUP    (33 + IH2_BASE)
 #define INT_24XX_SDMA_IRQ3     15
 #define INT_24XX_CAM_IRQ       24
 #define INT_24XX_DSS_IRQ       25
+#define INT_24XX_MAIL_U0_MPU   26
+#define INT_24XX_DSP_UMA       27
+#define INT_24XX_DSP_MMU       28
 #define INT_24XX_GPIO_BANK1    29
 #define INT_24XX_GPIO_BANK2    30
 #define INT_24XX_GPIO_BANK3    31
 #define INT_24XX_GPIO_BANK4    32
+#define INT_24XX_GPIO_BANK5    33
+#define INT_24XX_MAIL_U3_MPU   34
 #define INT_24XX_GPTIMER1      37
 #define INT_24XX_GPTIMER2      38
 #define INT_24XX_GPTIMER3      39
 #define INT_24XX_UART1_IRQ     72
 #define INT_24XX_UART2_IRQ     73
 #define INT_24XX_UART3_IRQ     74
+#define INT_24XX_USB_IRQ_GEN   75
+#define INT_24XX_USB_IRQ_NISO  76
+#define INT_24XX_USB_IRQ_ISO   77
+#define INT_24XX_USB_IRQ_HGEN  78
+#define INT_24XX_USB_IRQ_HSOF  79
+#define INT_24XX_USB_IRQ_OTG   80
 #define INT_24XX_MMC_IRQ       83
 
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
deleted file mode 100644 (file)
index 004e67e..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LCD_LPH8923_H
-#define __LCD_LPH8923_H
-
-enum lcd_lph8923_test_num {
-       LCD_LPH8923_TEST_RGB_LINES,
-};
-
-enum lcd_lph8923_test_result {
-       LCD_LPH8923_TEST_SUCCESS,
-       LCD_LPH8923_TEST_INVALID,
-       LCD_LPH8923_TEST_FAILED,
-};
-
-#endif
diff --git a/include/asm-arm/arch-omap/lcd_mipid.h b/include/asm-arm/arch-omap/lcd_mipid.h
new file mode 100644 (file)
index 0000000..f8fbc48
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __LCD_MIPID_H
+#define __LCD_MIPID_H
+
+enum mipid_test_num {
+       MIPID_TEST_RGB_LINES,
+};
+
+enum mipid_test_result {
+       MIPID_TEST_SUCCESS,
+       MIPID_TEST_INVALID,
+       MIPID_TEST_FAILED,
+};
+
+#ifdef __KERNEL__
+
+struct mipid_platform_data {
+       int     nreset_gpio;
+       int     data_lines;
+       void    (*shutdown)(struct mipid_platform_data *pdata);
+};
+
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-omap/led.h b/include/asm-arm/arch-omap/led.h
new file mode 100644 (file)
index 0000000..f3acae2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *  linux/include/asm-arm/arch-omap/led.h
+ *
+ *  Copyright (C) 2006 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * 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.
+ */
+#ifndef ASMARM_ARCH_LED_H
+#define ASMARM_ARCH_LED_H
+
+struct omap_led_config {
+       struct led_classdev     cdev;
+       s16                     gpio;
+};
+
+struct omap_led_platform_data {
+       s16                     nr_leds;
+       struct omap_led_config  *leds;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/mailbox.h b/include/asm-arm/arch-omap/mailbox.h
new file mode 100644 (file)
index 0000000..4bf0909
--- /dev/null
@@ -0,0 +1,73 @@
+/* mailbox.h */
+
+#ifndef MAILBOX_H
+#define MAILBOX_H
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/blkdev.h>
+
+typedef u32 mbox_msg_t;
+typedef void (mbox_receiver_t)(mbox_msg_t msg);
+struct omap_mbox;
+
+typedef int __bitwise omap_mbox_irq_t;
+#define IRQ_TX ((__force omap_mbox_irq_t) 1)
+#define IRQ_RX ((__force omap_mbox_irq_t) 2)
+
+typedef int __bitwise omap_mbox_type_t;
+#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1)
+#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2)
+
+struct omap_mbox_ops {
+       omap_mbox_type_t        type;
+       int             (*startup)(struct omap_mbox *mbox);
+       void            (*shutdown)(struct omap_mbox *mbox);
+       /* fifo */
+       mbox_msg_t      (*fifo_read)(struct omap_mbox *mbox);
+       void            (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
+       int             (*fifo_empty)(struct omap_mbox *mbox);
+       int             (*fifo_full)(struct omap_mbox *mbox);
+       /* irq */
+       void            (*enable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+       void            (*disable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+       void            (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+       int             (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+};
+
+struct omap_mbox_queue {
+       spinlock_t              lock;
+       request_queue_t         *queue;
+       struct work_struct      work;
+       int     (*callback)(void *);
+       struct omap_mbox        *mbox;
+};
+
+struct omap_mbox {
+       char                    *name;
+       unsigned int            irq;
+
+       struct omap_mbox_queue  *txq, *rxq;
+
+       struct omap_mbox_ops    *ops;
+
+       mbox_msg_t              seq_snd, seq_rcv;
+
+       struct device           dev;
+
+       struct omap_mbox        *next;
+       void                    *priv;
+
+       void                    (*err_notify)(void);
+};
+
+int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg, void *);
+void omap_mbox_init_seq(struct omap_mbox *);
+
+struct omap_mbox *omap_mbox_get(const char *);
+void omap_mbox_put(struct omap_mbox *);
+
+int omap_mbox_register(struct omap_mbox *);
+int omap_mbox_unregister(struct omap_mbox *);
+
+#endif /* MAILBOX_H */
index 9e7f40a88e1b2be0d2d8cabe4fe98a89ddd101e3..1254e4945b6f85d9ede13b23a0df4b99be6e9118 100644 (file)
@@ -2,7 +2,6 @@
 #define _OMAP2_MCSPI_H
 
 struct omap2_mcspi_platform_config {
-       unsigned long   base;
        unsigned short  num_cs;
 };
 
index 48fabc493163fc44c004e8dcac03d86ff6c9ecae..14cba97c18ad061973876d1763aed27c7d8647ba 100644 (file)
 
 #endif /* CONFIG_ARCH_OMAP15XX */
 
+/* Override the ARM default */
+#ifdef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+
+#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0)
+#undef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 2
+#endif
+
+#define CONSISTENT_DMA_SIZE \
+       (((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+
+#endif
+
 #endif
 
index 88cd4c87f0decd72f22a5ba1d5f012911ff59933..82d276a6bd95b6f8f867ec22fe6b463a5fb32045 100644 (file)
@@ -7,10 +7,19 @@
 #ifndef __ASM_ARCH_MENELAUS_H
 #define __ASM_ARCH_MENELAUS_H
 
-extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
-                                 unsigned long data);
-extern void menelaus_mmc_remove(void);
-extern void menelaus_mmc_opendrain(int enable);
+extern int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+                                         void *data);
+extern void menelaus_unregister_mmc_callback(void);
+extern int menelaus_set_mmc_opendrain(int slot, int enable);
+extern int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_on);
+
+extern int menelaus_set_vmem(unsigned int mV);
+extern int menelaus_set_vio(unsigned int mV);
+extern int menelaus_set_vmmc(unsigned int mV);
+extern int menelaus_set_vaux(unsigned int mV);
+extern int menelaus_set_vdcdc(int dcdc, unsigned int mV);
+extern int menelaus_set_slot_sel(int enable);
+extern int menelaus_get_slot_pin_states(void);
 
 #if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
 #define omap_has_menelaus()    1
index f0c7f0fb4dc032e2a8c2303714b49504c3b7235b..f7f5cdfdccce4f40a4a6a2c9e54240f76864ae49 100644 (file)
 #define UART3_OSC_12M_SEL       (OMAP_UART3_BASE + 0x4C)
 #define UART3_MVR               (OMAP_UART3_BASE + 0x50)
 
-/*
- * ----------------------------------------------------------------------------
- * Pulse-Width Light
- * ----------------------------------------------------------------------------
- */
-#define OMAP16XX_PWL_BASE      (0xfffb5800)
-#define OMAP16XX_PWL_ENABLE    (OMAP16XX_PWL_BASE + 0x00)
-#define OMAP16XX_PWL_CLK_ENABLE        (OMAP16XX_PWL_BASE + 0x04)
-
 /*
  * ---------------------------------------------------------------------------
  * Watchdog timer
 #define WSPR_DISABLE_0         (0x0000aaaa)
 #define WSPR_DISABLE_1         (0x00005555)
 
+/* Mailbox */
+#define OMAP16XX_MAILBOX_BASE  (0xfffcf000)
+
 #endif /*  __ASM_ARCH_OMAP16XX_H */
 
index 6e59805fa6545b8c3edeef8be3e2378b8fb0cf19..708b2fac77f21e7b92544d77e06ca685ab97cef1 100644 (file)
 #define OMAP24XX_PRCM_BASE     (L4_24XX_BASE + 0x8000)
 #define OMAP24XX_SDRC_BASE     (L3_24XX_BASE + 0x9000)
 
+/* DSP SS */
+#define OMAP24XX_DSP_BASE      0x58000000
+#define OMAP24XX_DSP_MEM_BASE  (OMAP24XX_DSP_BASE + 0x0)
+#define OMAP24XX_DSP_IPI_BASE  (OMAP24XX_DSP_BASE + 0x1000000)
+#define OMAP24XX_DSP_MMU_BASE  (OMAP24XX_DSP_BASE + 0x2000000)
+
+/* Mailbox */
+#define OMAP24XX_MAILBOX_BASE  (L4_24XX_BASE + 0x94000)
+
 #endif /* __ASM_ARCH_OMAP24XX_H */
 
index fccdb3db025ff0dc79fd08dc4c5d7a0a27f0d1d3..46d7a4f6085495ec4d86274b61d8a90146cc92fc 100644 (file)
@@ -24,6 +24,9 @@
 #ifndef __OMAPFB_H
 #define __OMAPFB_H
 
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 /* IOCTL commands. */
 
 #define OMAP_IOW(num, dtype)   _IOW('O', num, dtype)
 #define OMAPFB_SYNC_GFX                OMAP_IO(37)
 #define OMAPFB_VSYNC           OMAP_IO(38)
 #define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
-#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
-#define OMAPFB_GET_CAPS                OMAP_IOR(42, unsigned long)
+#define OMAPFB_GET_CAPS                OMAP_IOR(42, struct omapfb_caps)
 #define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
 #define OMAPFB_LCD_TEST                OMAP_IOW(45, int)
 #define OMAPFB_CTRL_TEST       OMAP_IOW(46, int)
-#define OMAPFB_UPDATE_WINDOW   OMAP_IOW(47, struct omapfb_update_window)
-#define OMAPFB_SETUP_PLANE     OMAP_IOW(48, struct omapfb_setup_plane)
-#define OMAPFB_ENABLE_PLANE    OMAP_IOW(49, struct omapfb_enable_plane)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
 #define OMAPFB_SET_COLOR_KEY   OMAP_IOW(50, struct omapfb_color_key)
+#define OMAPFB_GET_COLOR_KEY   OMAP_IOW(51, struct omapfb_color_key)
+#define OMAPFB_SETUP_PLANE     OMAP_IOW(52, struct omapfb_plane_info)
+#define OMAPFB_QUERY_PLANE     OMAP_IOW(53, struct omapfb_plane_info)
+#define OMAPFB_UPDATE_WINDOW   OMAP_IOW(54, struct omapfb_update_window)
+#define OMAPFB_SETUP_MEM       OMAP_IOW(55, struct omapfb_mem_info)
+#define OMAPFB_QUERY_MEM       OMAP_IOW(56, struct omapfb_mem_info)
 
 #define OMAPFB_CAPS_GENERIC_MASK       0x00000fff
 #define OMAPFB_CAPS_LCDC_MASK          0x00fff000
 #define OMAPFB_CAPS_PANEL_MASK         0xff000000
 
 #define OMAPFB_CAPS_MANUAL_UPDATE      0x00001000
+#define OMAPFB_CAPS_TEARSYNC           0x00002000
+#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
+#define OMAPFB_CAPS_PLANE_SCALE                0x00008000
+#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE        0x00010000
+#define OMAPFB_CAPS_WINDOW_SCALE       0x00020000
+#define OMAPFB_CAPS_WINDOW_OVERLAY     0x00040000
 #define OMAPFB_CAPS_SET_BACKLIGHT      0x01000000
 
 /* Values from DSP must map to lower 16-bits */
-#define OMAPFB_FORMAT_MASK         0x00ff
-#define OMAPFB_FORMAT_FLAG_DOUBLE  0x0100
+#define OMAPFB_FORMAT_MASK             0x00ff
+#define OMAPFB_FORMAT_FLAG_DOUBLE      0x0100
+#define OMAPFB_FORMAT_FLAG_TEARSYNC    0x0200
+#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
+#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY      0x0800
+#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY     0x1000
+
+#define OMAPFB_EVENT_READY     1
+#define OMAPFB_EVENT_DISABLED  2
+
+#define OMAPFB_MEMTYPE_SDRAM           0
+#define OMAPFB_MEMTYPE_SRAM            1
+#define OMAPFB_MEMTYPE_MAX             1
 
 enum omapfb_color_format {
        OMAPFB_COLOR_RGB565 = 0,
@@ -64,17 +87,23 @@ enum omapfb_color_format {
        OMAPFB_COLOR_CLUT_4BPP,
        OMAPFB_COLOR_CLUT_2BPP,
        OMAPFB_COLOR_CLUT_1BPP,
+       OMAPFB_COLOR_RGB444,
+       OMAPFB_COLOR_YUY422,
 };
 
 struct omapfb_update_window {
        __u32 x, y;
        __u32 width, height;
        __u32 format;
+       __u32 out_x, out_y;
+       __u32 out_width, out_height;
+       __u32 reserved[8];
 };
 
 struct omapfb_update_window_old {
        __u32 x, y;
        __u32 width, height;
+       __u32 format;
 };
 
 enum omapfb_plane {
@@ -88,18 +117,28 @@ enum omapfb_channel_out {
        OMAPFB_CHANNEL_OUT_DIGIT,
 };
 
-struct omapfb_setup_plane {
-       __u8  plane;
+struct omapfb_plane_info {
+       __u32 pos_x;
+       __u32 pos_y;
+       __u8  enabled;
        __u8  channel_out;
-       __u32 offset;
-       __u32 pos_x, pos_y;
-       __u32 width, height;
-       __u32 color_mode;
+       __u8  mirror;
+       __u8  reserved1;
+       __u32 out_width;
+       __u32 out_height;
+       __u32 reserved2[12];
 };
 
-struct omapfb_enable_plane {
-       __u8  plane;
-       __u8  enable;
+struct omapfb_mem_info {
+       __u32 size;
+       __u8  type;
+       __u8  reserved[3];
+};
+
+struct omapfb_caps {
+       __u32 ctrl;
+       __u32 plane_color;
+       __u32 wnd_color;
 };
 
 enum omapfb_color_key_type {
@@ -141,6 +180,9 @@ enum omapfb_update_mode {
 
 #define OMAP_LCDC_PANEL_TFT            0x0100
 
+#define OMAPFB_PLANE_XRES_MIN          8
+#define OMAPFB_PLANE_YRES_MIN          8
+
 #ifdef CONFIG_ARCH_OMAP1
 #define OMAPFB_PLANE_NUM               1
 #else
@@ -169,19 +211,19 @@ struct lcd_panel {
        int             pcd;            /* pixel clock divider.
                                           Obsolete use pixel_clock instead */
 
-       int             (*init)         (struct omapfb_device *fbdev);
-       void            (*cleanup)      (void);
-       int             (*enable)       (void);
-       void            (*disable)      (void);
-       unsigned long   (*get_caps)     (void);
-       int             (*set_bklight_level)(unsigned int level);
-       unsigned int    (*get_bklight_level)(void);
-       unsigned int    (*get_bklight_max)  (void);
-       int             (*run_test)     (int test_num);
+       int             (*init)         (struct lcd_panel *panel,
+                                        struct omapfb_device *fbdev);
+       void            (*cleanup)      (struct lcd_panel *panel);
+       int             (*enable)       (struct lcd_panel *panel);
+       void            (*disable)      (struct lcd_panel *panel);
+       unsigned long   (*get_caps)     (struct lcd_panel *panel);
+       int             (*set_bklight_level)(struct lcd_panel *panel,
+                                            unsigned int level);
+       unsigned int    (*get_bklight_level)(struct lcd_panel *panel);
+       unsigned int    (*get_bklight_max)  (struct lcd_panel *panel);
+       int             (*run_test)     (struct lcd_panel *panel, int test_num);
 };
 
-struct omapfb_device;
-
 struct extif_timings {
        int cs_on_time;
        int cs_off_time;
@@ -202,9 +244,10 @@ struct extif_timings {
 };
 
 struct lcd_ctrl_extif {
-       int  (*init)            (void);
+       int  (*init)            (struct omapfb_device *fbdev);
        void (*cleanup)         (void);
        void (*get_clk_info)    (u32 *clk_period, u32 *max_clk_div);
+       unsigned long (*get_max_tx_rate)(void);
        int  (*convert_timings) (struct extif_timings *timings);
        void (*set_timings)     (const struct extif_timings *timings);
        void (*set_bits_per_cycle)(int bpc);
@@ -213,31 +256,48 @@ struct lcd_ctrl_extif {
        void (*write_data)      (const void *buf, unsigned int len);
        void (*transfer_area)   (int width, int height,
                                 void (callback)(void * data), void *data);
+       int  (*setup_tearsync)  (unsigned pin_cnt,
+                                unsigned hs_pulse_time, unsigned vs_pulse_time,
+                                int hs_pol_inv, int vs_pol_inv, int div);
+       int  (*enable_tearsync) (int enable, unsigned line);
+
        unsigned long           max_transmit_size;
 };
 
 struct omapfb_notifier_block {
        struct notifier_block   nb;
        void                    *data;
+       int                     plane_idx;
 };
 
-typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
-                                          unsigned long event,
-                                          struct omapfb_device *fbdev);
+typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
+                                         unsigned long event,
+                                         void *fbi);
+
+struct omapfb_mem_region {
+       dma_addr_t      paddr;
+       void            *vaddr;
+       unsigned long   size;
+       u8              type;           /* OMAPFB_PLANE_MEM_* */
+       unsigned        alloc:1;        /* allocated by the driver */
+       unsigned        map:1;          /* kernel mapped by the driver */
+};
+
+struct omapfb_mem_desc {
+       int                             region_cnt;
+       struct omapfb_mem_region        region[OMAPFB_PLANE_NUM];
+};
 
 struct lcd_ctrl {
        const char      *name;
        void            *data;
 
        int             (*init)           (struct omapfb_device *fbdev,
-                                          int ext_mode, int req_vram_size);
+                                          int ext_mode,
+                                          struct omapfb_mem_desc *req_md);
        void            (*cleanup)        (void);
        void            (*bind_client)    (struct omapfb_notifier_block *nb);
-       void            (*get_vram_layout)(unsigned long *size,
-                                          void **virt_base,
-                                          dma_addr_t *phys_base);
-       int             (*mmap)           (struct vm_area_struct *vma);
-       unsigned long   (*get_caps)       (void);
+       void            (*get_caps)       (int plane, struct omapfb_caps *caps);
        int             (*set_update_mode)(enum omapfb_update_mode mode);
        enum omapfb_update_mode (*get_update_mode)(void);
        int             (*setup_plane)    (int plane, int channel_out,
@@ -245,8 +305,16 @@ struct lcd_ctrl {
                                           int screen_width,
                                           int pos_x, int pos_y, int width,
                                           int height, int color_mode);
+       int             (*setup_mem)      (int plane, size_t size,
+                                          int mem_type, unsigned long *paddr);
+       int             (*mmap)           (struct fb_info *info,
+                                          struct vm_area_struct *vma);
+       int             (*set_scale)      (int plane,
+                                          int orig_width, int orig_height,
+                                          int out_width, int out_height);
        int             (*enable_plane)   (int plane, int enable);
-       int             (*update_window)  (struct omapfb_update_window *win,
+       int             (*update_window)  (struct fb_info *fbi,
+                                          struct omapfb_update_window *win,
                                           void (*callback)(void *),
                                           void *callback_data);
        void            (*sync)           (void);
@@ -257,7 +325,7 @@ struct lcd_ctrl {
                                           u16 blue, u16 transp,
                                           int update_hw_mem);
        int             (*set_color_key)  (struct omapfb_color_key *ck);
-
+       int             (*get_color_key)  (struct omapfb_color_key *ck);
 };
 
 enum omapfb_state {
@@ -266,19 +334,20 @@ enum omapfb_state {
        OMAPFB_ACTIVE   = 100
 };
 
+struct omapfb_plane_struct {
+       int                             idx;
+       struct omapfb_plane_info        info;
+       enum omapfb_color_format        color_mode;
+       struct omapfb_device            *fbdev;
+};
+
 struct omapfb_device {
        int                     state;
        int                     ext_lcdc;               /* Using external
                                                            LCD controller */
        struct mutex            rqueue_mutex;
 
-       void                    *vram_virt_base;
-       dma_addr_t              vram_phys_base;
-       unsigned long           vram_size;
-
-       int                     color_mode;
        int                     palette_size;
-       int                     mirror;
        u32                     pseudo_palette[17];
 
        struct lcd_panel        *panel;                 /* LCD panel */
@@ -286,19 +355,19 @@ struct omapfb_device {
        struct lcd_ctrl         *int_ctrl;              /* internal LCD ctrl */
        struct lcd_ctrl_extif   *ext_if;                /* LCD ctrl external
                                                           interface */
-       struct fb_info          *fb_info;
-
        struct device           *dev;
+       struct fb_var_screeninfo        new_var;        /* for mode changes */
+
+       struct omapfb_mem_desc          mem_desc;
+       struct fb_info                  *fb_info[OMAPFB_PLANE_NUM];
 };
 
 struct omapfb_platform_data {
-       struct omap_lcd_config   lcd;
-       struct omap_fbmem_config fbmem;
+       struct omap_lcd_config          lcd;
+       struct omapfb_mem_desc          mem_desc;
+       void                            *ctrl_platform_data;
 };
 
-#define OMAPFB_EVENT_READY     1
-#define OMAPFB_EVENT_DISABLED  2
-
 #ifdef CONFIG_ARCH_OMAP1
 extern struct lcd_ctrl omap1_lcd_ctrl;
 #else
@@ -310,15 +379,16 @@ extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
 extern void omapfb_notify_clients(struct omapfb_device *fbdev,
                                  unsigned long event);
 extern int  omapfb_register_client(struct omapfb_notifier_block *nb,
-                                   omapfb_notifier_callback_t callback,
-                                   void *callback_data);
+                                  omapfb_notifier_callback_t callback,
+                                  void *callback_data);
 extern int  omapfb_unregister_client(struct omapfb_notifier_block *nb);
-extern int  omapfb_update_window_async(struct omapfb_update_window *win,
-                                       void (*callback)(void *),
-                                       void *callback_data);
+extern int  omapfb_update_window_async(struct fb_info *fbi,
+                                      struct omapfb_update_window *win,
+                                      void (*callback)(void *),
+                                      void *callback_data);
 
-/* in arch/arm/plat-omap/devices.c */
-extern void omapfb_reserve_mem(void);
+/* in arch/arm/plat-omap/fb.c */
+extern void omapfb_set_ctrl_platform_data(void *pdata);
 
 #endif /* __KERNEL__ */
 
index 6fc0dd57b7c383ae69c6aea14679e4f6c5bc1115..bb9bb3fd532f7c88e715db8fe4ddf48f4507844e 100644 (file)
@@ -20,9 +20,6 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                      u32 mem_type);
 extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
 
-extern unsigned long omap_fb_sram_start;
-extern unsigned long omap_fb_sram_size;
-
 /* Do not use these */
 extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
 extern unsigned long sram_reprogram_clock_sz;
index 054fb9a8e0c684052ec4046be5c887c61538582b..99ae9eabaf71bb3740aabe11cc6b2667065d91f5 100644 (file)
@@ -7,9 +7,27 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define OTG_BASE                       0xfffb0400
-#define UDC_BASE                       0xfffb4000
-#define OMAP_OHCI_BASE                 0xfffba000
+#define OMAP1_OTG_BASE                 0xfffb0400
+#define OMAP1_UDC_BASE                 0xfffb4000
+#define OMAP1_OHCI_BASE                        0xfffba000
+
+#define OMAP2_OHCI_BASE                        0x4805e000
+#define OMAP2_UDC_BASE                 0x4805e200
+#define OMAP2_OTG_BASE                 0x4805e300
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#define OTG_BASE                       OMAP1_OTG_BASE
+#define UDC_BASE                       OMAP1_UDC_BASE
+#define OMAP_OHCI_BASE                 OMAP1_OHCI_BASE
+
+#else
+
+#define OTG_BASE                       OMAP2_OTG_BASE
+#define UDC_BASE                       OMAP2_UDC_BASE
+#define OMAP_OHCI_BASE                 OMAP2_OHCI_BASE
+
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -28,6 +46,7 @@
 #      define   HST_IDLE_EN            (1 << 14)
 #      define   DEV_IDLE_EN            (1 << 13)
 #      define   OTG_RESET_DONE         (1 << 2)
+#      define   OTG_SOFT_RESET         (1 << 1)
 #define OTG_SYSCON_2_REG               OTG_REG32(0x08)
 #      define   OTG_EN                 (1 << 31)
 #      define   USBX_SYNCHRO           (1 << 30)
 
 /*-------------------------------------------------------------------------*/
 
+/* OMAP1 */
 #define        USB_TRANSCEIVER_CTRL_REG        __REG32(0xfffe1000 + 0x0064)
 #      define  CONF_USB2_UNI_R         (1 << 8)
 #      define  CONF_USB1_UNI_R         (1 << 7)
 #      define  CONF_USB_PWRDN_DM_R     (1 << 2)
 #      define  CONF_USB_PWRDN_DP_R     (1 << 1)
 
-
-
+/* OMAP2 */
+#define        CONTROL_DEVCONF_REG             __REG32(L4_24XX_BASE + 0x0274)
+#      define  USB_UNIDIR                      0x0
+#      define  USB_UNIDIR_TLL                  0x1
+#      define  USB_BIDIR                       0x2
+#      define  USB_BIDIR_TLL                   0x3
+#      define  USBT0WRMODEI(x)         ((x) << 22)
+#      define  USBT1WRMODEI(x)         ((x) << 20)
+#      define  USBT2WRMODEI(x)         ((x) << 18)
+#      define  USBT2TLL5PI             (1 << 17)
+#      define  USB0PUENACTLOI          (1 << 16)
+#      define  USBSTANDBYCTRL          (1 << 15)
 
 #endif /* __ASM_ARCH_OMAP_USB_H */
index 6c319ea2afac3044d446003c0a624c6a2b26782c..94ff96505b6aadac08a88e0d6d171e4d242db7f1 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-power.h
+/* linux/include/asm-arm/arch-s3c2410/regs-power.h
  *
  * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
  *                   http://armlinux.simtec.co.uk/
index ff0536d2de42644c6ab6e371ba676bcbc4748679..cd9e26568f858254fd15f3895d083a7782567fee 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
+/* linux/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
  *
  * Copyright (c) 2007 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
index f4fff448c7bdc808b4d915ba466b39f1c2421d44..a9c5d491bdb6b691c40261c724aec6a72149d51a 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-watchdog.h
+/* linux/include/asm-arm/arch-s3c2410/regs-watchdog.h
  *
  * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
  *                   http://www.simtec.co.uk/products/SWLINUX/
index e59ec339d614158411209029e06b81b1079eb048..b8aa6cb69b58ec5c8a7269ea9e2a54398db00d9d 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/udc.h
+/* linux/include/asm-arm/arch-s3c2410/udc.h
  *
  * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
  *
index afad32c76e6c964df908c6493441139ccb328977..d1294a46c70c62237c9d0e266d90c645f1182bf0 100644 (file)
 //# endif
 #endif
 
+#if defined(CONFIG_CPU_V7)
+//# ifdef _CACHE
+#  define MULTI_CACHE 1
+//# else
+//#  define _CACHE v7
+//# endif
+#endif
+
 #if !defined(_CACHE) && !defined(MULTI_CACHE)
 #error Unknown cache maintainence model
 #endif
@@ -418,11 +426,19 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
  */
 #define flush_icache_page(vma,page)    do { } while (0)
 
-#define __cacheid_present(val)         (val != read_cpuid(CPUID_ID))
-#define __cacheid_vivt(val)            ((val & (15 << 25)) != (14 << 25))
-#define __cacheid_vipt(val)            ((val & (15 << 25)) == (14 << 25))
-#define __cacheid_vipt_nonaliasing(val)        ((val & (15 << 25 | 1 << 23)) == (14 << 25))
-#define __cacheid_vipt_aliasing(val)   ((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+#define __cacheid_present(val)                 (val != read_cpuid(CPUID_ID))
+#define __cacheid_type_v7(val)                 ((val & (7 << 29)) == (4 << 29))
+
+#define __cacheid_vivt_prev7(val)              ((val & (15 << 25)) != (14 << 25))
+#define __cacheid_vipt_prev7(val)              ((val & (15 << 25)) == (14 << 25))
+#define __cacheid_vipt_nonaliasing_prev7(val)  ((val & (15 << 25 | 1 << 23)) == (14 << 25))
+#define __cacheid_vipt_aliasing_prev7(val)     ((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+
+#define __cacheid_vivt(val)                    (__cacheid_type_v7(val) ? 0 : __cacheid_vivt_prev7(val))
+#define __cacheid_vipt(val)                    (__cacheid_type_v7(val) ? 1 : __cacheid_vipt_prev7(val))
+#define __cacheid_vipt_nonaliasing(val)                (__cacheid_type_v7(val) ? 1 : __cacheid_vipt_nonaliasing_prev7(val))
+#define __cacheid_vipt_aliasing(val)           (__cacheid_type_v7(val) ? 0 : __cacheid_vipt_aliasing_prev7(val))
+#define __cacheid_vivt_asid_tagged_instr(val)  (__cacheid_type_v7(val) ? ((val & (3 << 14)) == (1 << 14)) : 0)
 
 #if defined(CONFIG_CPU_CACHE_VIVT) && !defined(CONFIG_CPU_CACHE_VIPT)
 
@@ -430,6 +446,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
 #define cache_is_vipt()                        0
 #define cache_is_vipt_nonaliasing()    0
 #define cache_is_vipt_aliasing()       0
+#define icache_is_vivt_asid_tagged()   0
 
 #elif defined(CONFIG_CPU_CACHE_VIPT)
 
@@ -447,6 +464,12 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
                __cacheid_vipt_aliasing(__val);                         \
        })
 
+#define icache_is_vivt_asid_tagged()                                   \
+       ({                                                              \
+               unsigned int __val = read_cpuid(CPUID_CACHETYPE);       \
+               __cacheid_vivt_asid_tagged_instr(__val);                \
+       })
+
 #else
 
 #define cache_is_vivt()                                                        \
@@ -475,6 +498,13 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
                 __cacheid_vipt_aliasing(__val);                        \
        })
 
+#define icache_is_vivt_asid_tagged()                                   \
+       ({                                                              \
+               unsigned int __val = read_cpuid(CPUID_CACHETYPE);       \
+               __cacheid_present(__val) &&                             \
+                __cacheid_vivt_asid_tagged_instr(__val);               \
+       })
+
 #endif
 
 #endif
index abfb75b654c7df7f8795b1f0db4ea4aa173fd0e8..c8b5d0db0cf08d8580efdffed8227dbf83f0624f 100644 (file)
@@ -445,7 +445,7 @@ extern void dmabounce_unregister_dev(struct device *);
  *
  * The dmabounce routines call this function whenever a dma-mapping
  * is requested to determine whether a given buffer needs to be bounced
- * or not. The function must return 0 if the the buffer is OK for
+ * or not. The function must return 0 if the buffer is OK for
  * DMA access and 1 if the buffer needs to be bounced.
  *
  */
index 0cc5d3b10ce2fb888a7735eb17e1e65a620514aa..22274ce8137509175dcd2664e2632edac0a167e7 100644 (file)
@@ -38,6 +38,7 @@
  *       v5tej_early   - ARMv5 with Thumb and Java early abort handler
  *       xscale        - ARMv5 with Thumb with Xscale extensions
  *       v6_early      - ARMv6 generic early abort handler
+ *       v7_early      - ARMv7 generic early abort handler
  */
 #undef CPU_ABORT_HANDLER
 #undef MULTI_ABORT
 # endif
 #endif
 
+#ifdef CONFIG_CPU_ABRT_EV7
+# ifdef CPU_ABORT_HANDLER
+#  define MULTI_ABORT 1
+# else
+#  define CPU_ABORT_HANDLER v7_early_abort
+# endif
+#endif
+
 #ifndef CPU_ABORT_HANDLER
 #error Unknown data abort handler type
 #endif
index f8755c818b5462549e39ed8bd0102ae3b02ed0a0..4981ad419198d1cf91d8f38cc0d54450f18c0c06 100644 (file)
@@ -36,8 +36,9 @@ void __check_kvm_seq(struct mm_struct *mm);
  * The context ID is used by debuggers and trace logic, and
  * should be unique within all running processes.
  */
-#define ASID_BITS      8
-#define ASID_MASK      ((~0) << ASID_BITS)
+#define ASID_BITS              8
+#define ASID_MASK              ((~0) << ASID_BITS)
+#define ASID_FIRST_VERSION     (1 << ASID_BITS)
 
 extern unsigned int cpu_last_asid;
 
@@ -96,8 +97,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 #ifdef CONFIG_MMU
        unsigned int cpu = smp_processor_id();
 
-       if (prev != next) {
-               cpu_set(cpu, next->cpu_vm_mask);
+       if (!cpu_test_and_set(cpu, next->cpu_vm_mask) || prev != next) {
                check_context(next);
                cpu_switch_mm(next->pgd, next);
                if (cache_is_vivt())
index 5030b2b232a3c7433be4c96676da242e77155c90..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __ASMARM_POLL_H
-#define __ASMARM_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index ea7e54c319be535ed1777640f0e1740b36c748a5..5599d4e5e7080afdb23ac2e8eb1cac308158e9cd 100644 (file)
 #   define CPU_NAME cpu_v6
 #  endif
 # endif
+# ifdef CONFIG_CPU_V7
+#  ifdef CPU_NAME
+#   undef  MULTI_CPU
+#   define MULTI_CPU
+#  else
+#   define CPU_NAME cpu_v7
+#  endif
+# endif
 #endif
 
 #ifndef __ASSEMBLY__
index f2da3b6e3a837e89369625fd6c6cd4f113e9212b..6f8e6a69dc5f4334391dc03ff6ef53b3d1bd032a 100644 (file)
@@ -14,6 +14,7 @@
 #define CPU_ARCH_ARMv5TE       6
 #define CPU_ARCH_ARMv5TEJ      7
 #define CPU_ARCH_ARMv6         8
+#define CPU_ARCH_ARMv7         9
 
 /*
  * CR1 bits (CP#15 CR1)
@@ -155,7 +156,11 @@ extern unsigned int user_debug;
 #define vectors_high() (0)
 #endif
 
-#if defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ >= 6
+#if __LINUX_ARM_ARCH__ >= 7
+#define isb() __asm__ __volatile__ ("isb" : : : "memory")
+#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
+#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
+#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
 #define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
                                    : : "r" (0) : "memory")
 #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
index 2aa033bd0678b07ba8936aedb375a5a21b757df1..a5a7a4d5e09c29ad8723155795ae41d419f2489e 100644 (file)
@@ -321,7 +321,7 @@ DECLARE_IO(int,l,"")
 
 #define mmiowb()
 
-/* the following macro is depreciated */
+/* the following macro is deprecated */
 #define ioaddr(port)                    __ioaddr((port))
 
 /*
index a65f10b80dfb8dc0cae7c5260a12204beac04c65..7c1e5be39060dd291f0863f6b631b2dc5c6554e2 100644 (file)
@@ -60,7 +60,7 @@ static inline void *phys_to_virt(unsigned long x)
 /*
  * Virtual <-> DMA view memory address translations
  * Again, these are *only* valid on the kernel direct mapped RAM
- * memory.  Use of these is *depreciated*.
+ * memory.  Use of these is *deprecated*.
  */
 #define virt_to_bus(x)         ((unsigned long)(x))
 #define bus_to_virt(x)         ((void *)((unsigned long)(x)))
@@ -93,7 +93,7 @@ static inline void *phys_to_virt(unsigned long x)
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
 /*
- * We should really eliminate virt_to_bus() here - it's depreciated.
+ * We should really eliminate virt_to_bus() here - it's deprecated.
  */
 #define page_to_bus(page)      (page_address(page))
 
index 9ccb7f4190cafaae318e3e4eb2d784c8d13cb7a1..1170e7065f6a9fad33b2f97d2c06191cace12140 100644 (file)
@@ -1,26 +1,8 @@
 #ifndef __ASMARM_POLL_H
 #define __ASMARM_POLL_H
 
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
+#include <asm-generic/poll.h>
 
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#undef POLLREMOVE
 
 #endif
index 1a867b4e8d531e4f86b81feb4680e6ab15de7636..10fd07c7666264b5f39c0387f66bf4d3200d94b7 100644 (file)
@@ -70,7 +70,7 @@ struct tag_ramdisk {
 /* describes where the compressed ramdisk image lives */
 /*
  * this one accidentally used virtual addresses - as such,
- * its depreciated.
+ * it's deprecated.
  */
 #define ATAG_INITRD    0x54410005
 
diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
new file mode 100644 (file)
index 0000000..2bdc5bd
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * AVR32 and (fake) AT91 CPU identification
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __ASM_ARCH_CPU_H
+#define __ASM_ARCH_CPU_H
+
+/*
+ * Only AT32AP7000 is defined for now. We can identify the specific
+ * chip at runtime, but I'm not sure if it's really worth it.
+ */
+#ifdef CONFIG_CPU_AT32AP7000
+# define cpu_is_at32ap7000()   (1)
+#else
+# define cpu_is_at32ap7000()   (0)
+#endif
+
+/*
+ * Since this is AVR32, we will never run on any AT91 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at91rm9200()    (0)
+#define cpu_is_at91sam9xe()    (0)
+#define cpu_is_at91sam9260()   (0)
+#define cpu_is_at91sam9261()   (0)
+#define cpu_is_at91sam9263()   (0)
+
+#endif /* __ASM_ARCH_CPU_H */
index 736e29755dfc73c6b8258f365db695fabdc0b7ae..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __ASM_AVR32_POLL_H
-#define __ASM_AVR32_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP      0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif /* __ASM_AVR32_POLL_H */
+#include <asm-generic/poll.h>
index 1ff1a217015d85d2e6eaedf8bcc5af61acd0a41f..b0828d43e110c93f27b65adf593fc0c40e58a676 100644 (file)
@@ -110,7 +110,7 @@ struct tagtable {
        int     (*parse)(struct tag *);
 };
 
-#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
+#define __tag __attribute_used__ __attribute__((__section__(".taglist.init")))
 #define __tagtable(tag, fn)                                            \
        static struct tagtable __tagtable_##fn __tag = { tag, fn }
 
index 8f51204718193751bc131cc4f9ce772c2405a36b..2418cce624cc18775a459436aaaef18e140f9398 100644 (file)
 #define __NR_shmdt             276
 #define __NR_shmctl            277
 
+#define __NR_utimensat         278
+
 #ifdef __KERNEL__
-#define NR_syscalls            278
+#define NR_syscalls            279
 
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
index 997465c93e82fbce217ec50107d54543881481d5..0336ff132c16db742f756643cc1a01ff221e1aea 100644 (file)
@@ -58,10 +58,10 @@ do {                                                                        \
        (_regs)->pc = (_pc);                                            \
        if (current->mm)                                                \
                (_regs)->p5 = current->mm->start_data;                  \
-       current->thread_info->l1_task_info.stack_start                  \
+       task_thread_info(current)->l1_task_info.stack_start             \
                = (void *)current->mm->context.stack_start;             \
-       current->thread_info->l1_task_info.lowest_sp = (void *)(_usp);          \
-       memcpy(L1_SCRATCH_TASK_INFO, &current->thread_info->l1_task_info,       \
+       task_thread_info(current)->l1_task_info.lowest_sp = (void *)(_usp); \
+       memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info, \
                sizeof(*L1_SCRATCH_TASK_INFO));                         \
        wrusp(_usp);                                                    \
 } while(0)
index b5bf6e7cb5e8caaae95ef37e70a610d1bf0daac5..5e5f1a0566c0fe6b1c90d9d0d0b039ed23c289e8 100644 (file)
@@ -239,9 +239,9 @@ asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_stru
 
 #define switch_to(prev,next,last) \
 do {    \
-       memcpy (&prev->thread_info->l1_task_info, L1_SCRATCH_TASK_INFO, \
+       memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \
                sizeof *L1_SCRATCH_TASK_INFO); \
-       memcpy (L1_SCRATCH_TASK_INFO, &next->thread_info->l1_task_info, \
+       memcpy (L1_SCRATCH_TASK_INFO, &task_thread_info(next)->l1_task_info, \
                sizeof *L1_SCRATCH_TASK_INFO); \
        (last) = resume (prev, next);   \
 } while (0)
index 1b25d4cf498c4aab72193c3246c94f312d00b1eb..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,26 +1 @@
-#ifndef __ASM_CRIS_POLL_H
-#define __ASM_CRIS_POLL_H
-
-/* taken from asm-alpha */
-
-#define POLLIN         1
-#define POLLPRI                2
-#define POLLOUT                4
-#define POLLERR                8
-#define POLLHUP                16
-#define POLLNVAL       32
-#define POLLRDNORM     64
-#define POLLRDBAND     128
-#define POLLWRNORM     256
-#define POLLWRBAND     512
-#define POLLMSG                1024
-#define POLLREMOVE     4096
-#define POLLRDHUP       8192
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index c8fe8801d075819c3e069e720e7806604d6ea8b5..0d01479ccc563eb133518052a69abad68b9750cb 100644 (file)
@@ -1,24 +1,12 @@
 #ifndef _ASM_POLL_H
 #define _ASM_POLL_H
 
-#define POLLIN           1
-#define POLLPRI                  2
-#define POLLOUT                  4
-#define POLLERR                  8
-#define POLLHUP                 16
-#define POLLNVAL        32
-#define POLLRDNORM      64
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     128
 #define POLLWRBAND     256
-#define POLLMSG                0x0400
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
 
 #endif
 
index f94fe5cb9b3aebd4180c0be159f33e53b1ee46af..cd458eb6d75ed113469d257d62a901ffb7f18701 100644 (file)
@@ -3,7 +3,11 @@
 
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_MMU
+extern void check_pgt_cache(void);
+#else
 #define check_pgt_cache() do {} while(0)
+#endif
 
 /*
  * we don't need any special per-pte or per-vma handling...
index 584c0417ae4de9ed74a0e167e6afd7cc30fc9738..d0ea6789b31e530cca93f92716aa474ff3a7bc45 100644 (file)
 #define __NR_rt_sigtimedwait   177
 #define __NR_rt_sigqueueinfo   178
 #define __NR_rt_sigsuspend     179
-#define __NR_pread             180
-#define __NR_pwrite            181
+#define __NR_pread64           180
+#define __NR_pwrite64          181
 #define __NR_chown             182
 #define __NR_getcwd            183
 #define __NR_capget            184
 #define __NR_faccessat         307
 #define __NR_pselect6          308
 #define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
+#define __NR_move_pages                317
+#define __NR_getcpu            318
+#define __NR_epoll_pwait       319
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 310
+#define NR_syscalls 320
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 /* #define __ARCH_WANT_OLD_READDIR */
index fa14f8cd30c501a6b7e0c8e8e391210a9c62a759..5bfeef7616494f22a117d1905933274c6850d51b 100644 (file)
@@ -4,6 +4,7 @@ header-y += fcntl.h
 header-y += ioctl.h
 header-y += ipc.h
 header-y += mman.h
+header-y += poll.h
 header-y += signal.h
 header-y += statfs.h
 
index 78339319ba02cbcb019fd875612b9291499a944c..cd8a9641bd668e5e0ae2da5bebac5d1e7bf8704f 100644 (file)
@@ -58,7 +58,7 @@ extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-generic/poll.h b/include/asm-generic/poll.h
new file mode 100644 (file)
index 0000000..44bce83
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __ASM_GENERIC_POLL_H
+#define __ASM_GENERIC_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN         0x0001
+#define POLLPRI                0x0002
+#define POLLOUT                0x0004
+#define POLLERR                0x0008
+#define POLLHUP                0x0010
+#define POLLNVAL       0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM     0x0040
+#define POLLRDBAND     0x0080
+#ifndef POLLWRNORM
+#define POLLWRNORM     0x0100
+#endif
+#ifndef POLLWRBAND
+#define POLLWRBAND     0x0200
+#endif
+#ifndef POLLMSG
+#define POLLMSG                0x0400
+#endif
+#ifndef POLLREMOVE
+#define POLLREMOVE     0x1000
+#endif
+#ifndef POLLRDHUP
+#define POLLRDHUP       0x2000
+#endif
+
+struct pollfd {
+       int fd;
+       short events;
+       short revents;
+};
+
+#endif /* __ASM_GENERIC_POLL_H */
index fc52103b276ae0011a2dfcb755c5b201ae6ea161..f61540c22d943ec18fd7a2dcfb16a694c6e50f6d 100644 (file)
@@ -1,23 +1,11 @@
 #ifndef __H8300_POLL_H
 #define __H8300_POLL_H
 
-#define POLLIN           1
-#define POLLPRI                  2
-#define POLLOUT                  4
-#define POLLERR                  8
-#define POLLHUP                 16
-#define POLLNVAL        32
-#define POLLRDNORM      64
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     128
 #define POLLWRBAND     256
-#define POLLMSG                0x0400
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
 
 #endif
index 7ddd414f8d16b37dd9068ddbd85ad2467eb7a6e1..99f3c3561ecba1f0004ba7180a3585a9c80641a3 100644 (file)
@@ -21,7 +21,7 @@
 #define __NR_time               13
 #define __NR_mknod              14
 #define __NR_chmod              15
-#define __NR_chown              16
+#define __NR_lchown             16
 #define __NR_break              17
 #define __NR_oldstat            18
 #define __NR_lseek              19
 #define __NR_lstat             107
 #define __NR_fstat             108
 #define __NR_olduname          109
-#define __NR_iopl              /* 110 */ not supported
+#define __NR_iopl              110
 #define __NR_vhangup           111
-#define __NR_idle              /* 112 */ Obsolete
-#define __NR_vm86              /* 113 */ not supported
+#define __NR_idle              112
+#define __NR_vm86old           113
 #define __NR_wait4             114
 #define __NR_swapoff           115
 #define __NR_sysinfo           116
 #define __NR_clone             120
 #define __NR_setdomainname     121
 #define __NR_uname             122
-#define __NR_cacheflush                123
+#define __NR_modify_ldt                123
 #define __NR_adjtimex          124
 #define __NR_mprotect          125
 #define __NR_sigprocmask       126
 #define __NR_mremap            163
 #define __NR_setresuid         164
 #define __NR_getresuid         165
-#define __NR_getpagesize       166
+#define __NR_vm86              166
 #define __NR_query_module      167
 #define __NR_poll              168
 #define __NR_nfsservctl                169
 #define __NR_rt_sigsuspend     179
 #define __NR_pread64           180
 #define __NR_pwrite64          181
-#define __NR_lchown            182
+#define __NR_chown             182
 #define __NR_getcwd            183
 #define __NR_capget            184
 #define __NR_capset            185
 #define __NR_stat64            195
 #define __NR_lstat64           196
 #define __NR_fstat64           197
-#define __NR_chown32           198
+#define __NR_lchown32          198
 #define __NR_getuid32          199
 #define __NR_getgid32          200
 #define __NR_geteuid32         201
 #define __NR_getresuid32       209
 #define __NR_setresgid32       210
 #define __NR_getresgid32       211
-#define __NR_lchown32          212
+#define __NR_chown32           212
 #define __NR_setuid32          213
 #define __NR_setgid32          214
 #define __NR_setfsuid32                215
 #define __NR_setfsgid32                216
 #define __NR_pivot_root                217
+#define __NR_mincore           218
+#define __NR_madvise           219
+#define __NR_madvise1          219
 #define __NR_getdents64                220
 #define __NR_fcntl64           221
-#define __NR_security          223
+/* 223 is unused */
 #define __NR_gettid            224
 #define __NR_readahead         225
 #define __NR_setxattr          226
 #define __NR_io_getevents      247
 #define __NR_io_submit         248
 #define __NR_io_cancel         249
-#define __NR_alloc_hugepages   250
-#define __NR_free_hugepages    251
+#define __NR_fadvise64         250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
 #define __NR_exit_group                252
 #define __NR_lookup_dcookie    253
-#define __NR_sys_epoll_create  254
-#define __NR_sys_epoll_ctl     255
-#define __NR_sys_epoll_wait    256
+#define __NR_epoll_create      254
+#define __NR_epoll_ctl         255
+#define __NR_epoll_wait                256
 #define __NR_remap_file_pages  257
 #define __NR_set_tid_address   258
 #define __NR_timer_create      259
 #define __NR_add_key           286
 #define __NR_request_key       287
 #define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_fstatat64         300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
+#define __NR_move_pages                317
+#define __NR_getcpu            318
+#define __NR_epoll_pwait       319
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 289
+#define NR_syscalls 320
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 0f70b379b029cca89aa8cded9d705b282e9c6fa7..eb7da5402bfaa17623bb523bed36c171adc0c776 100644 (file)
@@ -97,6 +97,12 @@ static inline void alternatives_smp_switch(int smp) {}
                      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
                      ".previous" : output : [feat] "i" (feature), ##input)
 
+/*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
 /*
  * Alternative inline assembly for SMP.
  *
index 273b50629357bf15955b6c433a9d95f19af9dfbe..a20fe9822f6002db96607331fd7ae50f0a95ee58 100644 (file)
@@ -27,7 +27,7 @@
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
index e7686d0a84136be4e4756a5a6bfdc762f55e35a0..bd024ab4fe53b02f6e9b0fe678defb0d1a982242 100644 (file)
@@ -12,7 +12,7 @@
 #define EXTENDED_VGA   0xfffe          /* 80x50 mode */
 #define ASK_VGA                0xfffd          /* ask for it at bootup */
 
-/* Physical address where kenrel should be loaded. */
+/* Physical address where kernel should be loaded. */
 #define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
                                + (CONFIG_PHYSICAL_ALIGN - 1)) \
                                & ~(CONFIG_PHYSICAL_ALIGN - 1))
index 3503ad66945ec4a488cbd192635e5cc7c7db1b4f..118e9812778fd857f832632d2cbaa38a888cf9b0 100644 (file)
@@ -122,21 +122,21 @@ static inline int pfn_valid(int pfn)
        __alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0)
 #define alloc_bootmem_node(pgdat, x)                                   \
 ({                                                                     \
-       struct pglist_data  __attribute__ ((unused))                    \
+       struct pglist_data  __maybe_unused                      \
                                *__alloc_bootmem_node__pgdat = (pgdat); \
        __alloc_bootmem_node(NODE_DATA(0), (x), SMP_CACHE_BYTES,        \
                                                __pa(MAX_DMA_ADDRESS)); \
 })
 #define alloc_bootmem_pages_node(pgdat, x)                             \
 ({                                                                     \
-       struct pglist_data  __attribute__ ((unused))                    \
+       struct pglist_data  __maybe_unused                      \
                                *__alloc_bootmem_node__pgdat = (pgdat); \
        __alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE,              \
                                                __pa(MAX_DMA_ADDRESS))  \
 })
 #define alloc_bootmem_low_pages_node(pgdat, x)                         \
 ({                                                                     \
-       struct pglist_data  __attribute__ ((unused))                    \
+       struct pglist_data  __maybe_unused                      \
                                *__alloc_bootmem_node__pgdat = (pgdat); \
        __alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0);          \
 })
index 26861df52cc4ebde75c53f18621f42dd53ff71d0..df21ea0493694a43db95b28f760263d6595f222d 100644 (file)
@@ -86,62 +86,50 @@ static inline unsigned long long native_read_pmc(void)
 
 #define rdmsr(msr,val1,val2)                                           \
        do {                                                            \
-               unsigned long long __val = native_read_msr(msr);        \
-               val1 = __val;                                           \
-               val2 = __val >> 32;                                     \
+               u64 __val = native_read_msr(msr);                       \
+               (val1) = (u32)__val;                                    \
+               (val2) = (u32)(__val >> 32);                            \
        } while(0)
 
-#define wrmsr(msr,val1,val2)                                           \
-       native_write_msr(msr, ((unsigned long long)val2 << 32) | val1)
-
-#define rdmsrl(msr,val)                                        \
-       do {                                            \
-               (val) = native_read_msr(msr);           \
-       } while(0)
-
-static inline void wrmsrl (unsigned long msr, unsigned long long val)
+static inline void wrmsr(u32 __msr, u32 __low, u32 __high)
 {
-       unsigned long lo, hi;
-       lo = (unsigned long) val;
-       hi = val >> 32;
-       wrmsr (msr, lo, hi);
+       native_write_msr(__msr, ((u64)__high << 32) | __low);
 }
 
+#define rdmsrl(msr,val)                                                        \
+       ((val) = native_read_msr(msr))
+
+#define wrmsrl(msr,val)        native_write_msr(msr, val)
+
 /* wrmsr with exception handling */
-#define wrmsr_safe(msr,val1,val2)                                              \
-       (native_write_msr_safe(msr, ((unsigned long long)val2 << 32) | val1))
+static inline int wrmsr_safe(u32 __msr, u32 __low, u32 __high)
+{
+       return native_write_msr_safe(__msr, ((u64)__high << 32) | __low);
+}
 
 /* rdmsr with exception handling */
 #define rdmsr_safe(msr,p1,p2)                                          \
        ({                                                              \
                int __err;                                              \
-               unsigned long long __val = native_read_msr_safe(msr, &__err);\
-               (*p1) = __val;                                          \
-               (*p2) = __val >> 32;                                    \
+               u64 __val = native_read_msr_safe(msr, &__err);          \
+               (*p1) = (u32)__val;                                     \
+               (*p2) = (u32)(__val >> 32);                             \
                __err;                                                  \
        })
 
-#define rdtsc(low,high)                                                \
-       do {                                                    \
-               u64 _l = native_read_tsc();                     \
-               (low) = (u32)_l;                                \
-               (high) = _l >> 32;                              \
-       } while(0)
-
 #define rdtscl(low)                                            \
-       do {                                                    \
-               (low) = native_read_tsc();                      \
-       } while(0)
+       ((low) = (u32)native_read_tsc())
 
-#define rdtscll(val) ((val) = native_read_tsc())
+#define rdtscll(val)                                           \
+       ((val) = native_read_tsc())
 
 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
 
 #define rdpmc(counter,low,high)                                        \
        do {                                                    \
                u64 _l = native_read_pmc();                     \
-               low = (u32)_l;                                  \
-               high = _l >> 32;                                \
+               (low)  = (u32)_l;                               \
+               (high) = (u32)(_l >> 32);                       \
        } while(0)
 #endif /* !CONFIG_PARAVIRT */
 
index e2e7f98723c57fac6c3f45c797a1a7a1060df45a..d7a0512f88e0a9a148a815e16a1146c0efe59985 100644 (file)
@@ -222,11 +222,6 @@ struct paravirt_ops
        void (*iret)(void);
 };
 
-/* Mark a paravirt probe function. */
-#define paravirt_probe(fn)                                             \
- static asmlinkage void (*__paravirtprobe_##fn)(void) __attribute_used__ \
-               __attribute__((__section__(".paravirtprobe"))) = fn
-
 extern struct paravirt_ops paravirt_ops;
 
 #define PARAVIRT_PATCH(x)                                      \
@@ -560,11 +555,6 @@ static inline u64 paravirt_read_tsc(void)
 {
        return PVOP_CALL0(u64, read_tsc);
 }
-#define rdtsc(low,high) do {                   \
-       u64 _l = paravirt_read_tsc();           \
-       low = (u32)_l;                          \
-       high = _l >> 32;                        \
-} while(0)
 
 #define rdtscl(low) do {                       \
        u64 _l = paravirt_read_tsc();           \
index 2cd4929abd40426b3ad88ef33762c859227b497b..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index 090abc1da32a158b786be16dd7a610cf507d3380..0c713278706262e60abaa34229ccedfa4e9a45d9 100644 (file)
@@ -124,20 +124,6 @@ static inline int num_booting_cpus(void)
        return cpus_weight(cpu_callout_map);
 }
 
-#ifdef CONFIG_X86_LOCAL_APIC
-
-#ifdef APIC_DEFINITION
-extern int hard_smp_processor_id(void);
-#else
-#include <mach_apicdef.h>
-static inline int hard_smp_processor_id(void)
-{
-       /* we don't want to mark this access volatile - bad code generation */
-       return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
-}
-#endif
-#endif
-
 extern int safe_smp_processor_id(void);
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
@@ -152,10 +138,31 @@ extern unsigned int num_processors;
 
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
 
-#endif
+#endif /* CONFIG_SMP */
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#ifdef APIC_DEFINITION
+extern int hard_smp_processor_id(void);
+#else
+#include <mach_apicdef.h>
+static inline int hard_smp_processor_id(void)
+{
+       /* we don't want to mark this access volatile - bad code generation */
+       return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
+#endif /* APIC_DEFINITION */
+
+#else /* CONFIG_X86_LOCAL_APIC */
+
+#ifndef CONFIG_SMP
+#define hard_smp_processor_id()                0
+#endif
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
 extern u8 apicid_2_node[];
 
 #ifdef CONFIG_X86_LOCAL_APIC
index 7d72351bea753f54d79d26e32aa460f2dd01ea06..cbce08a2d135e22b721bbfe7a643a3f01e3f321f 100644 (file)
@@ -24,7 +24,7 @@
  * if you do not require the atomic guarantees.
  *
  * Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non-x86 architectures, so if you are writing portable code,
  * make sure not to rely on its reordering guarantees.
  *
  * Note that @nr may be almost arbitrarily large; this function is not
index bf01d4b342bd40978997695c6298f65b55232c1d..4cb0f91ae64f3dc01e7a945012fe6184be784fd4 100644 (file)
@@ -172,7 +172,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TS_USEDFPU             0x0001  /* FPU was used by this task this quantum (SMP) */
 #define TS_POLLING             0x0002  /* True if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
index 3f3c1fa000b48ed8a0786435b557499922cac8db..62c091ffcccc46f8940feb9eff7e4c1277cfea85 100644 (file)
@@ -35,14 +35,16 @@ static inline cycles_t get_cycles(void)
 static __always_inline cycles_t get_cycles_sync(void)
 {
        unsigned long long ret;
-       unsigned eax;
+       unsigned eax, edx;
 
        /*
         * Use RDTSCP if possible; it is guaranteed to be synchronous
         * and doesn't cause a VMEXIT on Hypervisors
         */
        alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP,
-                                "=A" (ret), "0" (0ULL) : "ecx", "memory");
+                      ASM_OUTPUT2("=a" (eax), "=d" (edx)),
+                      "a" (0U), "d" (0U) : "ecx", "memory");
+       ret = (((unsigned long long)edx) << 32) | ((unsigned long long)eax);
        if (ret)
                return ret;
 
index bd21e795197c5689d823ae2d9abda8a3cc3693ad..e84ace1ec8bfae787d16c944aa7d8f10e0ed874b 100644 (file)
 #define __NR_getcpu            318
 #define __NR_epoll_pwait       319
 #define __NR_utimensat         320
+#define __NR_signalfd          321
+#define __NR_timerfd           322
+#define __NR_eventfd           323
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 321
+#define NR_syscalls 324
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 27f9df6b914539401c26421ce0bb38d970ef0081..c054d7a9aaa771cfb5743052c76fdca953b4aa69 100644 (file)
@@ -66,6 +66,7 @@ extern int ia64_last_device_vector;
 #define IA64_PERFMON_VECTOR            0xee    /* performanc monitor interrupt vector */
 #define IA64_TIMER_VECTOR              0xef    /* use highest-prio group 15 interrupt for timer */
 #define        IA64_MCA_WAKEUP_VECTOR          0xf0    /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
+#define IA64_IPI_LOCAL_TLB_FLUSH       0xfc    /* SMP flush local TLB */
 #define IA64_IPI_RESCHEDULE            0xfd    /* SMP reschedule */
 #define IA64_IPI_VECTOR                        0xfe    /* inter-processor interrupt vector */
 
index 20f98f1751a19677795035356972993d8aa24709..421cb6b62a7c1455c1cd0de701bdfcc289e7fc90 100644 (file)
@@ -83,7 +83,7 @@ extern int gsi_to_irq (unsigned int gsi);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
                                  unsigned long trigger);
 extern void iosapic_unregister_intr (unsigned int irq);
-extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
+extern void __devinit iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                                      unsigned long polarity,
                                      unsigned long trigger);
 extern int __init iosapic_register_platform_intr (u32 int_type,
index bcaf9f1402427ddaef313f0d82306d58e6a7410e..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,32 +1 @@
-#ifndef _ASM_IA64_POLL_H
-#define _ASM_IA64_POLL_H
-
-/*
- * poll(2) bit definitions.  Based on <asm-i386/poll.h>.
- *
- * Modified 1998, 1999, 2002
- *     David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif /* _ASM_IA64_POLL_H */
+#include <asm-generic/poll.h>
index 60fd4ae014f6fbe8a3fe19b8e9171a7e277f609e..c60024989ebd59b70bd090d01cc0ada6a95ad9d4 100644 (file)
@@ -38,6 +38,8 @@ ia64_get_lid (void)
        return lid.f.id << 8 | lid.f.eid;
 }
 
+#define hard_smp_processor_id()                ia64_get_lid()
+
 #ifdef CONFIG_SMP
 
 #define XTP_OFFSET             0x1e0008
@@ -110,8 +112,6 @@ max_xtp (void)
                writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
 }
 
-#define hard_smp_processor_id()                ia64_get_lid()
-
 /* Upping and downing of CPUs */
 extern int __cpu_disable (void);
 extern void __cpu_die (unsigned int cpu);
@@ -128,7 +128,7 @@ extern void unlock_ipi_calllock(void);
 extern void identify_siblings (struct cpuinfo_ia64 *);
 extern int is_multithreading_enabled(void);
 
-#else
+#else /* CONFIG_SMP */
 
 #define cpu_logical_id(i)              0
 #define cpu_physical_id(i)             ia64_get_lid()
index 2c4004eb5a68bf68f2ef7ddfc70943bcc7e91219..291e8ceed6e6ddddfdbcd2060aa97f0eb914aba9 100644 (file)
 /* interrupt handling */
 #define SAL_INTR_ALLOC         1
 #define SAL_INTR_FREE          2
+#define SAL_INTR_REDIRECT      3
 
 /*
  * operations available on the generic SN_SAL_SYSCTL_OP
index 91698599f91886f73bb591b6e0b12c84eaa1e2ac..7d0241db622b0e19f6ca350782b214c348d05e4c 100644 (file)
@@ -85,6 +85,7 @@ struct thread_info {
 #define TIF_SYSCALL_TRACE      3       /* syscall trace active */
 #define TIF_SYSCALL_AUDIT      4       /* syscall auditing active */
 #define TIF_SINGLESTEP         5       /* restore singlestep on return to user mode */
+#define TIF_RESTORE_SIGMASK    6       /* restore signal mask in do_signal() */
 #define TIF_POLLING_NRFLAG     16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             17
 #define TIF_MCA_INIT           18      /* this task is processing MCA or INIT */
@@ -96,6 +97,7 @@ struct thread_info {
 #define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
 #define _TIF_SYSCALL_TRACEAUDIT        (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
+#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
@@ -104,12 +106,12 @@ struct thread_info {
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
 
 /* "work to do on user-return" bits */
-#define TIF_ALLWORK_MASK       (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define TIF_ALLWORK_MASK       (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_RESTORE_SIGMASK)
 /* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */
 #define TIF_WORK_MASK          (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
 
 #define TS_POLLING             1       /* true if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* _ASM_IA64_THREAD_INFO_H */
index cf9acb9bb1fb69b7744f4e40081ad1bdcf8061b0..e37f9fbf33af8babd7406b648219a1dca48bc152 100644 (file)
@@ -27,9 +27,11 @@ extern void local_flush_tlb_all (void);
 #ifdef CONFIG_SMP
   extern void smp_flush_tlb_all (void);
   extern void smp_flush_tlb_mm (struct mm_struct *mm);
+  extern void smp_flush_tlb_cpumask (cpumask_t xcpumask);
 # define flush_tlb_all()       smp_flush_tlb_all()
 #else
 # define flush_tlb_all()       local_flush_tlb_all()
+# define smp_flush_tlb_cpumask(m) local_flush_tlb_all()
 #endif
 
 static inline void
@@ -94,6 +96,15 @@ flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end
         */
 }
 
+/*
+ * Flush the local TLB. Invoked from another cpu using an IPI.
+ */
+#ifdef CONFIG_SMP
+void smp_local_flush_tlb(void);
+#else
+#define smp_local_flush_tlb()
+#endif
+
 #define flush_tlb_kernel_range(start, end)     flush_tlb_all() /* XXX fix me */
 
 #endif /* _ASM_IA64_TLBFLUSH_H */
index a9e1fa4cac4d46d652e534ce1bfaf54ddc1698bf..861c8ec87b095374c942b593ba91b3108d86c79a 100644 (file)
 #define __NR_readlinkat                        1291
 #define __NR_fchmodat                  1292
 #define __NR_faccessat                 1293
-/* 1294, 1295 reserved for pselect/ppoll */
+#define __NR_pselect6                  1294
+#define __NR_ppoll                     1295
 #define __NR_unshare                   1296
 #define __NR_splice                    1297
 #define __NR_set_robust_list           1298
 #define NR_syscalls                    281 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 #ifdef CONFIG_IA32_SUPPORT
 # define __ARCH_WANT_SYS_FADVISE64
 # define __ARCH_WANT_SYS_OLDUMOUNT
 # define __ARCH_WANT_SYS_SIGPENDING
 # define __ARCH_WANT_SYS_SIGPROCMASK
+# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 # define __ARCH_WANT_COMPAT_SYS_TIME
 #endif
 
index 750925726a10bc73b14b2dcc7f693a6ed141c24a..bca3475f9595753aa43672791a17a177579831e9 100644 (file)
@@ -71,8 +71,8 @@ static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address)
 #define pfn_pmd(pfn, prot)     __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
 #define PTE_FILE_MAX_BITS      29
-#define pte_to_pgoff(pte)      (((pte_val(pte) >> 2) & 0xef) | (((pte_val(pte) >> 10)) << 7))
-#define pgoff_to_pte(off)      ((pte_t) { (((off) & 0xef) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
+#define pte_to_pgoff(pte)      (((pte_val(pte) >> 2) & 0x7f) | (((pte_val(pte) >> 10)) << 7))
+#define pgoff_to_pte(off)      ((pte_t) { (((off) & 0x7f) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_M32R_PGTABLE_2LEVEL_H */
index 8b2a2f17e69559e42c21894c0448f9d2ac048947..6604303fc47cd281e54e5abee4d62c62e0022834 100644 (file)
@@ -366,7 +366,7 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 #define pte_unmap_nested(pte)  do { } while (0)
 
 /* Encode and de-code a swap entry */
-#define __swp_type(x)                  (((x).val >> 2) & 0x3f)
+#define __swp_type(x)                  (((x).val >> 2) & 0x1f)
 #define __swp_offset(x)                        ((x).val >> 10)
 #define __swp_entry(type, offset)      \
        ((swp_entry_t) { ((type) << 2) | ((offset) << 10) })
index 9e0e700e727c94e2e160b7b1e717181ce142a190..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,32 +1 @@
-#ifndef _ASM_M32R_POLL_H
-#define _ASM_M32R_POLL_H
-
-/*
- * poll(2) bit definitions.  Based on <asm-i386/poll.h>.
- *
- * Modified 2004
- *      Hirokazu Takata <takata at linux-m32r.org>
- */
-
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif  /* _ASM_M32R_POLL_H */
+#include <asm-generic/poll.h>
index abd937ac5239ae91503275cea548652bf020db23..078e1a51a042a74a6eeda6c48d3f8882a466f2fc 100644 (file)
@@ -108,6 +108,10 @@ extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
 #define IPI_SHIFT      (0)
 #define NR_IPIS                (8)
 
-#endif /* CONFIG_SMP */
+#else  /* CONFIG_SMP */
+
+#define hard_smp_processor_id()                0
+
+#endif /* CONFIG_SMP */
 
 #endif /* _ASM_M32R_SMP_H */
index 06cdece358653bf249ac001f250287cc8852f939..b291b2f729549d35589e8faf5198db364986731b 100644 (file)
  * `next' and `prev' should be struct task_struct, but it isn't always defined
  */
 
+#if defined(CONFIG_FRAME_POINTER) || \
+       !defined(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER)
+#define M32R_PUSH_FP " push fp\n"
+#define M32R_POP_FP  " pop  fp\n"
+#else
+#define M32R_PUSH_FP ""
+#define M32R_POP_FP  ""
+#endif
+
 #define switch_to(prev, next, last)  do { \
        __asm__ __volatile__ ( \
                "       seth    lr, #high(1f)                           \n" \
                "       or3     lr, lr, #low(1f)                        \n" \
                "       st      lr, @%4  ; store old LR                 \n" \
                "       ld      lr, @%5  ; load new LR                  \n" \
+                       M32R_PUSH_FP \
                "       st      sp, @%2  ; store old SP                 \n" \
                "       ld      sp, @%3  ; load new SP                  \n" \
                "       push    %1  ; store `prev' on new stack         \n" \
@@ -34,6 +44,7 @@
                "       .fillinsn                                       \n" \
                "1:                                                     \n" \
                "       pop     %0  ; restore `__last' from new stack   \n" \
+                       M32R_POP_FP \
                : "=r" (last) \
                : "0" (prev), \
                  "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \
@@ -136,7 +147,7 @@ extern void  __xchg_called_with_bad_pointer(void);
        "add3   "reg0", "addr", #0x2000;                \n\t"   \
        "ld     "reg0", @"reg0";                        \n\t"   \
        "unlock "reg0", @"reg1";                        \n\t"
-       /* FIXME: This workaround code cannot handle kenrel modules
+       /* FIXME: This workaround code cannot handle kernel modules
         * correctly under SMP environment.
         */
 #else  /* CONFIG_CHIP_M32700_TS1 */
index f28acd0fd689f17c62a4b76d20bb359853ad907a..6211363a345ff4a7353ad2a2b2d5a20d20c5625c 100644 (file)
@@ -2,7 +2,7 @@
 ** linux/atarihw.h -- This header defines some macros and pointers for
 **                    the various Atari custom hardware registers.
 **
-** Copyright 1994 by Bj\94rn Brauel
+** Copyright 1994 by BjÂ\94rn Brauel
 **
 ** 5/1/94 Roman Hodek:
 **   Added definitions for TT specific chips.
index 0ed454fc24bb5416e0b4f0c1c17b1c95fc15fe6e..ce6c445805bde61e7dab52c5173089024362ec39 100644 (file)
@@ -1,7 +1,7 @@
 /*
 ** atariints.h -- Atari Linux interrupt handling structs and prototypes
 **
-** Copyright 1994 by Bj\94rn Brauel
+** Copyright 1994 by BjÂ\94rn Brauel
 **
 ** 5/2/94 Roman Hodek:
 **   TT interrupt definitions added.
index 0fb8843647f8a4a4bbafc74d99bda97e622db475..f080fcdb61bf617696c7bdc8ea9ab87e7e1a5460 100644 (file)
@@ -1,24 +1,9 @@
 #ifndef __m68k_POLL_H
 #define __m68k_POLL_H
 
-#define POLLIN           1
-#define POLLPRI                  2
-#define POLLOUT                  4
-#define POLLERR                  8
-#define POLLHUP                 16
-#define POLLNVAL        32
-#define POLLRDNORM      64
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     128
 #define POLLWRBAND     256
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
index 8e612266da51bb1bcc6871bf55663b144d1d2d12..24887a2d9c7bd09290b6980fee23e4a1d74090fa 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _M68K_SCATTERLIST_H
 #define _M68K_SCATTERLIST_H
 
+#include <linux/types.h>
+
 struct scatterlist {
        struct page *page;
        unsigned int offset;
index c4d622a57dfbf5d3bfb9913bfa257bc8c0ab58da..d635a375248896149ba6a14fcfc7392ca62873f0 100644 (file)
@@ -37,17 +37,17 @@ struct thread_info {
 #define init_stack             (init_thread_union.stack)
 
 #define task_thread_info(tsk)  (&(tsk)->thread.info)
-#define task_stack_page(tsk)   ((void *)(tsk)->thread_info)
+#define task_stack_page(tsk)   ((tsk)->stack)
 #define current_thread_info()  task_thread_info(current)
 
 #define __HAVE_THREAD_FUNCTIONS
 
 #define setup_thread_stack(p, org) ({                  \
-       *(struct task_struct **)(p)->thread_info = (p); \
+       *(struct task_struct **)(p)->stack = (p);       \
        task_thread_info(p)->task = (p);                \
 })
 
-#define end_of_stack(p) ((unsigned long *)(p)->thread_info + 1)
+#define end_of_stack(p) ((unsigned long *)(p)->stack + 1)
 
 /* entry.S relies on these definitions!
  * bits 0-7 are tested at every exception exit
index c7c945baf1ee6c4140468baa7f84d90e2391cf47..dbf834f4dac41a7a3888933b53cea2b518a5b0ba 100644 (file)
@@ -254,7 +254,7 @@ extern void free_init_pages(const char *what,
 extern char arcs_cmdline[CL_SIZE];
 
 /*
- * Registers a0, a1, a3 and a4 as passed to the kenrel entry by firmware
+ * Registers a0, a1, a3 and a4 as passed to the kernel entry by firmware
  */
 extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
 
index 70881f8c5c5092e58e00df92ec21956abeb1586e..47b9520804315b718611797bf02174d97d8c8903 100644 (file)
@@ -1,28 +1,9 @@
 #ifndef __ASM_POLL_H
 #define __ASM_POLL_H
 
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
 #define POLLWRNORM     POLLOUT
 #define POLLWRBAND     0x0100
 
-/* These seem to be more or less nonstandard ...  */
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* __ASM_POLL_H */
index 30f23a2b46ca0c5d32afd99bff1a52ff30254890..3713d256d36958d52d6ac750315f414c3610ff77 100644 (file)
@@ -55,7 +55,7 @@ do {                                                                  \
        if (cpu_has_dsp)                                                \
                __save_dsp(prev);                                       \
        next->thread.emulated_fp = 0;                                   \
-       (last) = resume(prev, next, next->thread_info);                 \
+       (last) = resume(prev, next, task_thread_info(next));            \
        if (cpu_has_dsp)                                                \
                __restore_dsp(current);                                 \
 } while(0)
index fe8579023531d5a8e8788eea06c7f672f161fa36..11f4222597a067c1f9c41b60b222078d0bf4dfc9 100644 (file)
@@ -152,7 +152,7 @@ static __inline__ void __user *compat_alloc_user_space(long len)
 
 static inline int __is_compat_task(struct task_struct *t)
 {
-       return test_ti_thread_flag(t->thread_info, TIF_32BIT);
+       return test_ti_thread_flag(task_thread_info(t), TIF_32BIT);
 }
 
 static inline int is_compat_task(void)
index 20e4d03c74cb835d7d873015456aa26a0b67a6c6..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __PARISC_POLL_H
-#define __PARISC_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index 9e4dd98eb220ca65a409ffe475bc59a762f84f55..a7b60bf639e0896f5b1099ee29c664c20fa0d33a 100644 (file)
@@ -48,8 +48,15 @@ extern void iseries_handle_interrupts(void);
 
 #define irqs_disabled()                (local_get_flags() == 0)
 
-#define hard_irq_enable()      __mtmsrd(mfmsr() | MSR_EE, 1)
-#define hard_irq_disable()     __mtmsrd(mfmsr() & ~MSR_EE, 1)
+#define __hard_irq_enable()    __mtmsrd(mfmsr() | MSR_EE, 1)
+#define __hard_irq_disable()   __mtmsrd(mfmsr() & ~MSR_EE, 1)
+
+#define  hard_irq_disable()                    \
+       do {                                    \
+               __hard_irq_disable();           \
+               get_paca()->soft_enabled = 0;   \
+               get_paca()->hard_enabled = 0;   \
+       } while(0)
 
 #else
 
index 6739457d8bc02aa3fbf45935c967a70be668e369..b8dca30bd0b57436a4401608f57183e9a32caaac 100644 (file)
@@ -73,8 +73,9 @@ extern char initial_stab[];
 
 #define HPTES_PER_GROUP 8
 
+#define HPTE_V_SSIZE_SHIFT     62
 #define HPTE_V_AVPN_SHIFT      7
-#define HPTE_V_AVPN            ASM_CONST(0xffffffffffffff80)
+#define HPTE_V_AVPN            ASM_CONST(0x3fffffffffffff80)
 #define HPTE_V_AVPN_VAL(x)     (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
 #define HPTE_V_COMPARE(x,y)    (!(((x) ^ (y)) & HPTE_V_AVPN))
 #define HPTE_V_BOLTED          ASM_CONST(0x0000000000000010)
@@ -151,6 +152,15 @@ struct mmu_psize_def
 #define MMU_PAGE_16G           5       /* 16G */
 #define MMU_PAGE_COUNT         6
 
+/*
+ * Segment sizes.
+ * These are the values used by hardware in the B field of
+ * SLB entries and the first dword of MMU hashtable entries.
+ * The B field is 2 bits; the values 2 and 3 are unused and reserved.
+ */
+#define MMU_SEGSIZE_256M       0
+#define MMU_SEGSIZE_1T         1
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -350,10 +360,13 @@ typedef unsigned long mm_context_id_t;
 
 typedef struct {
        mm_context_id_t id;
-       u16 user_psize;                 /* page size index */
-       u16 sllp;                       /* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
-       u16 low_htlb_areas, high_htlb_areas;
+       u16 user_psize;         /* page size index */
+
+#ifdef CONFIG_PPC_MM_SLICES
+       u64 low_slices_psize;   /* SLB page size encodings */
+       u64 high_slices_psize;  /* 4 bits per slice for now */
+#else
+       u16 sllp;               /* SLB page size encoding */
 #endif
        unsigned long vdso_base;
 } mm_context_t;
index d484ca94cb7c9b9a2c06c6627818db2ca6696022..19f299b7e256b93e4d8d1162153cc422ca1ceb72 100644 (file)
@@ -43,9 +43,5 @@ extern unsigned long max_pfn;
 
 #endif /* CONFIG_NEED_MULTIPLE_NODES */
 
-#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-extern int __init early_pfn_to_nid(unsigned long pfn);
-#endif
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_MMZONE_H_ */
index cf95274f735e43ea3e9120b9697e0b0be75177bf..c6a5b173566676c5d5bef92336f687c95bc13142 100644 (file)
@@ -83,8 +83,8 @@ struct paca_struct {
 
        mm_context_t context;
        u16 vmalloc_sllp;
-       u16 slb_cache[SLB_CACHE_ENTRIES];
        u16 slb_cache_ptr;
+       u16 slb_cache[SLB_CACHE_ENTRIES];
 
        /*
         * then miscellaneous read-write fields
index eab779c219958b18b82afd1ff5c55bc5de05f89b..3448a3d4bc64efc74d84a9c3e337a8989b108fd9 100644 (file)
@@ -88,57 +88,55 @@ extern unsigned int HPAGE_SHIFT;
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_PPC_MM_SLICES
 
-#define HTLB_AREA_SHIFT                40
-#define HTLB_AREA_SIZE         (1UL << HTLB_AREA_SHIFT)
-#define GET_HTLB_AREA(x)       ((x) >> HTLB_AREA_SHIFT)
+#define SLICE_LOW_SHIFT                28
+#define SLICE_HIGH_SHIFT       40
 
-#define LOW_ESID_MASK(addr, len)    \
-       (((1U << (GET_ESID(min((addr)+(len)-1, 0x100000000UL))+1)) \
-         - (1U << GET_ESID(min((addr), 0x100000000UL)))) & 0xffff)
-#define HTLB_AREA_MASK(addr, len)   (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
-                                     - (1U << GET_HTLB_AREA(addr))) & 0xffff)
+#define SLICE_LOW_TOP          (0x100000000ul)
+#define SLICE_NUM_LOW          (SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
+#define SLICE_NUM_HIGH         (PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
 
-#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define GET_LOW_SLICE_INDEX(addr)      ((addr) >> SLICE_LOW_SHIFT)
+#define GET_HIGH_SLICE_INDEX(addr)     ((addr) >> SLICE_HIGH_SHIFT)
 
-#define touches_hugepage_low_range(mm, addr, len) \
-       (((addr) < 0x100000000UL) \
-        && (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas))
-#define touches_hugepage_high_range(mm, addr, len) \
-       ((((addr) + (len)) > 0x100000000UL) \
-         && (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas))
-
-#define __within_hugepage_low_range(addr, len, segmask) \
-       ( (((addr)+(len)) <= 0x100000000UL) \
-         && ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask)))
-#define within_hugepage_low_range(addr, len) \
-       __within_hugepage_low_range((addr), (len), \
-                                   current->mm->context.low_htlb_areas)
-#define __within_hugepage_high_range(addr, len, zonemask) \
-       ( ((addr) >= 0x100000000UL) \
-         && ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask)))
-#define within_hugepage_high_range(addr, len) \
-       __within_hugepage_high_range((addr), (len), \
-                                   current->mm->context.high_htlb_areas)
-
-#define is_hugepage_only_range(mm, addr, len) \
-       (touches_hugepage_high_range((mm), (addr), (len)) || \
-         touches_hugepage_low_range((mm), (addr), (len)))
-#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#ifndef __ASSEMBLY__
+
+struct slice_mask {
+       u16 low_slices;
+       u16 high_slices;
+};
+
+struct mm_struct;
 
-#define in_hugepage_area(context, addr) \
-       (cpu_has_feature(CPU_FTR_16M_PAGE) && \
-        ( ( (addr) >= 0x100000000UL) \
-          ? ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) \
-          : ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) )
+extern unsigned long slice_get_unmapped_area(unsigned long addr,
+                                            unsigned long len,
+                                            unsigned long flags,
+                                            unsigned int psize,
+                                            int topdown,
+                                            int use_cache);
 
-#else /* !CONFIG_HUGETLB_PAGE */
+extern unsigned int get_slice_psize(struct mm_struct *mm,
+                                   unsigned long addr);
 
-#define in_hugepage_area(mm, addr)     0
+extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
+extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
+
+#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+extern int is_hugepage_only_range(struct mm_struct *m,
+                                 unsigned long addr,
+                                 unsigned long len);
+
+#endif /* __ASSEMBLY__ */
+#else
+#define slice_init()
+#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
 #endif /* !CONFIG_HUGETLB_PAGE */
 
index 30b50cf56e2c1da4b0178978844f767728aecc95..d9a3a8ca58a108ed0781e17ed9d80903a5176f7b 100644 (file)
 
 extern struct kmem_cache *pgtable_cache[];
 
-#ifdef CONFIG_PPC_64K_PAGES
-#define PTE_CACHE_NUM  0
-#define PMD_CACHE_NUM  1
-#define PGD_CACHE_NUM  2
-#define HUGEPTE_CACHE_NUM 3
-#else
-#define PTE_CACHE_NUM  0
-#define PMD_CACHE_NUM  1
-#define PUD_CACHE_NUM  1
-#define PGD_CACHE_NUM  0
-#define HUGEPTE_CACHE_NUM 2
-#endif
+#define PGD_CACHE_NUM          0
+#define PUD_CACHE_NUM          1
+#define PMD_CACHE_NUM          1
+#define HUGEPTE_CACHE_NUM      2
+#define PTE_NONCACHE_NUM       3  /* from GFP rather than kmem_cache */
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
@@ -91,8 +84,7 @@ static inline void pmd_free(pmd_t *pmd)
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                          unsigned long address)
 {
-       return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
-                               GFP_KERNEL|__GFP_REPEAT);
+        return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
@@ -103,12 +95,12 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm,
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-       kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
+       free_page((unsigned long)pte);
 }
 
 static inline void pte_free(struct page *ptepage)
 {
-       pte_free_kernel(page_address(ptepage));
+       __free_page(ptepage);
 }
 
 #define PGF_CACHENUM_MASK      0x3
@@ -130,14 +122,17 @@ static inline void pgtable_free(pgtable_free_t pgf)
        void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
        int cachenum = pgf.val & PGF_CACHENUM_MASK;
 
-       kmem_cache_free(pgtable_cache[cachenum], p);
+       if (cachenum == PTE_NONCACHE_NUM)
+               free_page((unsigned long)p);
+       else
+               kmem_cache_free(pgtable_cache[cachenum], p);
 }
 
 extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
 
 #define __pte_free_tlb(tlb, ptepage)   \
        pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
-               PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
+               PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1))
 #define __pmd_free_tlb(tlb, pmd)       \
        pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
                PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
index 1744d6ac12a2d4970fe473e6dcb061672e5d233c..add5481fd7c7ce3436d65b5eee5ec32f245978e2 100644 (file)
 
 #define pte_iterate_hashed_end() } while(0)
 
-#define pte_pagesize_index(pte)        MMU_PAGE_4K
+#ifdef CONFIG_PPC_HAS_HASH_64K
+#define pte_pagesize_index(mm, addr, pte)      get_slice_psize(mm, addr)
+#else
+#define pte_pagesize_index(mm, addr, pte)      MMU_PAGE_4K
+#endif
 
 /*
  * 4-level page tables related bits
index 16ef4978520dd276b15d2775bc89ef54261c3178..31cbd3d7fce82b24690e4ed4e0fa6a7b84d5ceda 100644 (file)
 #define _PAGE_HPTE_SUB0        0x08000000 /* combo only: first sub page */
 #define _PAGE_COMBO    0x10000000 /* this is a combo 4k page */
 #define _PAGE_4K_PFN   0x20000000 /* PFN is for a single 4k page */
+
+/* Note the full page bits must be in the same location as for normal
+ * 4k pages as the same asssembly will be used to insert 64K pages
+ * wether the kernel has CONFIG_PPC_64K_PAGES or not
+ */
 #define _PAGE_F_SECOND  0x00008000 /* full page: hidx bits */
 #define _PAGE_F_GIX     0x00007000 /* full page: hidx bits */
 
@@ -88,7 +93,7 @@
 
 #define pte_iterate_hashed_end() } while(0); } } while(0)
 
-#define pte_pagesize_index(pte)        \
+#define pte_pagesize_index(mm, addr, pte)      \
        (((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
 #define remap_4k_pfn(vma, addr, pfn, prot)                             \
index 9c7d1263103353745dfb10cece78ac1e3719d976..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,24 +1 @@
-#ifndef _ASM_POWERPC_POLL_H
-#define _ASM_POWERPC_POLL_H
-
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif /* _ASM_POWERPC_POLL_H */
+#include <asm-generic/poll.h>
index d74b2965bb82d007b793a36a593123b0c9cb8e2a..8e2005159ffd85e83aca379d785bc705e127f75e 100644 (file)
@@ -62,11 +62,14 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr);
 
 /**
  * eeh_slot_error_detail -- record and EEH error condition to the log
- * @severity: 1 if temporary, 2 if permanent failure.
+ * @pdn:      pci device node
+ * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE
  *
- * Obtains the the EEH error details from the RTAS subsystem,
+ * Obtains the EEH error details from the RTAS subsystem,
  * and then logs these details with the RTAS error log system.
  */
+#define EEH_LOG_TEMP_FAILURE 1
+#define EEH_LOG_PERM_FAILURE 2
 void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
 
 /**
@@ -82,6 +85,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function);
 
 /**
  * rtas_set_slot_reset -- unfreeze a frozen slot
+ * @pdn:       pci device node
  *
  * Clear the EEH-frozen condition on a slot.  This routine
  * does this by asserting the PCI #RST line for 1/8th of
@@ -95,6 +99,7 @@ int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
 
 /** 
  * eeh_restore_bars - Restore device configuration info.
+ * @pdn:       pci device node
  *
  * A reset of a PCI device will clear out its config space.
  * This routines will restore the config space for this
@@ -105,6 +110,7 @@ void eeh_restore_bars(struct pci_dn *);
 
 /**
  * rtas_configure_bridge -- firmware initialization of pci bridge
+ * @pdn:       pci device node
  *
  * Ask the firmware to configure all PCI bridges devices
  * located behind the indicated node. Required after a
@@ -118,16 +124,22 @@ int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
 
 /**
+ * eeh_mark_slot -- set mode flags for pertition endpoint
+ * @pdn:       pci device node
+ *
  * mark and clear slots: find "partition endpoint" PE and set or 
  * clear the flags for each subnode of the PE.
  */
 void eeh_mark_slot (struct device_node *dn, int mode_flag);
 void eeh_clear_slot (struct device_node *dn, int mode_flag);
 
-/* Find the associated "Partiationable Endpoint" PE */
+/**
+ * find_device_pe -- Find the associated "Partiationable Endpoint" PE
+ * @pdn:       pci device node
+ */
 struct device_node * find_device_pe(struct device_node *dn);
 
-#endif
+#endif /* CONFIG_EEH */
 
 #else /* CONFIG_PCI */
 static inline void find_and_init_phbs(void) { }
index 13c372df99e84aafa69256c4fa7af52c14989be8..1e04651eedc4bbc7819b0e17549af58cd6181d49 100644 (file)
@@ -377,8 +377,13 @@ int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
 
 /* system manager */
 
+#ifdef CONFIG_PS3_SYS_MANAGER
 void ps3_sys_manager_restart(void);
 void ps3_sys_manager_power_off(void);
+#else
+static inline void ps3_sys_manager_restart(void) {}
+static inline void ps3_sys_manager_power_off(void) {}
+#endif
 
 struct ps3_prealloc {
     const char *name;
index a62168ec535fc3a522a8c67167a41c9729f80e33..9d304b1f1608bf94f2e0b145d6ebc18afab75222 100644 (file)
@@ -38,11 +38,11 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input);
 void qe_setbrg(u32 brg, u32 rate);
 int qe_get_snum(void);
 void qe_put_snum(u8 snum);
-u32 qe_muram_alloc(u32 size, u32 align);
-int qe_muram_free(u32 offset);
-u32 qe_muram_alloc_fixed(u32 offset, u32 size);
+unsigned long qe_muram_alloc(int size, int align);
+int qe_muram_free(unsigned long offset);
+unsigned long qe_muram_alloc_fixed(unsigned long offset, int size);
 void qe_muram_dump(void);
-void *qe_muram_addr(u32 offset);
+void *qe_muram_addr(unsigned long offset);
 
 /* Buffer descriptors */
 struct qe_bd {
@@ -448,10 +448,5 @@ struct ucc_slow_pram {
 #define UCC_FAST_FUNCTION_CODE_DTB_LCL 0x02
 #define UCC_FAST_FUNCTION_CODE_BDB_LCL 0x01
 
-static inline long IS_MURAM_ERR(const u32 offset)
-{
-       return offset > (u32) - 1000L;
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_QE_H */
diff --git a/include/asm-powerpc/reg_booke.h b/include/asm-powerpc/reg_booke.h
new file mode 100644 (file)
index 0000000..064405c
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Contains register definitions common to the Book E PowerPC
+ * specification.  Notice that while the IBM-40x series of CPUs
+ * are not true Book E PowerPCs, they borrowed a number of features
+ * before Book E was finalized, and are included here as well.  Unfortunatly,
+ * they sometimes used different locations than true Book E CPUs did.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_REG_BOOKE_H__
+#define __ASM_POWERPC_REG_BOOKE_H__
+
+#ifndef __ASSEMBLY__
+/* Performance Monitor Registers */
+#define mfpmr(rn)      ({unsigned int rval; \
+                       asm volatile("mfpmr %0," __stringify(rn) \
+                                    : "=r" (rval)); rval;})
+#define mtpmr(rn, v)   asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
+#endif /* __ASSEMBLY__ */
+
+/* Freescale Book E Performance Monitor APU Registers */
+#define PMRN_PMC0      0x010   /* Performance Monitor Counter 0 */
+#define PMRN_PMC1      0x011   /* Performance Monitor Counter 1 */
+#define PMRN_PMC2      0x012   /* Performance Monitor Counter 1 */
+#define PMRN_PMC3      0x013   /* Performance Monitor Counter 1 */
+#define PMRN_PMLCA0    0x090   /* PM Local Control A0 */
+#define PMRN_PMLCA1    0x091   /* PM Local Control A1 */
+#define PMRN_PMLCA2    0x092   /* PM Local Control A2 */
+#define PMRN_PMLCA3    0x093   /* PM Local Control A3 */
+
+#define PMLCA_FC       0x80000000      /* Freeze Counter */
+#define PMLCA_FCS      0x40000000      /* Freeze in Supervisor */
+#define PMLCA_FCU      0x20000000      /* Freeze in User */
+#define PMLCA_FCM1     0x10000000      /* Freeze when PMM==1 */
+#define PMLCA_FCM0     0x08000000      /* Freeze when PMM==0 */
+#define PMLCA_CE       0x04000000      /* Condition Enable */
+
+#define PMLCA_EVENT_MASK 0x007f0000    /* Event field */
+#define PMLCA_EVENT_SHIFT      16
+
+#define PMRN_PMLCB0    0x110   /* PM Local Control B0 */
+#define PMRN_PMLCB1    0x111   /* PM Local Control B1 */
+#define PMRN_PMLCB2    0x112   /* PM Local Control B2 */
+#define PMRN_PMLCB3    0x113   /* PM Local Control B3 */
+
+#define PMLCB_THRESHMUL_MASK   0x0700  /* Threshhold Multiple Field */
+#define PMLCB_THRESHMUL_SHIFT  8
+
+#define PMLCB_THRESHOLD_MASK   0x003f  /* Threshold Field */
+#define PMLCB_THRESHOLD_SHIFT  0
+
+#define PMRN_PMGC0     0x190   /* PM Global Control 0 */
+
+#define PMGC0_FAC      0x80000000      /* Freeze all Counters */
+#define PMGC0_PMIE     0x40000000      /* Interrupt Enable */
+#define PMGC0_FCECE    0x20000000      /* Freeze countes on
+                                          Enabled Condition or
+                                          Event */
+
+#define PMRN_UPMC0     0x000   /* User Performance Monitor Counter 0 */
+#define PMRN_UPMC1     0x001   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC2     0x002   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC3     0x003   /* User Performance Monitor Counter 1 */
+#define PMRN_UPMLCA0   0x080   /* User PM Local Control A0 */
+#define PMRN_UPMLCA1   0x081   /* User PM Local Control A1 */
+#define PMRN_UPMLCA2   0x082   /* User PM Local Control A2 */
+#define PMRN_UPMLCA3   0x083   /* User PM Local Control A3 */
+#define PMRN_UPMLCB0   0x100   /* User PM Local Control B0 */
+#define PMRN_UPMLCB1   0x101   /* User PM Local Control B1 */
+#define PMRN_UPMLCB2   0x102   /* User PM Local Control B2 */
+#define PMRN_UPMLCB3   0x103   /* User PM Local Control B3 */
+#define PMRN_UPMGC0    0x180   /* User PM Global Control 0 */
+
+
+/* Machine State Register (MSR) Fields */
+#define MSR_UCLE       (1<<26) /* User-mode cache lock enable */
+#define MSR_SPE                (1<<25) /* Enable SPE */
+#define MSR_DWE                (1<<10) /* Debug Wait Enable */
+#define MSR_UBLE       (1<<10) /* BTB lock enable (e500) */
+#define MSR_IS         MSR_IR  /* Instruction Space */
+#define MSR_DS         MSR_DR  /* Data Space */
+#define MSR_PMM                (1<<2)  /* Performance monitor mark bit */
+
+/* Default MSR for kernel mode. */
+#if defined (CONFIG_40x)
+#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
+#elif defined(CONFIG_BOOKE)
+#define MSR_KERNEL     (MSR_ME|MSR_RI|MSR_CE)
+#endif
+
+/* Special Purpose Registers (SPRNs)*/
+#define SPRN_DECAR     0x036   /* Decrementer Auto Reload Register */
+#define SPRN_IVPR      0x03F   /* Interrupt Vector Prefix Register */
+#define SPRN_USPRG0    0x100   /* User Special Purpose Register General 0 */
+#define SPRN_SPRG4R    0x104   /* Special Purpose Register General 4 Read */
+#define SPRN_SPRG5R    0x105   /* Special Purpose Register General 5 Read */
+#define SPRN_SPRG6R    0x106   /* Special Purpose Register General 6 Read */
+#define SPRN_SPRG7R    0x107   /* Special Purpose Register General 7 Read */
+#define SPRN_SPRG4W    0x114   /* Special Purpose Register General 4 Write */
+#define SPRN_SPRG5W    0x115   /* Special Purpose Register General 5 Write */
+#define SPRN_SPRG6W    0x116   /* Special Purpose Register General 6 Write */
+#define SPRN_SPRG7W    0x117   /* Special Purpose Register General 7 Write */
+#define SPRN_DBCR2     0x136   /* Debug Control Register 2 */
+#define SPRN_IAC3      0x13A   /* Instruction Address Compare 3 */
+#define SPRN_IAC4      0x13B   /* Instruction Address Compare 4 */
+#define SPRN_DVC1      0x13E   /* Data Value Compare Register 1 */
+#define SPRN_DVC2      0x13F   /* Data Value Compare Register 2 */
+#define SPRN_IVOR0     0x190   /* Interrupt Vector Offset Register 0 */
+#define SPRN_IVOR1     0x191   /* Interrupt Vector Offset Register 1 */
+#define SPRN_IVOR2     0x192   /* Interrupt Vector Offset Register 2 */
+#define SPRN_IVOR3     0x193   /* Interrupt Vector Offset Register 3 */
+#define SPRN_IVOR4     0x194   /* Interrupt Vector Offset Register 4 */
+#define SPRN_IVOR5     0x195   /* Interrupt Vector Offset Register 5 */
+#define SPRN_IVOR6     0x196   /* Interrupt Vector Offset Register 6 */
+#define SPRN_IVOR7     0x197   /* Interrupt Vector Offset Register 7 */
+#define SPRN_IVOR8     0x198   /* Interrupt Vector Offset Register 8 */
+#define SPRN_IVOR9     0x199   /* Interrupt Vector Offset Register 9 */
+#define SPRN_IVOR10    0x19A   /* Interrupt Vector Offset Register 10 */
+#define SPRN_IVOR11    0x19B   /* Interrupt Vector Offset Register 11 */
+#define SPRN_IVOR12    0x19C   /* Interrupt Vector Offset Register 12 */
+#define SPRN_IVOR13    0x19D   /* Interrupt Vector Offset Register 13 */
+#define SPRN_IVOR14    0x19E   /* Interrupt Vector Offset Register 14 */
+#define SPRN_IVOR15    0x19F   /* Interrupt Vector Offset Register 15 */
+#define SPRN_SPEFSCR   0x200   /* SPE & Embedded FP Status & Control */
+#define SPRN_BBEAR     0x201   /* Branch Buffer Entry Address Register */
+#define SPRN_BBTAR     0x202   /* Branch Buffer Target Address Register */
+#define SPRN_IVOR32    0x210   /* Interrupt Vector Offset Register 32 */
+#define SPRN_IVOR33    0x211   /* Interrupt Vector Offset Register 33 */
+#define SPRN_IVOR34    0x212   /* Interrupt Vector Offset Register 34 */
+#define SPRN_IVOR35    0x213   /* Interrupt Vector Offset Register 35 */
+#define SPRN_MCSRR0    0x23A   /* Machine Check Save and Restore Register 0 */
+#define SPRN_MCSRR1    0x23B   /* Machine Check Save and Restore Register 1 */
+#define SPRN_MCSR      0x23C   /* Machine Check Status Register */
+#define SPRN_MCAR      0x23D   /* Machine Check Address Register */
+#define SPRN_DSRR0     0x23E   /* Debug Save and Restore Register 0 */
+#define SPRN_DSRR1     0x23F   /* Debug Save and Restore Register 1 */
+#define SPRN_MAS0      0x270   /* MMU Assist Register 0 */
+#define SPRN_MAS1      0x271   /* MMU Assist Register 1 */
+#define SPRN_MAS2      0x272   /* MMU Assist Register 2 */
+#define SPRN_MAS3      0x273   /* MMU Assist Register 3 */
+#define SPRN_MAS4      0x274   /* MMU Assist Register 4 */
+#define SPRN_MAS5      0x275   /* MMU Assist Register 5 */
+#define SPRN_MAS6      0x276   /* MMU Assist Register 6 */
+#define SPRN_MAS7      0x3b0   /* MMU Assist Register 7 */
+#define SPRN_PID1      0x279   /* Process ID Register 1 */
+#define SPRN_PID2      0x27A   /* Process ID Register 2 */
+#define SPRN_TLB0CFG   0x2B0   /* TLB 0 Config Register */
+#define SPRN_TLB1CFG   0x2B1   /* TLB 1 Config Register */
+#define SPRN_CCR1      0x378   /* Core Configuration Register 1 */
+#define SPRN_ZPR       0x3B0   /* Zone Protection Register (40x) */
+#define SPRN_MMUCR     0x3B2   /* MMU Control Register */
+#define SPRN_CCR0      0x3B3   /* Core Configuration Register 0 */
+#define SPRN_SGR       0x3B9   /* Storage Guarded Register */
+#define SPRN_DCWR      0x3BA   /* Data Cache Write-thru Register */
+#define SPRN_SLER      0x3BB   /* Little-endian real mode */
+#define SPRN_SU0R      0x3BC   /* "User 0" real mode (40x) */
+#define SPRN_DCMP      0x3D1   /* Data TLB Compare Register */
+#define SPRN_ICDBDR    0x3D3   /* Instruction Cache Debug Data Register */
+#define SPRN_EVPR      0x3D6   /* Exception Vector Prefix Register */
+#define SPRN_L1CSR0    0x3F2   /* L1 Cache Control and Status Register 0 */
+#define SPRN_L1CSR1    0x3F3   /* L1 Cache Control and Status Register 1 */
+#define SPRN_PIT       0x3DB   /* Programmable Interval Timer */
+#define SPRN_DCCR      0x3FA   /* Data Cache Cacheability Register */
+#define SPRN_ICCR      0x3FB   /* Instruction Cache Cacheability Register */
+#define SPRN_SVR       0x3FF   /* System Version Register */
+
+/*
+ * SPRs which have conflicting definitions on true Book E versus classic,
+ * or IBM 40x.
+ */
+#ifdef CONFIG_BOOKE
+#define SPRN_PID       0x030   /* Process ID */
+#define SPRN_PID0      SPRN_PID/* Process ID Register 0 */
+#define SPRN_CSRR0     0x03A   /* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1     0x03B   /* Critical Save and Restore Register 1 */
+#define SPRN_DEAR      0x03D   /* Data Error Address Register */
+#define SPRN_ESR       0x03E   /* Exception Syndrome Register */
+#define SPRN_PIR       0x11E   /* Processor Identification Register */
+#define SPRN_DBSR      0x130   /* Debug Status Register */
+#define SPRN_DBCR0     0x134   /* Debug Control Register 0 */
+#define SPRN_DBCR1     0x135   /* Debug Control Register 1 */
+#define SPRN_IAC1      0x138   /* Instruction Address Compare 1 */
+#define SPRN_IAC2      0x139   /* Instruction Address Compare 2 */
+#define SPRN_DAC1      0x13C   /* Data Address Compare 1 */
+#define SPRN_DAC2      0x13D   /* Data Address Compare 2 */
+#define SPRN_TSR       0x150   /* Timer Status Register */
+#define SPRN_TCR       0x154   /* Timer Control Register */
+#endif /* Book E */
+#ifdef CONFIG_40x
+#define SPRN_PID       0x3B1   /* Process ID */
+#define SPRN_DBCR1     0x3BD   /* Debug Control Register 1 */          
+#define SPRN_ESR       0x3D4   /* Exception Syndrome Register */
+#define SPRN_DEAR      0x3D5   /* Data Error Address Register */
+#define SPRN_TSR       0x3D8   /* Timer Status Register */
+#define SPRN_TCR       0x3DA   /* Timer Control Register */
+#define SPRN_SRR2      0x3DE   /* Save/Restore Register 2 */
+#define SPRN_SRR3      0x3DF   /* Save/Restore Register 3 */
+#define SPRN_DBSR      0x3F0   /* Debug Status Register */             
+#define SPRN_DBCR0     0x3F2   /* Debug Control Register 0 */
+#define SPRN_DAC1      0x3F6   /* Data Address Compare 1 */
+#define SPRN_DAC2      0x3F7   /* Data Address Compare 2 */
+#define SPRN_CSRR0     SPRN_SRR2 /* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1     SPRN_SRR3 /* Critical Save and Restore Register 1 */
+#endif
+
+/* Bit definitions for CCR1. */
+#define        CCR1_DPC        0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
+#define        CCR1_TCS        0x00000080 /* Timer Clock Select */
+
+/* Bit definitions for the MCSR. */
+#ifdef CONFIG_440A
+#define MCSR_MCS       0x80000000 /* Machine Check Summary */
+#define MCSR_IB                0x40000000 /* Instruction PLB Error */
+#define MCSR_DRB       0x20000000 /* Data Read PLB Error */
+#define MCSR_DWB       0x10000000 /* Data Write PLB Error */
+#define MCSR_TLBP      0x08000000 /* TLB Parity Error */
+#define MCSR_ICP       0x04000000 /* I-Cache Parity Error */
+#define MCSR_DCSP      0x02000000 /* D-Cache Search Parity Error */
+#define MCSR_DCFP      0x01000000 /* D-Cache Flush Parity Error */
+#define MCSR_IMPE      0x00800000 /* Imprecise Machine Check Exception */
+#endif
+#ifdef CONFIG_E500
+#define MCSR_MCP       0x80000000UL /* Machine Check Input Pin */
+#define MCSR_ICPERR    0x40000000UL /* I-Cache Parity Error */
+#define MCSR_DCP_PERR  0x20000000UL /* D-Cache Push Parity Error */
+#define MCSR_DCPERR    0x10000000UL /* D-Cache Parity Error */
+#define MCSR_GL_CI     0x00010000UL /* Guarded Load or Cache-Inhibited stwcx. */
+#define MCSR_BUS_IAERR         0x00000080UL /* Instruction Address Error */
+#define MCSR_BUS_RAERR         0x00000040UL /* Read Address Error */
+#define MCSR_BUS_WAERR         0x00000020UL /* Write Address Error */
+#define MCSR_BUS_IBERR         0x00000010UL /* Instruction Data Error */
+#define MCSR_BUS_RBERR         0x00000008UL /* Read Data Bus Error */
+#define MCSR_BUS_WBERR         0x00000004UL /* Write Data Bus Error */
+#define MCSR_BUS_IPERR         0x00000002UL /* Instruction parity Error */
+#define MCSR_BUS_RPERR         0x00000001UL /* Read parity Error */
+#endif
+#ifdef CONFIG_E200
+#define MCSR_MCP       0x80000000UL /* Machine Check Input Pin */
+#define MCSR_CP_PERR   0x20000000UL /* Cache Push Parity Error */
+#define MCSR_CPERR     0x10000000UL /* Cache Parity Error */
+#define MCSR_EXCP_ERR  0x08000000UL /* ISI, ITLB, or Bus Error on 1st insn
+                                       fetch for an exception handler */
+#define MCSR_BUS_IRERR         0x00000010UL /* Read Bus Error on instruction fetch*/
+#define MCSR_BUS_DRERR         0x00000008UL /* Read Bus Error on data load */
+#define MCSR_BUS_WRERR         0x00000004UL /* Write Bus Error on buffered
+                                       store or cache line push */
+#endif
+
+/* Bit definitions for the DBSR. */
+/*
+ * DBSR bits which have conflicting definitions on true Book E versus IBM 40x.
+ */
+#ifdef CONFIG_BOOKE
+#define DBSR_IC                0x08000000      /* Instruction Completion */
+#define DBSR_BT                0x04000000      /* Branch Taken */
+#define DBSR_TIE       0x01000000      /* Trap Instruction Event */
+#define DBSR_IAC1      0x00800000      /* Instr Address Compare 1 Event */
+#define DBSR_IAC2      0x00400000      /* Instr Address Compare 2 Event */
+#define DBSR_IAC3      0x00200000      /* Instr Address Compare 3 Event */
+#define DBSR_IAC4      0x00100000      /* Instr Address Compare 4 Event */
+#define DBSR_DAC1R     0x00080000      /* Data Addr Compare 1 Read Event */
+#define DBSR_DAC1W     0x00040000      /* Data Addr Compare 1 Write Event */
+#define DBSR_DAC2R     0x00020000      /* Data Addr Compare 2 Read Event */
+#define DBSR_DAC2W     0x00010000      /* Data Addr Compare 2 Write Event */
+#endif
+#ifdef CONFIG_40x
+#define DBSR_IC                0x80000000      /* Instruction Completion */
+#define DBSR_BT                0x40000000      /* Branch taken */
+#define DBSR_TIE       0x10000000      /* Trap Instruction debug Event */
+#define DBSR_IAC1      0x04000000      /* Instruction Address Compare 1 Event */
+#define DBSR_IAC2      0x02000000      /* Instruction Address Compare 2 Event */
+#define DBSR_IAC3      0x00080000      /* Instruction Address Compare 3 Event */
+#define DBSR_IAC4      0x00040000      /* Instruction Address Compare 4 Event */
+#define DBSR_DAC1R     0x01000000      /* Data Address Compare 1 Read Event */
+#define DBSR_DAC1W     0x00800000      /* Data Address Compare 1 Write Event */
+#define DBSR_DAC2R     0x00400000      /* Data Address Compare 2 Read Event */
+#define DBSR_DAC2W     0x00200000      /* Data Address Compare 2 Write Event */
+#endif
+
+/* Bit definitions related to the ESR. */
+#define ESR_MCI                0x80000000      /* Machine Check - Instruction */
+#define ESR_IMCP       0x80000000      /* Instr. Machine Check - Protection */
+#define ESR_IMCN       0x40000000      /* Instr. Machine Check - Non-config */
+#define ESR_IMCB       0x20000000      /* Instr. Machine Check - Bus error */
+#define ESR_IMCT       0x10000000      /* Instr. Machine Check - Timeout */
+#define ESR_PIL                0x08000000      /* Program Exception - Illegal */
+#define ESR_PPR                0x04000000      /* Program Exception - Priveleged */
+#define ESR_PTR                0x02000000      /* Program Exception - Trap */
+#define ESR_FP         0x01000000      /* Floating Point Operation */
+#define ESR_DST                0x00800000      /* Storage Exception - Data miss */
+#define ESR_DIZ                0x00400000      /* Storage Exception - Zone fault */
+#define ESR_ST         0x00800000      /* Store Operation */
+#define ESR_DLK                0x00200000      /* Data Cache Locking */
+#define ESR_ILK                0x00100000      /* Instr. Cache Locking */
+#define ESR_PUO                0x00040000      /* Unimplemented Operation exception */
+#define ESR_BO         0x00020000      /* Byte Ordering */
+
+/* Bit definitions related to the DBCR0. */
+#define DBCR0_EDM      0x80000000      /* External Debug Mode */
+#define DBCR0_IDM      0x40000000      /* Internal Debug Mode */
+#define DBCR0_RST      0x30000000      /* all the bits in the RST field */
+#define DBCR0_RST_SYSTEM 0x30000000    /* System Reset */
+#define DBCR0_RST_CHIP 0x20000000      /* Chip Reset */
+#define DBCR0_RST_CORE 0x10000000      /* Core Reset */
+#define DBCR0_RST_NONE 0x00000000      /* No Reset */
+#define DBCR0_IC       0x08000000      /* Instruction Completion */
+#define DBCR0_BT       0x04000000      /* Branch Taken */
+#define DBCR0_EDE      0x02000000      /* Exception Debug Event */
+#define DBCR0_TDE      0x01000000      /* TRAP Debug Event */
+#define DBCR0_IA1      0x00800000      /* Instr Addr compare 1 enable */
+#define DBCR0_IA2      0x00400000      /* Instr Addr compare 2 enable */
+#define DBCR0_IA12     0x00200000      /* Instr Addr 1-2 range enable */
+#define DBCR0_IA12X    0x00100000      /* Instr Addr 1-2 range eXclusive */
+#define DBCR0_IA3      0x00080000      /* Instr Addr compare 3 enable */
+#define DBCR0_IA4      0x00040000      /* Instr Addr compare 4 enable */
+#define DBCR0_IA34     0x00020000      /* Instr Addr 3-4 range Enable */
+#define DBCR0_IA34X    0x00010000      /* Instr Addr 3-4 range eXclusive */
+#define DBCR0_IA12T    0x00008000      /* Instr Addr 1-2 range Toggle */
+#define DBCR0_IA34T    0x00004000      /* Instr Addr 3-4 range Toggle */
+#define DBCR0_FT       0x00000001      /* Freeze Timers on debug event */
+
+/* Bit definitions related to the TCR. */
+#define TCR_WP(x)      (((x)&0x3)<<30) /* WDT Period */
+#define TCR_WP_MASK    TCR_WP(3)
+#define WP_2_17                0               /* 2^17 clocks */
+#define WP_2_21                1               /* 2^21 clocks */
+#define WP_2_25                2               /* 2^25 clocks */
+#define WP_2_29                3               /* 2^29 clocks */
+#define TCR_WRC(x)     (((x)&0x3)<<28) /* WDT Reset Control */
+#define TCR_WRC_MASK   TCR_WRC(3)
+#define WRC_NONE       0               /* No reset will occur */
+#define WRC_CORE       1               /* Core reset will occur */
+#define WRC_CHIP       2               /* Chip reset will occur */
+#define WRC_SYSTEM     3               /* System reset will occur */
+#define TCR_WIE                0x08000000      /* WDT Interrupt Enable */
+#define TCR_PIE                0x04000000      /* PIT Interrupt Enable */
+#define TCR_DIE                TCR_PIE         /* DEC Interrupt Enable */
+#define TCR_FP(x)      (((x)&0x3)<<24) /* FIT Period */
+#define TCR_FP_MASK    TCR_FP(3)
+#define FP_2_9         0               /* 2^9 clocks */
+#define FP_2_13                1               /* 2^13 clocks */
+#define FP_2_17                2               /* 2^17 clocks */
+#define FP_2_21                3               /* 2^21 clocks */
+#define TCR_FIE                0x00800000      /* FIT Interrupt Enable */
+#define TCR_ARE                0x00400000      /* Auto Reload Enable */
+
+/* Bit definitions for the TSR. */
+#define TSR_ENW                0x80000000      /* Enable Next Watchdog */
+#define TSR_WIS                0x40000000      /* WDT Interrupt Status */
+#define TSR_WRS(x)     (((x)&0x3)<<28) /* WDT Reset Status */
+#define WRS_NONE       0               /* No WDT reset occurred */
+#define WRS_CORE       1               /* WDT forced core reset */
+#define WRS_CHIP       2               /* WDT forced chip reset */
+#define WRS_SYSTEM     3               /* WDT forced system reset */
+#define TSR_PIS                0x08000000      /* PIT Interrupt Status */
+#define TSR_DIS                TSR_PIS         /* DEC Interrupt Status */
+#define TSR_FIS                0x04000000      /* FIT Interrupt Status */
+
+/* Bit definitions for the DCCR. */
+#define DCCR_NOCACHE   0               /* Noncacheable */
+#define DCCR_CACHE     1               /* Cacheable */
+
+/* Bit definitions for DCWR. */
+#define DCWR_COPY      0               /* Copy-back */
+#define DCWR_WRITE     1               /* Write-through */
+
+/* Bit definitions for ICCR. */
+#define ICCR_NOCACHE   0               /* Noncacheable */
+#define ICCR_CACHE     1               /* Cacheable */
+
+/* Bit definitions for L1CSR0. */
+#define L1CSR0_CLFC    0x00000100      /* Cache Lock Bits Flash Clear */
+#define L1CSR0_DCFI    0x00000002      /* Data Cache Flash Invalidate */
+#define L1CSR0_CFI     0x00000002      /* Cache Flash Invalidate */
+#define L1CSR0_DCE     0x00000001      /* Data Cache Enable */
+
+/* Bit definitions for L1CSR1. */
+#define L1CSR1_ICLFR   0x00000100      /* Instr Cache Lock Bits Flash Reset */
+#define L1CSR1_ICFI    0x00000002      /* Instr Cache Flash Invalidate */
+#define L1CSR1_ICE     0x00000001      /* Instr Cache Enable */
+
+/* Bit definitions for SGR. */
+#define SGR_NORMAL     0               /* Speculative fetching allowed. */
+#define SGR_GUARDED    1               /* Speculative fetching disallowed. */
+
+/* Bit definitions for SPEFSCR. */
+#define SPEFSCR_SOVH   0x80000000      /* Summary integer overflow high */
+#define SPEFSCR_OVH    0x40000000      /* Integer overflow high */
+#define SPEFSCR_FGH    0x20000000      /* Embedded FP guard bit high */
+#define SPEFSCR_FXH    0x10000000      /* Embedded FP sticky bit high */
+#define SPEFSCR_FINVH  0x08000000      /* Embedded FP invalid operation high */
+#define SPEFSCR_FDBZH  0x04000000      /* Embedded FP div by zero high */
+#define SPEFSCR_FUNFH  0x02000000      /* Embedded FP underflow high */
+#define SPEFSCR_FOVFH  0x01000000      /* Embedded FP overflow high */
+#define SPEFSCR_FINXS  0x00200000      /* Embedded FP inexact sticky */
+#define SPEFSCR_FINVS  0x00100000      /* Embedded FP invalid op. sticky */
+#define SPEFSCR_FDBZS  0x00080000      /* Embedded FP div by zero sticky */
+#define SPEFSCR_FUNFS  0x00040000      /* Embedded FP underflow sticky */
+#define SPEFSCR_FOVFS  0x00020000      /* Embedded FP overflow sticky */
+#define SPEFSCR_MODE   0x00010000      /* Embedded FP mode */
+#define SPEFSCR_SOV    0x00008000      /* Integer summary overflow */
+#define SPEFSCR_OV     0x00004000      /* Integer overflow */
+#define SPEFSCR_FG     0x00002000      /* Embedded FP guard bit */
+#define SPEFSCR_FX     0x00001000      /* Embedded FP sticky bit */
+#define SPEFSCR_FINV   0x00000800      /* Embedded FP invalid operation */
+#define SPEFSCR_FDBZ   0x00000400      /* Embedded FP div by zero */
+#define SPEFSCR_FUNF   0x00000200      /* Embedded FP underflow */
+#define SPEFSCR_FOVF   0x00000100      /* Embedded FP overflow */
+#define SPEFSCR_FINXE  0x00000040      /* Embedded FP inexact enable */
+#define SPEFSCR_FINVE  0x00000020      /* Embedded FP invalid op. enable */
+#define SPEFSCR_FDBZE  0x00000010      /* Embedded FP div by zero enable */
+#define SPEFSCR_FUNFE  0x00000008      /* Embedded FP underflow enable */
+#define SPEFSCR_FOVFE  0x00000004      /* Embedded FP overflow enable */
+#define SPEFSCR_FRMC   0x00000003      /* Embedded FP rounding mode control */
+
+/*
+ * The IBM-403 is an even more odd special case, as it is much
+ * older than the IBM-405 series.  We put these down here incase someone
+ * wishes to support these machines again.
+ */
+#ifdef CONFIG_403GCX
+/* Special Purpose Registers (SPRNs)*/
+#define SPRN_TBHU      0x3CC   /* Time Base High User-mode */
+#define SPRN_TBLU      0x3CD   /* Time Base Low User-mode */
+#define SPRN_CDBCR     0x3D7   /* Cache Debug Control Register */
+#define SPRN_TBHI      0x3DC   /* Time Base High */
+#define SPRN_TBLO      0x3DD   /* Time Base Low */
+#define SPRN_DBCR      0x3F2   /* Debug Control Regsiter */
+#define SPRN_PBL1      0x3FC   /* Protection Bound Lower 1 */
+#define SPRN_PBL2      0x3FE   /* Protection Bound Lower 2 */
+#define SPRN_PBU1      0x3FD   /* Protection Bound Upper 1 */
+#define SPRN_PBU2      0x3FF   /* Protection Bound Upper 2 */
+
+
+/* Bit definitions for the DBCR. */
+#define DBCR_EDM       DBCR0_EDM
+#define DBCR_IDM       DBCR0_IDM
+#define DBCR_RST(x)    (((x) & 0x3) << 28)
+#define DBCR_RST_NONE  0
+#define DBCR_RST_CORE  1
+#define DBCR_RST_CHIP  2
+#define DBCR_RST_SYSTEM        3
+#define DBCR_IC                DBCR0_IC        /* Instruction Completion Debug Evnt */
+#define DBCR_BT                DBCR0_BT        /* Branch Taken Debug Event */
+#define DBCR_EDE       DBCR0_EDE       /* Exception Debug Event */
+#define DBCR_TDE       DBCR0_TDE       /* TRAP Debug Event */
+#define DBCR_FER       0x00F80000      /* First Events Remaining Mask */
+#define DBCR_FT                0x00040000      /* Freeze Timers on Debug Event */
+#define DBCR_IA1       0x00020000      /* Instr. Addr. Compare 1 Enable */
+#define DBCR_IA2       0x00010000      /* Instr. Addr. Compare 2 Enable */
+#define DBCR_D1R       0x00008000      /* Data Addr. Compare 1 Read Enable */
+#define DBCR_D1W       0x00004000      /* Data Addr. Compare 1 Write Enable */
+#define DBCR_D1S(x)    (((x) & 0x3) << 12)     /* Data Adrr. Compare 1 Size */
+#define DAC_BYTE       0
+#define DAC_HALF       1
+#define DAC_WORD       2
+#define DAC_QUAD       3
+#define DBCR_D2R       0x00000800      /* Data Addr. Compare 2 Read Enable */
+#define DBCR_D2W       0x00000400      /* Data Addr. Compare 2 Write Enable */
+#define DBCR_D2S(x)    (((x) & 0x3) << 8)      /* Data Addr. Compare 2 Size */
+#define DBCR_SBT       0x00000040      /* Second Branch Taken Debug Event */
+#define DBCR_SED       0x00000020      /* Second Exception Debug Event */
+#define DBCR_STD       0x00000010      /* Second Trap Debug Event */
+#define DBCR_SIA       0x00000008      /* Second IAC Enable */
+#define DBCR_SDA       0x00000004      /* Second DAC Enable */
+#define DBCR_JOI       0x00000002      /* JTAG Serial Outbound Int. Enable */
+#define DBCR_JII       0x00000001      /* JTAG Serial Inbound Int. Enable */
+#endif /* 403GCX */
+#endif /* __ASM_POWERPC_REG_BOOKE_H__ */
+#endif /* __KERNEL__ */
similarity index 75%
rename from include/asm-ppc/rheap.h
rename to include/asm-powerpc/rheap.h
index 39a10d86224431e20dc9a9e584caa924b05b76cd..172381769cfcf1f540234cab7591d07b973811ad 100644 (file)
@@ -18,7 +18,7 @@
 
 typedef struct _rh_block {
        struct list_head list;
-       void *start;
+       unsigned long start;
        int size;
        const char *owner;
 } rh_block_t;
@@ -37,8 +37,8 @@ typedef struct _rh_info {
 #define RHIF_STATIC_INFO       0x1
 #define RHIF_STATIC_BLOCK      0x2
 
-typedef struct rh_stats_t {
-       void *start;
+typedef struct _rh_stats {
+       unsigned long start;
        int size;
        const char *owner;
 } rh_stats_t;
@@ -57,24 +57,24 @@ extern void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
                    rh_block_t * block);
 
 /* Attach a free region to manage */
-extern int rh_attach_region(rh_info_t * info, void *start, int size);
+extern int rh_attach_region(rh_info_t * info, unsigned long start, int size);
 
 /* Detach a free region */
-extern void *rh_detach_region(rh_info_t * info, void *start, int size);
+extern unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size);
 
 /* Allocate the given size from the remote heap (with alignment) */
-extern void *rh_alloc_align(rh_info_t * info, int size, int alignment,
+extern unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment,
                const char *owner);
 
 /* Allocate the given size from the remote heap */
-extern void *rh_alloc(rh_info_t * info, int size, const char *owner);
+extern unsigned long rh_alloc(rh_info_t * info, int size, const char *owner);
 
 /* Allocate the given size from the given address */
-extern void *rh_alloc_fixed(rh_info_t * info, void *start, int size,
+extern unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size,
                            const char *owner);
 
 /* Free the allocated area */
-extern int rh_free(rh_info_t * info, void *start);
+extern int rh_free(rh_info_t * info, unsigned long start);
 
 /* Get stats for debugging purposes */
 extern int rh_get_stats(rh_info_t * info, int what, int max_stats,
@@ -84,6 +84,6 @@ extern int rh_get_stats(rh_info_t * info, int what, int max_stats,
 extern void rh_dump(rh_info_t * info);
 
 /* Set owner of taken block */
-extern int rh_set_owner(rh_info_t * info, void *start, const char *owner);
+extern int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner);
 
 #endif                         /* __ASM_PPC_RHEAP_H__ */
index 01717f266dc9f1ba07b6cf6723eedfcf17830229..d037f50580e23fbf7c6482903e3ddf4ffc68be17 100644 (file)
@@ -83,6 +83,7 @@ extern void __cpu_die(unsigned int cpu);
 
 #else
 /* for UP */
+#define hard_smp_processor_id()                0
 #define smp_setup_cpu_maps()
 
 #endif /* CONFIG_SMP */
index 02e56a6685a24baf9216336bbe2c3f1c6308829e..c48ae185c8744ecc3a6e57a3c93bb852a039c5f4 100644 (file)
@@ -235,6 +235,12 @@ struct spu_priv2_collapsed {
  */
 struct spu_state {
        struct spu_lscsa *lscsa;
+#ifdef CONFIG_SPU_FS_64K_LS
+       int             use_big_pages;
+       /* One struct page per 64k page */
+#define SPU_LSCSA_NUM_BIG_PAGES        (sizeof(struct spu_lscsa) / 0x10000)
+       struct page     *lscsa_pages[SPU_LSCSA_NUM_BIG_PAGES];
+#endif
        struct spu_problem_collapsed prob;
        struct spu_priv1_collapsed priv1;
        struct spu_priv2_collapsed priv2;
@@ -247,12 +253,14 @@ struct spu_state {
        spinlock_t register_lock;
 };
 
-extern void spu_init_csa(struct spu_state *csa);
+extern int spu_init_csa(struct spu_state *csa);
 extern void spu_fini_csa(struct spu_state *csa);
 extern int spu_save(struct spu_state *prev, struct spu *spu);
 extern int spu_restore(struct spu_state *new, struct spu *spu);
 extern int spu_switch(struct spu_state *prev, struct spu_state *new,
                      struct spu *spu);
+extern int spu_alloc_lscsa(struct spu_state *csa);
+extern void spu_free_lscsa(struct spu_state *csa);
 
 #endif /* !__SPU__ */
 #endif /* __KERNEL__ */
index 0b00068313f9274ff07506ed3ef4cb9b946c8976..3d44446fb74fe6ace1a08e9a973a75247d3b0f42 100644 (file)
@@ -307,3 +307,4 @@ COMPAT_SYS_SPU(set_robust_list)
 COMPAT_SYS_SPU(move_pages)
 SYSCALL_SPU(getcpu)
 COMPAT_SYS(epoll_pwait)
+COMPAT_SYS_SPU(utimensat)
index 2baedbe54e13cb61bdf57d221b6354bcd3f41668..21f004aef5084237ce1971bee3db49dfa9acfdc9 100644 (file)
 #define __NR_move_pages                301
 #define __NR_getcpu            302
 #define __NR_epoll_pwait       303
+#define __NR_utimensat         304
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          304
+#define __NR_syscalls          305
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 4f99df1bafd7ec6ad46df6147b533f983bcb27fe..397248705e0ed88060f7a76e1ef4adef617b34f1 100644 (file)
 #define CPM_DATAONLY_SIZE      ((uint)0x0700)
 #define CPM_DP_NOSPACE         ((uint)0x7fffffff)
 
-static inline long IS_DPERR(const uint offset)
-{
-       return (uint)offset > (uint)-1000L;
-}
-
 /* Export the base address of the communication processor registers
  * and dual port ram.
  */
 extern cpm8xx_t        *cpmp;          /* Pointer to comm processor */
-extern uint cpm_dpalloc(uint size, uint align);
-extern int cpm_dpfree(uint offset);
-extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
+extern unsigned long cpm_dpalloc(uint size, uint align);
+extern int cpm_dpfree(unsigned long offset);
+extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align);
 extern void cpm_dpdump(void);
-extern void *cpm_dpram_addr(uint offset);
+extern void *cpm_dpram_addr(unsigned long offset);
 extern uint cpm_dpram_phys(u8* addr);
 extern void cpm_setbrg(uint brg, uint rate);
 
index 220cc2debe089ee92c5daa70caa3590e5494b5ea..12a2860f9a9c35d2338d26bcb2cb7ca482501a81 100644 (file)
  */
 #define NUM_CPM_HOST_PAGES     2
 
-static inline long IS_DPERR(const uint offset)
-{
-       return (uint)offset > (uint)-1000L;
-}
-
 /* Export the base address of the communication processor registers
  * and dual port ram.
  */
 extern         cpm_cpm2_t      *cpmp;   /* Pointer to comm processor */
 
-extern uint cpm_dpalloc(uint size, uint align);
-extern int cpm_dpfree(uint offset);
-extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
+extern unsigned long cpm_dpalloc(uint size, uint align);
+extern int cpm_dpfree(unsigned long offset);
+extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align);
 extern void cpm_dpdump(void);
-extern void *cpm_dpram_addr(uint offset);
+extern void *cpm_dpram_addr(unsigned long offset);
 extern void cpm_setbrg(uint brg, uint rate);
 extern void cpm2_fastbrg(uint brg, uint rate, int div16);
 extern void cpm2_reset(void);
index 833a8aff2a80cc7b9f768d701c5adb302beb486e..1ad4eed07fbe0e5ab7c59855663d53c39b778722 100644 (file)
@@ -8,7 +8,7 @@
  *     Macintosh Technology in the Common Hardware Reference Platform
  *     Apple Computer, Inc.
  *
- *     © Copyright 1995 Apple Computer, Inc. All rights reserved.
+ *     Â© Copyright 1995 Apple Computer, Inc. All rights reserved.
  *
  *  It's available online from http://chrp.apple.com/MacTech.pdf.
  *  You can obtain paper copies of this book from computer bookstores or by
index 6795ecefd15b353c3c93414856a770d5e350416a..4c2e1710f15724ad7d170adb25723683245a30e1 100644 (file)
@@ -16,6 +16,7 @@
 /* structs from asm/cio.h */
 struct irb;
 struct ccw1;
+struct ccw_dev_id;
 
 /* simplified initializers for struct ccw_device:
  * CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one
@@ -175,6 +176,7 @@ extern int ccw_device_set_offline(struct ccw_device *cdev);
 
 extern struct ciw *ccw_device_get_ciw(struct ccw_device *, __u32 cmd);
 extern __u8 ccw_device_get_path_mask(struct ccw_device *);
+extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 
 #define get_ccwdev_lock(x) (x)->ccwlock
 
@@ -184,7 +186,6 @@ extern __u8 ccw_device_get_path_mask(struct ccw_device *);
 extern struct ccw_device *ccw_device_probe_console(void);
 
 // FIXME: these have to go
-extern int _ccw_device_get_device_number(struct ccw_device *);
 extern int _ccw_device_get_subchannel_number(struct ccw_device *);
 
 extern void *ccw_device_get_chp_desc(struct ccw_device *, int);
index bdcd448d43fb86518f5edb2d0eca000a1333129d..2c40fd3a137f304afd985a58c8155abadd7dcf70 100644 (file)
@@ -79,8 +79,8 @@ struct ipl_parameter_block {
  * IPL validity flags
  */
 extern u32 ipl_flags;
-
 extern u32 dump_prefix_page;
+extern unsigned int zfcpdump_prefix_array[];
 
 extern void do_reipl(void);
 extern void ipl_save_parameters(void);
index 085a7e229b2377e9a6c462d255f597e3a995e25c..34aaa4603347f46f4125a2d787ef256a854037d3 100644 (file)
@@ -10,7 +10,7 @@
 #define _ASMS390_PARAM_H
 
 #ifdef __KERNEL__
-# define HZ            100             /* Internal kernel timer frequency */
+# define HZ            CONFIG_HZ       /* Internal kernel timer frequency */
 # define USER_HZ       100             /* .. some user interfaces are in "ticks" */
 # define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
 #endif
index 6f7f65ac7d27da520ca756590ba1495076dd34a2..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,35 +1 @@
-/*
- *  include/asm-s390/poll.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/poll.h"
- */
-
-#ifndef __S390_POLL_H
-#define __S390_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN          0x0001
-#define POLLPRI         0x0002
-#define POLLOUT         0x0004
-#define POLLERR         0x0008
-#define POLLHUP         0x0010
-#define POLLNVAL        0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index 0a28e6d6ef405f576a63e5012e6bc683ddc2a975..76e424f718c63bb98ca8225b50e02bde5a873353 100644 (file)
@@ -110,6 +110,7 @@ static inline void smp_send_stop(void)
        __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 }
 
+#define hard_smp_processor_id()                0
 #define smp_cpu_not_running(cpu)       1
 #define smp_setup_cpu_possible_map()   do { } while (0)
 #endif
index 794c36daf06da9e3530ee167a87958cc1672048a..46f925c815aca9918823e4b23607b1e50e833cd4 100644 (file)
@@ -1,12 +1,12 @@
 #ifndef __ASM_SH_BUG_H
 #define __ASM_SH_BUG_H
 
+#define TRAPA_BUG_OPCODE       0xc33e  /* trapa #0x3e */
+
 #ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
 #define HAVE_ARCH_WARN_ON
 
-#define TRAPA_BUG_OPCODE       0xc33e  /* trapa #0x3e */
-
 /**
  * _EMIT_BUG_ENTRY
  * %1 - __FILE__
index 4bccd7c032f9c3d2320c8c7735b7fb5a0d02937b..86308aa3973180867a7b30a2f95e43f6137e54c2 100644 (file)
@@ -20,5 +20,6 @@
 #define CPU_HAS_PTEA           0x0020  /* PTEA register */
 #define CPU_HAS_LLSC           0x0040  /* movli.l/movco.l */
 #define CPU_HAS_L2_CACHE       0x0080  /* Secondary cache / URAM */
+#define CPU_HAS_OP32           0x0100  /* 32-bit instruction support */
 
 #endif /* __ASM_SH_CPU_FEATURES_H */
index 954801b46022ec5fe5bdae0389be708f7d7db5fc..3a66dc458023ecb371e4496664fa9caf67b7cf66 100644 (file)
@@ -26,7 +26,7 @@ enum {
        XMIT_SZ_128BIT,
 };
 
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
        [XMIT_SZ_8BIT]          = 0,
        [XMIT_SZ_16BIT]         = 1,
        [XMIT_SZ_32BIT]         = 2,
index 6c90d28331b27d49d094efc4f9348b58435aca3f..71b426a6e482b169d3b532369de5e5207425ab09 100644 (file)
@@ -28,7 +28,7 @@ enum {
 /*
  * The DMA count is defined as the number of bytes to transfer.
  */
-static unsigned int __attribute__ ((used)) ts_shift[] = {
+static unsigned int ts_shift[] __maybe_unused = {
        [XMIT_SZ_8BIT]          = 0,
        [XMIT_SZ_16BIT]         = 1,
        [XMIT_SZ_32BIT]         = 2,
index c135e9cebd9c0c9a74f0479c3e16c1cfd09c38e6..36e26a964765ebcb0bd994d31ffbe742d0d83ef3 100644 (file)
@@ -53,7 +53,7 @@ enum {
 /*
  * The DMA count is defined as the number of bytes to transfer.
  */
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
        [XMIT_SZ_64BIT]         = 3,
        [XMIT_SZ_8BIT]          = 0,
        [XMIT_SZ_16BIT]         = 1,
diff --git a/include/asm-sh/dmabrg.h b/include/asm-sh/dmabrg.h
new file mode 100644 (file)
index 0000000..c5edba2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SH7760 DMABRG (USB/Audio) support
+ */
+
+#ifndef _DMABRG_H_
+#define _DMABRG_H_
+
+/* IRQ sources */
+#define DMABRGIRQ_USBDMA       0
+#define DMABRGIRQ_USBDMAERR    1
+#define DMABRGIRQ_A0TXF                2
+#define DMABRGIRQ_A0TXH                3
+#define DMABRGIRQ_A0RXF                4
+#define DMABRGIRQ_A0RXH                5
+#define DMABRGIRQ_A1TXF                6
+#define DMABRGIRQ_A1TXH                7
+#define DMABRGIRQ_A1RXF                8
+#define DMABRGIRQ_A1RXH                9
+
+extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *);
+extern void dmabrg_free_irq(unsigned int);
+
+#endif
index a1089a65bc367ca03958c961878beeb2e412f194..5bdc9d9be3de9cacad4a972338157b890f8fb365 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-sh/edosk7705/io.h
+ * include/asm-sh/edosk7705.h
  *
  * Modified version of io_se.h for the EDOSK7705 specific functions.
  *
index 493c206297479adb4ffdb7f14457c0e8b8338c13..16578b7c9da12cf3ac7a2100ebaeea7e287fce73 100644 (file)
@@ -2,20 +2,6 @@
 #define __ASM_SH_KDEBUG_H
 
 #include <linux/notifier.h>
-#include <asm-generic/kdebug.h>
-
-struct pt_regs;
-
-struct die_args {
-       struct pt_regs *regs;
-       int trapnr;
-};
-
-int register_die_notifier(struct notifier_block *nb);
-int unregister_die_notifier(struct notifier_block *nb);
-int register_page_fault_notifier(struct notifier_block *nb);
-int unregister_page_fault_notifier(struct notifier_block *nb);
-extern struct atomic_notifier_head shdie_chain;
 
 /* Grossly misnamed. */
 enum die_val {
@@ -23,14 +9,7 @@ enum die_val {
        DIE_PAGE_FAULT,
 };
 
-static inline int notify_die(enum die_val val, struct pt_regs *regs,
-                            int trap, int sig)
-{
-       struct die_args args = {
-               .regs = regs,
-               .trapnr = trap,
-       };
+int register_page_fault_notifier(struct notifier_block *nb);
+int unregister_page_fault_notifier(struct notifier_block *nb);
 
-       return atomic_notifier_call_chain(&shdie_chain, val, &args);
-}
 #endif /* __ASM_SH_KDEBUG_H */
index 888e4529e6fe3c4bb2108f134b8b7674435836c3..18b613c57cf5118a8ea6fc452d0a0230ff4d50bf 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef __ASM_SH_PGALLOC_H
 #define __ASM_SH_PGALLOC_H
 
+#include <linux/quicklist.h>
+#include <asm/page.h>
+
+#define QUICK_PGD 0    /* We preserve special mappings over free */
+#define QUICK_PT 1     /* Other page table pages that are zero on free */
+
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
                                       pte_t *pte)
 {
@@ -13,48 +19,49 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
        set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
 }
 
+static inline void pgd_ctor(void *x)
+{
+       pgd_t *pgd = x;
+
+       memcpy(pgd + USER_PTRS_PER_PGD,
+              swapper_pg_dir + USER_PTRS_PER_PGD,
+              (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
 /*
  * Allocate and free page tables.
  */
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
-
-       if (pgd) {
-               memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
-               memcpy(pgd + USER_PTRS_PER_PGD,
-                      swapper_pg_dir + USER_PTRS_PER_PGD,
-                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-       }
-
-       return pgd;
+       return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
 static inline void pgd_free(pgd_t *pgd)
 {
-       free_page((unsigned long)pgd);
+       quicklist_free(QUICK_PGD, NULL, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                          unsigned long address)
 {
-       return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+       return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
 }
 
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
                                         unsigned long address)
 {
-       return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+       void *pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+       return pg ? virt_to_page(pg) : NULL;
 }
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-       free_page((unsigned long)pte);
+       quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-       __free_page(pte);
+       quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
 #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
@@ -66,6 +73,11 @@ static inline void pte_free(struct page *pte)
 
 #define pmd_free(x)                    do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
-#define check_pgt_cache()              do { } while (0)
+
+static inline void check_pgt_cache(void)
+{
+       quicklist_trim(QUICK_PGD, NULL, 25, 16);
+       quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 
 #endif /* __ASM_SH_PGALLOC_H */
index dbca9b32f4a6c4ff0f9f5f250e218e3eed4a0846..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __ASM_SH_POLL_H
-#define __ASM_SH_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif /* __ASM_SH_POLL_H */
+#include <asm-generic/poll.h>
index 6b5e4ddc073accbdb7133b7831b53303fdccc086..2d712e72c9e5ab9cae0afd1b32a2ab8201e5b792 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-sh/snapgear/io.h
+ * include/asm-sh/snapgear.h
  *
  * Modified version of io_se.h for the snapgear-specific functions.
  *
index e7e96ee0c8a5470e39f044e6067dcf8de8dea7a4..82f3e229e62135c2e944e1fbbe5e316744e2c4c1 100644 (file)
@@ -255,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler)
        return set_exception_table_vec(evt >> 5, handler);
 }
 
+/*
+ * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
+ */
+#ifdef CONFIG_CPU_SH2A
+extern unsigned int instruction_size(unsigned int insn);
+#else
+#define instruction_size(insn) (2)
+#endif
+
 /* XXX
  * disable hlt during certain critical i/o operations
  */
index 17b5e76a4c3131471599b52bb3aea12ce78aad43..701ba84c7049305dd1e763efe671bfbf15ed9439 100644 (file)
@@ -2,12 +2,14 @@
 #define __ASM_SH_TIMER_H
 
 #include <linux/sysdev.h>
+#include <linux/clocksource.h>
 #include <asm/cpu/timer.h>
 
 struct sys_timer_ops {
        int (*init)(void);
        int (*start)(void);
        int (*stop)(void);
+       cycle_t (*read)(void);
 #ifndef CONFIG_GENERIC_TIME
        unsigned long (*get_offset)(void);
 #endif
@@ -18,29 +20,8 @@ struct sys_timer {
 
        struct sys_device       dev;
        struct sys_timer_ops    *ops;
-
-#ifdef CONFIG_NO_IDLE_HZ
-       struct dyn_tick_timer   *dyn_tick;
-#endif
 };
 
-#ifdef CONFIG_NO_IDLE_HZ
-#define DYN_TICK_ENABLED       (1 << 1)
-
-struct dyn_tick_timer {
-       spinlock_t      lock;
-       unsigned int    state;                  /* Current state */
-       int             (*enable)(void);        /* Enables dynamic tick */
-       int             (*disable)(void);       /* Disables dynamic tick */
-       void            (*reprogram)(unsigned long); /* Reprograms the timer */
-       int             (*handler)(int, void *);
-};
-
-void timer_dyn_reprogram(void);
-#else
-#define timer_dyn_reprogram()  do { } while (0)
-#endif
-
 #define TICK_SIZE (tick_nsec / 1000)
 
 extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer;
@@ -58,5 +39,7 @@ struct sys_timer *get_sys_timer(void);
 
 /* arch/sh/kernel/time.c */
 void handle_timer_tick(void);
+extern unsigned long sh_hpt_frequency;
+extern struct clocksource clocksource_sh;
 
 #endif /* __ASM_SH_TIMER_H */
index 49be50a36b77dc3dc02dad61892100051f030377..af71e379a5eea94097e029e44e555ab5b3c4cd40 100644 (file)
@@ -85,7 +85,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     /* Back compatible 2Gig limited rlimit */
 #define __NR_getrusage          77
 #define __NR_gettimeofday       78
 #define __NR_settimeofday       79
 #define __NR_move_pages                317
 #define __NR_getcpu            318
 #define __NR_epoll_pwait       319
+#define __NR_utimensat         320
 
-#define NR_syscalls 320
+#define NR_syscalls 321
 
 #ifdef __KERNEL__
 
index 3a6cbad08d281a9bc2a94a3b7fdc0397eca31502..ca2950267c535035da0af068ab05280b6196fdc2 100644 (file)
@@ -1,37 +1,8 @@
 #ifndef __ASM_SH64_POLL_H
 #define __ASM_SH64_POLL_H
 
-/*
- * 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.
- *
- * include/asm-sh64/poll.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- */
+#include <asm-generic/poll.h>
 
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#undef POLLREMOVE
 
 #endif /* __ASM_SH64_POLL_H */
index 26f13fb35497f77926404a6503e7b091c1f5a425..091d3ad2e83017f4606d2a0371949fc929b19bda 100644 (file)
@@ -1,24 +1,12 @@
 #ifndef __SPARC_POLL_H
 #define __SPARC_POLL_H
 
-#define POLLIN           1
-#define POLLPRI                  2
-#define POLLOUT                  4
-#define POLLERR                  8
-#define POLLHUP                 16
-#define POLLNVAL        32
-#define POLLRDNORM      64
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     128
 #define POLLWRBAND     256
 #define POLLMSG                512
 #define POLLREMOVE     1024
 #define POLLRDHUP       2048
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
index b9da9a600e356339dd146fff14bf54d96e7df3ff..b3f492208fd20168d2615a6bf51ae8a9101f63b3 100644 (file)
@@ -165,6 +165,7 @@ void smp_setup_cpu_possible_map(void);
 
 #else /* SMP */
 
+#define hard_smp_processor_id()                0
 #define smp_setup_cpu_possible_map() do { } while (0)
 
 #endif /* !(SMP) */
index e43ed1d63a9df15eb9ece97221efa52f60181410..da9bdc5e5526bf287d1ec6c018f1971fa7fe59ea 100644 (file)
 #define __NR_move_pages                307
 #define __NR_getcpu            308
 #define __NR_epoll_pwait       309
+#define __NR_utimensat         310
 
-#define NR_SYSCALLS            310
+#define NR_SYSCALLS            311
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
index f8032e73f384303dbfd790d1d8a0b3d2736d5ef3..627e3396a5f0c136bf486eada3a6706b76f68486 100644 (file)
@@ -7,8 +7,19 @@
 
 struct pt_regs;
 
-extern int register_page_fault_notifier(struct notifier_block *);
-extern int unregister_page_fault_notifier(struct notifier_block *);
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation.  Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
 
 extern void bad_trap(struct pt_regs *, long);
 
@@ -20,7 +31,6 @@ enum die_val {
        DIE_DIE,
        DIE_TRAP,
        DIE_TRAP_TL1,
-       DIE_GPF,
        DIE_CALL,
        DIE_PAGE_FAULT,
 };
index becc38fa06c5a5c60422c4f4d62efcb1ab4494ce..a331b7b0dff2bd56ef5b6b35d28912838135bee0 100644 (file)
@@ -43,4 +43,5 @@ struct kprobe_ctlblk {
 
 extern int kprobe_exceptions_notify(struct notifier_block *self,
                                    unsigned long val, void *data);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 #endif /* _SPARC64_KPROBES_H */
index e01b80559c93f164c8ec056aa624bffae6104038..26ec046715c86c3bee6e5911336e5ac858349d31 100644 (file)
@@ -177,7 +177,7 @@ struct linux_nodeops {
 /* More fun PROM structures for device probing. */
 #define PROMREG_MAX     24
 #define PROMVADDR_MAX   16
-#define PROMINTR_MAX    15
+#define PROMINTR_MAX    32
 
 struct linux_prom_registers {
        unsigned which_io;      /* hi part of physical address                  */
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
deleted file mode 100644 (file)
index c008cec..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* pbm.h: UltraSparc PCI controller software state.
- *
- * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef __SPARC64_PBM_H
-#define __SPARC64_PBM_H
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/msi.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/iommu.h>
-
-/* The abstraction used here is that there are PCI controllers,
- * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
- * underneath.  Each PCI bus module uses an IOMMU (shared by both
- * PBMs of a controller, or per-PBM), and if a streaming buffer
- * is present, each PCI bus module has it's own. (ie. the IOMMU
- * might be shared between PBMs, the STC is never shared)
- * Furthermore, each PCI bus module controls it's own autonomous
- * PCI bus.
- */
-
-extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
-
-#define PCI_STC_FLUSHFLAG_INIT(STC) \
-       (*((STC)->strbuf_flushflag) = 0UL)
-#define PCI_STC_FLUSHFLAG_SET(STC) \
-       (*((STC)->strbuf_flushflag) != 0UL)
-
-/* There can be quite a few ranges and interrupt maps on a PCI
- * segment.  Thus...
- */
-#define PROM_PCIRNG_MAX                64
-#define PROM_PCIIMAP_MAX       64
-
-struct pci_controller_info;
-
-struct pci_pbm_info {
-       /* PCI controller we sit under. */
-       struct pci_controller_info      *parent;
-
-       /* Physical address base of controller registers. */
-       unsigned long                   controller_regs;
-
-       /* Physical address base of PBM registers. */
-       unsigned long                   pbm_regs;
-
-       /* Physical address of DMA sync register, if any.  */
-       unsigned long                   sync_reg;
-
-       /* Opaque 32-bit system bus Port ID. */
-       u32                             portid;
-
-       /* Opaque 32-bit handle used for hypervisor calls.  */
-       u32                             devhandle;
-
-       /* Chipset version information. */
-       int                             chip_type;
-#define PBM_CHIP_TYPE_SABRE            1
-#define PBM_CHIP_TYPE_PSYCHO           2
-#define PBM_CHIP_TYPE_SCHIZO           3
-#define PBM_CHIP_TYPE_SCHIZO_PLUS      4
-#define PBM_CHIP_TYPE_TOMATILLO                5
-       int                             chip_version;
-       int                             chip_revision;
-
-       /* Name used for top-level resources. */
-       char                            *name;
-
-       /* OBP specific information. */
-       struct device_node              *prom_node;
-       u64                             ino_bitmap;
-
-       /* PBM I/O and Memory space resources. */
-       struct resource                 io_space;
-       struct resource                 mem_space;
-
-       /* Base of PCI Config space, can be per-PBM or shared. */
-       unsigned long                   config_space;
-
-       /* State of 66MHz capabilities on this PBM. */
-       int                             is_66mhz_capable;
-       int                             all_devs_66mhz;
-
-#ifdef CONFIG_PCI_MSI
-       /* MSI info.  */
-       u32                             msiq_num;
-       u32                             msiq_ent_count;
-       u32                             msiq_first;
-       u32                             msiq_first_devino;
-       u32                             msi_num;
-       u32                             msi_first;
-       u32                             msi_data_mask;
-       u32                             msix_data_width;
-       u64                             msi32_start;
-       u64                             msi64_start;
-       u32                             msi32_len;
-       u32                             msi64_len;
-       void                            *msi_queues;
-       unsigned long                   *msi_bitmap;
-#endif /* !(CONFIG_PCI_MSI) */
-
-       /* This PBM's streaming buffer. */
-       struct strbuf                   stc;
-
-       /* IOMMU state, potentially shared by both PBM segments. */
-       struct iommu                    *iommu;
-
-       /* Now things for the actual PCI bus probes. */
-       unsigned int                    pci_first_busno;
-       unsigned int                    pci_last_busno;
-       struct pci_bus                  *pci_bus;
-};
-
-struct pci_controller_info {
-       /* List of all PCI controllers. */
-       struct pci_controller_info      *next;
-
-       /* Each controller gets a unique index, used mostly for
-        * error logging purposes.
-        */
-       int                             index;
-
-       /* The PCI bus modules controlled by us. */
-       struct pci_pbm_info             pbm_A;
-       struct pci_pbm_info             pbm_B;
-
-       /* Operations which are controller specific. */
-       void (*scan_bus)(struct pci_controller_info *);
-
-#ifdef CONFIG_PCI_MSI
-       int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
-                            struct msi_desc *entry);
-       void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
-#endif
-
-       /* Now things for the actual PCI bus probes. */
-       struct pci_ops                  *pci_ops;
-       unsigned int                    pci_first_busno;
-       unsigned int                    pci_last_busno;
-};
-
-#endif /* !(__SPARC64_PBM_H) */
index ab6b0d1bb4adb6c0d2b1599fc951e5a5b7399896..ebeeb3816c40397bfdd66e03126c1bf13dbdc8ff 100644 (file)
@@ -1,24 +1,12 @@
 #ifndef __SPARC64_POLL_H
 #define __SPARC64_POLL_H
 
-#define POLLIN           1
-#define POLLPRI                  2
-#define POLLOUT                  4
-#define POLLERR                  8
-#define POLLHUP                 16
-#define POLLNVAL        32
-#define POLLRDNORM      64
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     128
 #define POLLWRBAND     256
 #define POLLMSG                512
 #define POLLREMOVE     1024
 #define POLLRDHUP       2048
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif
index cca54804b72243e216ec4fd051175ec8c8fe735e..869d16fb907bb134dd040dcef05f91806c6b5ff4 100644 (file)
@@ -48,6 +48,7 @@ extern unsigned char boot_cpu_id;
 
 #else
 
+#define hard_smp_processor_id()                0
 #define smp_setup_cpu_possible_map() do { } while (0)
 #define boot_cpu_id    (0)
 
index e2dcb87e0c6287b117505b075d3f44b8b3b21ed5..fcd627594f4c781452082a4ee79661582b7312e0 100644 (file)
 #define __NR_move_pages                307
 #define __NR_getcpu            308
 #define __NR_epoll_pwait       309
+#define __NR_utimensat         310
 
-#define NR_SYSCALLS            310
+#define NR_SYSCALLS            311
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
diff --git a/include/asm-um/required-features.h b/include/asm-um/required-features.h
new file mode 100644 (file)
index 0000000..dfb967b
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __UM_REQUIRED_FEATURES_H
+#define __UM_REQUIRED_FEATURES_H
+
+/*
+ * Nothing to see, just need something for the i386 and x86_64 asm
+ * headers to include.
+ */
+
+#endif
index ca552261ed1fcee5c3493830d2903e9754bcc3a3..84f8cf29324e8950fd941b38a98fe76eea3a463f 100644 (file)
@@ -24,6 +24,10 @@ extern inline void smp_cpus_done(unsigned int maxcpus)
 
 extern struct task_struct *idle_threads[NR_CPUS];
 
+#else
+
+#define hard_smp_processor_id()                0
+
 #endif
 
 #endif
index 261e2f4528f6a62e1f5dd94c41ff06d5405beeed..18a13ba746053eb8da1dc912fda5957d0dc57577 100644 (file)
@@ -22,6 +22,7 @@ struct thread_info {
                                                   0-0xBFFFFFFF for user
                                                   0-0xFFFFFFFF for kernel */
        struct restart_block    restart_block;
+       struct thread_info      *real_thread;    /* Points to non-IRQ stack */
 };
 
 #define INIT_THREAD_INFO(tsk)                  \
@@ -35,6 +36,7 @@ struct thread_info {
        .restart_block =  {                     \
                .fn =  do_no_restart_syscall,   \
        },                                      \
+       .real_thread = NULL,                    \
 }
 
 #define init_thread_info       (init_thread_union.thread_info)
index c10176c2c28ff7b7b15a05e3e600399948a59966..803cad0b9b59388f16c1854795a10065cfd98349 100644 (file)
@@ -1,24 +1,9 @@
 #ifndef __V850_POLL_H__
 #define __V850_POLL_H__
 
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-#define POLLRDNORM     0x0040
 #define POLLWRNORM     POLLOUT
-#define POLLRDBAND     0x0080
 #define POLLWRBAND     0x0100
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* __V850_POLL_H__ */
index a09fe85c268e7e06943ec01f7c9d500457c9852a..a094276407647ecbfea524af86ef686133be4f91 100644 (file)
@@ -102,6 +102,12 @@ static inline void alternatives_smp_switch(int smp) {}
                      "663:\n\t" newinstr "\n664:\n"   /* replacement */ \
                      ".previous" : output : [feat] "i" (feature), ##input)
 
+/*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
 /*
  * Alternative inline assembly for SMP.
  *
index dee632fa457d2a8fe5e7eb48168521618b0c4fa8..e327c830da0c241e26308f09c01bb8ac1ad89ce5 100644 (file)
@@ -80,6 +80,15 @@ extern unsigned long phys_base;
 #define __PHYSICAL_START       CONFIG_PHYSICAL_START
 #define __KERNEL_ALIGN         0x200000
 
+/*
+ * Make sure kernel is aligned to 2MB address. Catching it at compile
+ * time is better. Change your config file and compile the kernel
+ * for a 2MB aligned address (CONFIG_PHYSICAL_START)
+ */
+#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0
+#error "CONFIG_PHYSICAL_START must be a multiple of 2MB"
+#endif
+
 #define __START_KERNEL         (__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map     _AC(0xffffffff80000000, UL)
 #define __PAGE_OFFSET           _AC(0xffff810000000000, UL)
index c0475a9d8bb860d0e330a866b6d6576b9a99d114..c98509d3149e637951f5edf96116a70ed9d8bc51 100644 (file)
@@ -1,27 +1 @@
-#ifndef __x86_64_POLL_H
-#define __x86_64_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
-#define POLLWRNORM     0x0100
-#define POLLWRBAND     0x0200
-#define POLLMSG                0x0400
-#define POLLREMOVE     0x1000
-#define POLLRDHUP       0x2000
-
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
index d5704421456b5016dd6b23e2aef538fffb209b45..3f303d2365ed68d9b207b43976bd1c3aa2282e51 100644 (file)
@@ -57,12 +57,6 @@ static inline int num_booting_cpus(void)
 
 #define raw_smp_processor_id() read_pda(cpunumber)
 
-static inline int hard_smp_processor_id(void)
-{
-       /* we don't want to mark this access volatile - bad code generation */
-       return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
-}
-
 extern int __cpu_disable(void);
 extern void __cpu_die(unsigned int cpu);
 extern void prefill_possible_map(void);
@@ -71,7 +65,13 @@ extern unsigned __cpuinitdata disabled_cpus;
 
 #define NO_PROC_ID             0xFF            /* No processor magic marker */
 
-#endif
+#endif /* CONFIG_SMP */
+
+static inline int hard_smp_processor_id(void)
+{
+       /* we don't want to mark this access volatile - bad code generation */
+       return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
+}
 
 /*
  * Some lowlevel functions might want to know about
index b7b8021e8c43c871d81044df9f84c92485143c58..ead9f9a56234243ab0413b73a048de253f167695 100644 (file)
@@ -39,7 +39,7 @@
                       [threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
                       [ti_flags] "i" (offsetof(struct thread_info, flags)),\
                       [tif_fork] "i" (TIF_FORK),                         \
-                      [thread_info] "i" (offsetof(struct task_struct, thread_info)), \
+                      [thread_info] "i" (offsetof(struct task_struct, stack)), \
                       [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent))   \
                     : "memory", "cc" __EXTRA_CLOBBER)
     
index 74a6c74397f72bee7619075dd1fba64d7d13e136..10bb5a8ed688889a68a99161021e9c0704d760d9 100644 (file)
@@ -162,7 +162,7 @@ static inline struct thread_info *stack_thread_info(void)
 #define TS_COMPAT              0x0002  /* 32bit syscall active */
 #define TS_POLLING             0x0004  /* true if in idle loop and not sleeping */
 
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
 
 #endif /* __KERNEL__ */
 
index 595703949df39d370dbbc1a17c00363b6548c8c0..ae1ed05f28143d71ea31b0dbebd4f31369fce741 100644 (file)
@@ -621,6 +621,15 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice)
 __SYSCALL(__NR_move_pages, sys_move_pages)
 #define __NR_utimensat         280
 __SYSCALL(__NR_utimensat, sys_utimensat)
+#define __IGNORE_getcpu                /* implemented as a vsyscall */
+#define __NR_epoll_pwait       281
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+#define __NR_signalfd          282
+__SYSCALL(__NR_signalfd, sys_signalfd)
+#define __NR_timerfd           282
+__SYSCALL(__NR_timerfd, sys_timerfd)
+#define __NR_eventfd           283
+__SYSCALL(__NR_eventfd, sys_eventfd)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 6acb572759a696052553e1c7988da0ffe74df948..b7952c06a2b75286cb263828e51ab3ba561e3722 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * include/asm-xtensa/platform-iss/hardware.h
+ * include/asm-xtensa/platform-iss/simcall.h
  *
  * 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
index 6fd94773e866051bef79e0cff38fe5d6e0b04e6b..9d2d5993f0685c339d307a08f40ae09b50c25cdb 100644 (file)
 #ifndef _XTENSA_POLL_H
 #define _XTENSA_POLL_H
 
-
-#define POLLIN         0x0001
-#define POLLPRI                0x0002
-#define POLLOUT                0x0004
-
-#define POLLERR                0x0008
-#define POLLHUP                0x0010
-#define POLLNVAL       0x0020
-
-#define POLLRDNORM     0x0040
-#define POLLRDBAND     0x0080
 #define POLLWRNORM     POLLOUT
 #define POLLWRBAND     0x0100
-
-#define POLLMSG                0x0400
 #define POLLREMOVE     0x0800
-#define POLLRDHUP       0x2000
 
-struct pollfd {
-       int fd;
-       short events;
-       short revents;
-};
+#include <asm-generic/poll.h>
 
 #endif /* _XTENSA_POLL_H */
index 94cc04a143f28c21fe27775ba1ae4406f9c2e851..bcd01f269f60b61ce36fa7cb4c8c6169abf5018a 100644 (file)
@@ -140,7 +140,6 @@ header-y += snmp.h
 header-y += sockios.h
 header-y += som.h
 header-y += sound.h
-header-y += synclink.h
 header-y += taskstats.h
 header-y += telephony.h
 header-y += termios.h
@@ -191,6 +190,7 @@ unifdef-y += errno.h
 unifdef-y += errqueue.h
 unifdef-y += ethtool.h
 unifdef-y += eventpoll.h
+unifdef-y += signalfd.h
 unifdef-y += ext2_fs.h
 unifdef-y += ext3_fs.h
 unifdef-y += fb.h
@@ -320,6 +320,7 @@ unifdef-y += sonypi.h
 unifdef-y += soundcard.h
 unifdef-y += stat.h
 unifdef-y += stddef.h
+unifdef-y += synclink.h
 unifdef-y += sysctl.h
 unifdef-y += tcp.h
 unifdef-y += time.h
index 8bcfaa4c66ae78705ed128297d0069cd9f460752..fccd8b548d93f9457dc277ee997a9e6ca34f4b58 100644 (file)
@@ -182,7 +182,8 @@ extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
 extern int ec_transaction(u8 command,
                           const u8 *wdata, unsigned wdata_len,
-                          u8 *rdata, unsigned rdata_len);
+                          u8 *rdata, unsigned rdata_len,
+                         int force_poll);
 
 #endif /*CONFIG_ACPI_EC*/
 
index a30ef13c9e622c91bfd7706955758e5932fc639e..b903fc02bdb7dbc5f95a041dbba4dab24bb67e7c 100644 (file)
@@ -119,6 +119,12 @@ struct kiocb {
 
        struct list_head        ki_list;        /* the aio core uses this
                                                 * for cancellation */
+
+       /*
+        * If the aio_resfd field of the userspace iocb is not zero,
+        * this is the underlying file* to deliver event to.
+        */
+       struct file             *ki_eventfd;
 };
 
 #define is_sync_kiocb(iocb)    ((iocb)->ki_key == KIOCB_SYNC_KEY)
@@ -226,7 +232,8 @@ int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                __put_ioctx(kioctx);                                    \
 } while (0)
 
-#define in_aio() !is_sync_wait(current->io_wait)
+#define in_aio() (unlikely(!is_sync_wait(current->io_wait)))
+
 /* may be used for debugging */
 #define warn_if_async()                                                        \
 do {                                                                   \
index e3ca0a485cc646d171c7d1e5de1736b962908cdd..9e017293131542df17e57917e11d9809e6f4e49a 100644 (file)
@@ -45,6 +45,14 @@ enum {
        IOCB_CMD_PWRITEV = 8,
 };
 
+/*
+ * Valid flags for the "aio_flags" member of the "struct iocb".
+ *
+ * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb"
+ *                   is valid.
+ */
+#define IOCB_FLAG_RESFD                (1 << 0)
+
 /* read() from /dev/aio returns these structures. */
 struct io_event {
        __u64           data;           /* the data field from the iocb */
@@ -84,7 +92,15 @@ struct iocb {
 
        /* extra parameters */
        __u64   aio_reserved2;  /* TODO: use this for a (struct sigevent *) */
-       __u64   aio_reserved3;
+
+       /* flags for the "struct iocb" */
+       __u32   aio_flags;
+
+       /*
+        * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
+        * eventfd to signal AIO readiness to
+        */
+       __u32   aio_resfd;
 }; /* 64 bytes */
 
 #undef IFBIG
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
new file mode 100644 (file)
index 0000000..b2e1ba3
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ *  include/linux/anon_inodes.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_ANON_INODES_H
+#define _LINUX_ANON_INODES_H
+
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+                    const char *name, const struct file_operations *fops,
+                    void *priv);
+
+#endif /* _LINUX_ANON_INODES_H */
+
index a686eabe22d645e8304af1ab33ab6114783523d9..db5b00a792f519d7d4dde9a2e4824a2c7f948db9 100644 (file)
@@ -854,7 +854,7 @@ static inline void put_dev_sector(Sector p)
 
 struct work_struct;
 int kblockd_schedule_work(struct work_struct *work);
-void kblockd_flush(void);
+void kblockd_flush_work(struct work_struct *work);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
        MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
index 2665ca04cf8f5e919d2f72bfdde6d4390986f062..bf297b03a4e4650cd4c02a9dbe4e55307674411d 100644 (file)
@@ -49,6 +49,7 @@ struct clocksource;
  * @shift:             cycle to nanosecond divisor (power of two)
  * @flags:             flags describing special properties
  * @vread:             vsyscall based read
+ * @resume:            resume function for the clocksource, if necessary
  * @cycle_interval:    Used internally by timekeeping core, please ignore.
  * @xtime_interval:    Used internally by timekeeping core, please ignore.
  */
@@ -65,6 +66,7 @@ struct clocksource {
        u32 shift;
        unsigned long flags;
        cycle_t (*vread)(void);
+       void (*resume)(void);
 
        /* timekeeping specific data, ignore */
        cycle_t cycle_interval;
@@ -209,6 +211,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
 extern int clocksource_register(struct clocksource*);
 extern struct clocksource* clocksource_get_next(void);
 extern void clocksource_change_rating(struct clocksource *cs, int rating);
+extern void clocksource_resume(void);
 
 #ifdef CONFIG_GENERIC_TIME_VSYSCALL
 extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
index ccd863dd77fae4a654981181ba189f5c4604c155..636502c02734beedee6e3a65435f129219b85ddd 100644 (file)
@@ -225,6 +225,11 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs,
        return lhs->tv_nsec - rhs->tv_nsec;
 }
 
+extern int get_compat_itimerspec(struct itimerspec *dst,
+                                const struct compat_itimerspec __user *src);
+extern int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+                                const struct itimerspec *src);
+
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
 extern int compat_printk(const char *fmt, ...);
@@ -253,5 +258,8 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                        const compat_sigset_t __user *sigmask,
                        compat_size_t sigsetsize);
 
+asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename,
+                               struct compat_timespec __user *t, int flags);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
index a9f794716a8105f62f7a85e16dd7b240c94d535a..03ec2311fb29c9ce4d252e2e9b41b8eea19e8e18 100644 (file)
@@ -40,3 +40,4 @@
 #define  noinline                      __attribute__((noinline))
 #define __attribute_pure__             __attribute__((pure))
 #define __attribute_const__            __attribute__((__const__))
+#define __maybe_unused                 __attribute__((unused))
index ecd621fd27d2415376ea1d123b353edfd2ee7843..a9e2863c2dbf058a97b62ccf18af83bf8a1145c2 100644 (file)
@@ -4,9 +4,11 @@
 #include <linux/compiler-gcc.h>
 
 #if __GNUC_MINOR__ >= 3
-# define __attribute_used__    __attribute__((__used__))
+# define __used                        __attribute__((__used__))
+# define __attribute_used__    __used                          /* deprecated */
 #else
-# define __attribute_used__    __attribute__((__unused__))
+# define __used                        __attribute__((__unused__))
+# define __attribute_used__    __used                          /* deprecated */
 #endif
 
 #if __GNUC_MINOR__ >= 4
index fd0cc7c4a636e77dbf5a502b31b85f760cb088e9..a03e9398a6c2ba0d986405f8bec84f7f0141b786 100644 (file)
@@ -12,7 +12,8 @@
 # define __inline              __inline        __attribute__((always_inline))
 #endif
 
-#define __attribute_used__     __attribute__((__used__))
+#define __used                 __attribute__((__used__))
+#define __attribute_used__     __used                  /* deprecated */
 #define __must_check           __attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
 #define __always_inline                inline __attribute__((always_inline))
index 3b6949b417451d16145d9117c3ad72fa8cb654b6..498c35920762e2e4a10ff61b1e01f9d27298e7dc 100644 (file)
@@ -108,15 +108,30 @@ extern void __chk_io_ptr(const void __iomem *);
  * Allow us to avoid 'defined but not used' warnings on functions and data,
  * as well as force them to be emitted to the assembly file.
  *
- * As of gcc 3.3, static functions that are not marked with attribute((used))
- * may be elided from the assembly file.  As of gcc 3.3, static data not so
+ * As of gcc 3.4, static functions that are not marked with attribute((used))
+ * may be elided from the assembly file.  As of gcc 3.4, static data not so
  * marked will not be elided, but this may change in a future gcc version.
  *
+ * NOTE: Because distributions shipped with a backported unit-at-a-time
+ * compiler in gcc 3.3, we must define __used to be __attribute__((used))
+ * for gcc >=3.3 instead of 3.4.
+ *
  * In prior versions of gcc, such functions and data would be emitted, but
  * would be warned about except with attribute((unused)).
+ *
+ * Mark functions that are referenced only in inline assembly as __used so
+ * the code is emitted even though it appears to be unreferenced.
  */
 #ifndef __attribute_used__
-# define __attribute_used__    /* unimplemented */
+# define __attribute_used__    /* deprecated */
+#endif
+
+#ifndef __used
+# define __used                        /* unimplemented */
+#endif
+
+#ifndef __maybe_unused
+# define __maybe_unused                /* unimplemented */
 #endif
 
 /*
diff --git a/include/linux/crc-itu-t.h b/include/linux/crc-itu-t.h
new file mode 100644 (file)
index 0000000..84920f3
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *     crc-itu-t.h - CRC ITU-T V.41 routine
+ *
+ * Implements the standard CRC ITU-T V.41:
+ *   Width 16
+ *   Poly  0x0x1021 (x^16 + x^12 + x^15 + 1)
+ *   Init  0
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef CRC_ITU_T_H
+#define CRC_ITU_T_H
+
+#include <linux/types.h>
+
+extern u16 const crc_itu_t_table[256];
+
+extern u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len);
+
+static inline u16 crc_itu_t_byte(u16 crc, const u8 data)
+{
+       return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
+}
+
+#endif /* CRC_ITU_T_H */
+
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
new file mode 100644 (file)
index 0000000..0d6ecc6
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  include/linux/eventfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_EVENTFD_H
+#define _LINUX_EVENTFD_H
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_EVENTFD
+
+struct file *eventfd_fget(int fd);
+int eventfd_signal(struct file *file, int n);
+
+#else /* CONFIG_EVENTFD */
+
+#define eventfd_fget(fd) ERR_PTR(-ENOSYS)
+#define eventfd_signal(f, n) 0
+
+#endif /* CONFIG_EVENTFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EVENTFD_H */
+
index 4395e5206746b33be79bd57bef264da8a74bcd0a..7894dd0f3b77544a8006ff1d4471554f460be093 100644 (file)
@@ -54,7 +54,7 @@ struct ext3_block_alloc_info {
        /*
         * Was i_next_alloc_goal in ext3_inode_info
         * is the *physical* companion to i_next_alloc_block.
-        * it the the physical block number of the block which was most-recentl
+        * it the physical block number of the block which was most-recentl
         * allocated to this file.  This give us the goal (target) for the next
         * allocation when we detect linearly ascending requests.
         */
index bb42379cb7fdf91dde212e257df8d63ed06426f2..d5b177e5b3958338d13bfc46a9d8fcc1e338a9ee 100644 (file)
@@ -52,7 +52,7 @@ struct ext4_block_alloc_info {
        /*
         * Was i_next_alloc_goal in ext4_inode_info
         * is the *physical* companion to i_next_alloc_block.
-        * it the the physical block number of the block which was most-recentl
+        * it the physical block number of the block which was most-recentl
         * allocated to this file.  This give us the goal (target) for the next
         * allocation when we detect linearly ascending requests.
         */
index dff7a728948cab936d77f37bcd0583199e75c35c..c654d0e9ce3313d6f345eeac6ebd72279240d238 100644 (file)
@@ -868,7 +868,7 @@ struct fb_info {
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
new file mode 100644 (file)
index 0000000..d4455eb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Char device interface.
+ *
+ * Copyright (C) 2005-2006  Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_FIREWIRE_CDEV_H
+#define _LINUX_FIREWIRE_CDEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/firewire-constants.h>
+
+#define FW_CDEV_EVENT_BUS_RESET                0x00
+#define FW_CDEV_EVENT_RESPONSE         0x01
+#define FW_CDEV_EVENT_REQUEST          0x02
+#define FW_CDEV_EVENT_ISO_INTERRUPT    0x03
+
+/* The 'closure' fields are for user space to use.  Data passed in the
+ * 'closure' field for a request will be returned in the corresponding
+ * event.  It's a 64-bit type so that it's a fixed size type big
+ * enough to hold a pointer on all platforms. */
+
+struct fw_cdev_event_common {
+       __u64 closure;
+       __u32 type;
+};
+
+struct fw_cdev_event_bus_reset {
+       __u64 closure;
+       __u32 type;
+       __u32 node_id;
+       __u32 local_node_id;
+       __u32 bm_node_id;
+       __u32 irm_node_id;
+       __u32 root_node_id;
+       __u32 generation;
+};
+
+struct fw_cdev_event_response {
+       __u64 closure;
+       __u32 type;
+       __u32 rcode;
+       __u32 length;
+       __u32 data[0];
+};
+
+struct fw_cdev_event_request {
+       __u64 closure;
+       __u32 type;
+       __u32 tcode;
+       __u64 offset;
+       __u32 handle;
+       __u32 length;
+       __u32 data[0];
+};
+
+struct fw_cdev_event_iso_interrupt {
+       __u64 closure;
+       __u32 type;
+       __u32 cycle;
+       __u32 header_length;    /* Length in bytes of following headers. */
+       __u32 header[0];
+};
+
+union fw_cdev_event {
+       struct fw_cdev_event_common common;
+       struct fw_cdev_event_bus_reset bus_reset;
+       struct fw_cdev_event_response response;
+       struct fw_cdev_event_request request;
+       struct fw_cdev_event_iso_interrupt iso_interrupt;
+};
+
+#define FW_CDEV_IOC_GET_INFO           _IOWR('#', 0x00, struct fw_cdev_get_info)
+#define FW_CDEV_IOC_SEND_REQUEST       _IOW('#', 0x01, struct fw_cdev_send_request)
+#define FW_CDEV_IOC_ALLOCATE           _IOWR('#', 0x02, struct fw_cdev_allocate)
+#define FW_CDEV_IOC_DEALLOCATE         _IOW('#', 0x03, struct fw_cdev_deallocate)
+#define FW_CDEV_IOC_SEND_RESPONSE      _IOW('#', 0x04, struct fw_cdev_send_response)
+#define FW_CDEV_IOC_INITIATE_BUS_RESET _IOW('#', 0x05, struct fw_cdev_initiate_bus_reset)
+#define FW_CDEV_IOC_ADD_DESCRIPTOR     _IOWR('#', 0x06, struct fw_cdev_add_descriptor)
+#define FW_CDEV_IOC_REMOVE_DESCRIPTOR  _IOW('#', 0x07, struct fw_cdev_remove_descriptor)
+
+#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IOWR('#', 0x08, struct fw_cdev_create_iso_context)
+#define FW_CDEV_IOC_QUEUE_ISO          _IOWR('#', 0x09, struct fw_cdev_queue_iso)
+#define FW_CDEV_IOC_START_ISO          _IOW('#', 0x0a, struct fw_cdev_start_iso)
+#define FW_CDEV_IOC_STOP_ISO           _IOW('#', 0x0b, struct fw_cdev_stop_iso)
+
+/* FW_CDEV_VERSION History
+ *
+ * 1   Feb 18, 2007:  Initial version.
+ */
+#define FW_CDEV_VERSION                1
+
+struct fw_cdev_get_info {
+       /* The version field is just a running serial number.  We
+        * never break backwards compatibility.  Userspace passes in
+        * the version it expects and the kernel passes back the
+        * highest version it can provide.  Even if the structs in
+        * this interface are extended in a later version, the kernel
+        * will not copy back more data than what was present in the
+        * interface version userspace expects. */
+       __u32 version;
+
+       /* If non-zero, at most rom_length bytes of config rom will be
+        * copied into that user space address.  In either case,
+        * rom_length is updated with the actual length of the config
+        * rom. */
+       __u32 rom_length;
+       __u64 rom;
+
+       /* If non-zero, a fw_cdev_event_bus_reset struct will be
+        * copied here with the current state of the bus.  This does
+        * not cause a bus reset to happen.  The value of closure in
+        * this and sub-sequent bus reset events is set to
+        * bus_reset_closure. */
+       __u64 bus_reset;
+       __u64 bus_reset_closure;
+
+       /* The index of the card this devices belongs to. */
+       __u32 card;
+};
+
+struct fw_cdev_send_request {
+       __u32 tcode;
+       __u32 length;
+       __u64 offset;
+       __u64 closure;
+       __u64 data;
+       __u32 generation;
+};
+
+struct fw_cdev_send_response {
+       __u32 rcode;
+       __u32 length;
+       __u64 data;
+       __u32 handle;
+};
+
+struct fw_cdev_allocate {
+       __u64 offset;
+       __u64 closure;
+       __u32 length;
+       __u32 handle;
+};
+
+struct fw_cdev_deallocate {
+       __u32 handle;
+};
+
+#define FW_CDEV_LONG_RESET     0
+#define FW_CDEV_SHORT_RESET    1
+
+struct fw_cdev_initiate_bus_reset {
+       __u32 type;
+};
+
+struct fw_cdev_add_descriptor {
+       __u32 immediate;
+       __u32 key;
+       __u64 data;
+       __u32 length;
+       __u32 handle;
+};
+
+struct fw_cdev_remove_descriptor {
+       __u32 handle;
+};
+
+#define FW_CDEV_ISO_CONTEXT_TRANSMIT   0
+#define FW_CDEV_ISO_CONTEXT_RECEIVE    1
+
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0          1
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1          2
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2          4
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3          8
+#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS     15
+
+struct fw_cdev_create_iso_context {
+       __u32 type;
+       __u32 header_size;
+       __u32 channel;
+       __u32 speed;
+       __u64 closure;
+       __u32 handle;
+};
+
+struct fw_cdev_iso_packet {
+       __u16 payload_length;   /* Length of indirect payload. */
+       __u32 interrupt : 1;    /* Generate interrupt on this packet */
+       __u32 skip : 1;         /* Set to not send packet at all. */
+       __u32 tag : 2;
+       __u32 sy : 4;
+       __u32 header_length : 8;        /* Length of immediate header. */
+       __u32 header[0];
+};
+
+struct fw_cdev_queue_iso {
+       __u64 packets;
+       __u64 data;
+       __u32 size;
+       __u32 handle;
+};
+
+struct fw_cdev_start_iso {
+       __s32 cycle;
+       __u32 sync;
+       __u32 tags;
+       __u32 handle;
+};
+
+struct fw_cdev_stop_iso {
+       __u32 handle;
+};
+
+#endif /* _LINUX_FIREWIRE_CDEV_H */
diff --git a/include/linux/firewire-constants.h b/include/linux/firewire-constants.h
new file mode 100644 (file)
index 0000000..b316770
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _LINUX_FIREWIRE_CONSTANTS_H
+#define _LINUX_FIREWIRE_CONSTANTS_H
+
+#define TCODE_WRITE_QUADLET_REQUEST    0x0
+#define TCODE_WRITE_BLOCK_REQUEST      0x1
+#define TCODE_WRITE_RESPONSE           0x2
+#define TCODE_READ_QUADLET_REQUEST     0x4
+#define TCODE_READ_BLOCK_REQUEST       0x5
+#define TCODE_READ_QUADLET_RESPONSE    0x6
+#define TCODE_READ_BLOCK_RESPONSE      0x7
+#define TCODE_CYCLE_START              0x8
+#define TCODE_LOCK_REQUEST             0x9
+#define TCODE_STREAM_DATA              0xa
+#define TCODE_LOCK_RESPONSE            0xb
+
+#define EXTCODE_MASK_SWAP              0x1
+#define EXTCODE_COMPARE_SWAP           0x2
+#define EXTCODE_FETCH_ADD              0x3
+#define EXTCODE_LITTLE_ADD             0x4
+#define EXTCODE_BOUNDED_ADD            0x5
+#define EXTCODE_WRAP_ADD               0x6
+#define EXTCODE_VENDOR_DEPENDENT       0x7
+
+/* Juju specific tcodes */
+#define TCODE_LOCK_MASK_SWAP           (0x10 | EXTCODE_MASK_SWAP)
+#define TCODE_LOCK_COMPARE_SWAP                (0x10 | EXTCODE_COMPARE_SWAP)
+#define TCODE_LOCK_FETCH_ADD           (0x10 | EXTCODE_FETCH_ADD)
+#define TCODE_LOCK_LITTLE_ADD          (0x10 | EXTCODE_LITTLE_ADD)
+#define TCODE_LOCK_BOUNDED_ADD         (0x10 | EXTCODE_BOUNDED_ADD)
+#define TCODE_LOCK_WRAP_ADD            (0x10 | EXTCODE_WRAP_ADD)
+#define TCODE_LOCK_VENDOR_DEPENDENT    (0x10 | EXTCODE_VENDOR_DEPENDENT)
+
+#define RCODE_COMPLETE                 0x0
+#define RCODE_CONFLICT_ERROR           0x4
+#define RCODE_DATA_ERROR               0x5
+#define RCODE_TYPE_ERROR               0x6
+#define RCODE_ADDRESS_ERROR            0x7
+
+/* Juju specific rcodes */
+#define RCODE_SEND_ERROR               0x10
+#define RCODE_CANCELLED                        0x11
+#define RCODE_BUSY                     0x12
+#define RCODE_GENERATION               0x13
+#define RCODE_NO_ACK                   0x14
+
+#define SCODE_100                      0x0
+#define SCODE_200                      0x1
+#define SCODE_400                      0x2
+#define SCODE_800                      0x3
+#define SCODE_1600                     0x4
+#define SCODE_3200                     0x5
+#define SCODE_BETA                     0x3
+
+#define ACK_COMPLETE                   0x1
+#define ACK_PENDING                    0x2
+#define ACK_BUSY_X                     0x4
+#define ACK_BUSY_A                     0x5
+#define ACK_BUSY_B                     0x6
+#define ACK_DATA_ERROR                 0xd
+#define ACK_TYPE_ERROR                 0xe
+
+#define RETRY_1                                0x00
+#define RETRY_X                                0x01
+#define RETRY_A                                0x02
+#define RETRY_B                                0x03
+
+#endif /* _LINUX_FIREWIRE_CONSTANTS_H */
index 820125c628c1364478cfcc513275214aa9da628a..899fc7f20edd1b761023a58cbb883b12ba3e36ef 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <linux/sched.h>
 
+union ktime;
+
 /* Second argument to futex syscall */
 
 
 #define FUTEX_LOCK_PI          6
 #define FUTEX_UNLOCK_PI                7
 #define FUTEX_TRYLOCK_PI       8
+#define FUTEX_CMP_REQUEUE_PI   9
+
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CMD_MASK         ~FUTEX_PRIVATE_FLAG
+
+#define FUTEX_WAIT_PRIVATE     (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_PRIVATE     (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_REQUEUE_PRIVATE  (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_OP_PRIVATE  (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
+#define FUTEX_LOCK_PI_PRIVATE  (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_UNLOCK_PI_PRIVATE        (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
 
 /*
  * Support for robust futexes: the kernel cleans up held futexes at
@@ -82,10 +97,15 @@ struct robust_list_head {
  */
 #define FUTEX_OWNER_DIED       0x40000000
 
+/*
+ * Some processes have been requeued on this PI-futex
+ */
+#define FUTEX_WAITER_REQUEUED  0x20000000
+
 /*
  * The rest of the robust-futex field is for the TID:
  */
-#define FUTEX_TID_MASK         0x3fffffff
+#define FUTEX_TID_MASK         0x0fffffff
 
 /*
  * This limit protects against a deliberately circular list.
@@ -94,7 +114,7 @@ struct robust_list_head {
 #define ROBUST_LIST_LIMIT      2048
 
 #ifdef __KERNEL__
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
              u32 __user *uaddr2, u32 val2, u32 val3);
 
 extern int
@@ -106,9 +126,20 @@ handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
  * Don't rearrange members without looking at hash_futex().
  *
  * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
- * We set bit 0 to indicate if it's an inode-based key.
- */
+ * We use the two low order bits of offset to tell what is the kind of key :
+ *  00 : Private process futex (PTHREAD_PROCESS_PRIVATE)
+ *       (no reference on an inode or mm)
+ *  01 : Shared futex (PTHREAD_PROCESS_SHARED)
+ *     mapped on a file (reference on the underlying inode)
+ *  10 : Shared futex (PTHREAD_PROCESS_SHARED)
+ *       (but private mapping on an mm, and reference taken on it)
+*/
+
+#define FUT_OFF_INODE    1 /* We set bit 0 if key has a reference on inode */
+#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
+
 union futex_key {
+       u32 __user *uaddr;
        struct {
                unsigned long pgoff;
                struct inode *inode;
@@ -125,7 +156,8 @@ union futex_key {
                int offset;
        } both;
 };
-int get_futex_key(u32 __user *uaddr, union futex_key *key);
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *shared,
+                 union futex_key *key);
 void get_futex_key_refs(union futex_key *key);
 void drop_futex_key_refs(union futex_key *key);
 
index 80764f40be7531ff7c287f23ccba18b34e5515a8..886f5faa08cb6f1ff8c84ff2da04e9144d01c9df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * fs/generic_acl.c
+ * include/linux/generic_acl.h
  *
  * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
  *
index 2c65da7cabb2a25acc1c42c067a3770872f29141..f589559cf0709586d1f126f92ebbbbca9cefa53b 100644 (file)
@@ -413,6 +413,7 @@ char *disk_name (struct gendisk *hd, int part, char *buf);
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
 extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
 extern void delete_partition(struct gendisk *, int);
+extern void printk_all_partitions(void);
 
 extern struct gendisk *alloc_disk_node(int minors, int node_id);
 extern struct gendisk *alloc_disk(int minors);
index 97a36c3d96e2cb1d9981f1aa4a9b350138d268a0..0d2ef0b082a626853b7651914094cabf88672434 100644 (file)
@@ -176,10 +176,6 @@ extern void FASTCALL(free_cold_page(struct page *page));
 #define free_page(addr) free_pages((addr),0)
 
 void page_alloc_init(void);
-#ifdef CONFIG_NUMA
-void drain_node_pages(int node);
-#else
-static inline void drain_node_pages(int node) { };
-#endif
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
 
 #endif /* __LINUX_GFP_H */
index a515eb0afdfb660a56eedd0c8928b8281fe0b5b7..98e2cce996a4c1867543ffa03d83c66c3c8846de 100644 (file)
@@ -94,17 +94,26 @@ static inline void clear_highpage(struct page *page)
 
 /*
  * Same but also flushes aliased cache contents to RAM.
+ *
+ * This must be a macro because KM_USER0 and friends aren't defined if
+ * !CONFIG_HIGHMEM
  */
-static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
+#define zero_user_page(page, offset, size, km_type)            \
+       do {                                                    \
+               void *kaddr;                                    \
+                                                               \
+               BUG_ON((offset) + (size) > PAGE_SIZE);          \
+                                                               \
+               kaddr = kmap_atomic(page, km_type);             \
+               memset((char *)kaddr + (offset), 0, (size));    \
+               flush_dcache_page(page);                        \
+               kunmap_atomic(kaddr, (km_type));                \
+       } while (0)
+
+static inline void __deprecated memclear_highpage_flush(struct page *page,
+                       unsigned int offset, unsigned int size)
 {
-       void *kaddr;
-
-       BUG_ON(offset + size > PAGE_SIZE);
-
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset((char *)kaddr + offset, 0, size);
-       flush_dcache_page(page);
-       kunmap_atomic(kaddr, KM_USER0);
+       zero_user_page(page, offset, size, KM_USER0);
 }
 
 #ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
index 9ee0f800592f030bd56592ec2de113e5c8deb214..111334f5b92238664037059bed8f1fe431875337 100644 (file)
@@ -18,7 +18,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
 #ifndef _LINUX_I2C_ALGO_BIT_H
index 994eb86f882c1f4fa3ce682b523ce7e81f64ae9d..77afbb60fd1185fb76699eacd9a8ba6fd5f7f919 100644 (file)
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
 /* ------------------------------------------------------------------------- */
 
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
 #ifndef _LINUX_I2C_ALGO_PCF_H
index 418dfb5adadd80b93affaf08b6a0d809cf5bb3dd..df4e6a510310e43b27dac289ccbbc37fe346e133 100644 (file)
@@ -223,8 +223,9 @@ typedef struct hw_regs_s {
 /*
  * Register new hardware with ide
  */
-int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
-int ide_register_hw_with_fixup(hw_regs_t *, struct hwif_s **, void (*)(struct hwif_s *));
+int ide_register_hw(hw_regs_t *, int, struct hwif_s **);
+int ide_register_hw_with_fixup(hw_regs_t *, int, struct hwif_s **,
+                              void (*)(struct hwif_s *));
 
 /*
  * Set up hw_regs_t structure before calling ide_register_hw (optional)
@@ -559,9 +560,10 @@ typedef struct ide_drive_s {
        struct ide_drive_s      *next;  /* circular list of hwgroup drives */
        void            *driver_data;   /* extra driver data */
        struct hd_driveid       *id;    /* drive model identification info */
+#ifdef CONFIG_IDE_PROC_FS
        struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
        struct ide_settings_s *settings;/* /proc/ide/ drive settings */
-
+#endif
        struct hwif_s           *hwif;  /* actually (ide_hwif_t *) */
 
        unsigned long sleep;            /* sleep until this time */
@@ -601,16 +603,12 @@ typedef struct ide_drive_s {
        unsigned remap_0_to_1   : 1;    /* 0=noremap, 1=remap 0->1 (for EZDrive) */
        unsigned blocked        : 1;    /* 1=powermanagment told us not to do anything, so sleep nicely */
        unsigned vdma           : 1;    /* 1=doing PIO over DMA 0=doing normal DMA */
-       unsigned addressing;            /*      : 3;
-                                        *  0=28-bit
-                                        *  1=48-bit
-                                        *  2=48-bit doing 28-bit
-                                        *  3=64-bit
-                                        */
        unsigned scsi           : 1;    /* 0=default, 1=ide-scsi emulation */
        unsigned sleeping       : 1;    /* 1=sleeping & sleep field valid */
        unsigned post_reset     : 1;
+       unsigned udma33_warned  : 1;
 
+       u8      addressing;     /* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */
         u8     quirk_list;     /* considered quirky, set for a specific host */
         u8     init_speed;     /* transfer rate set at boot */
         u8     current_speed;  /* current transfer rate set */
@@ -717,11 +715,8 @@ typedef struct hwif_s {
        int     (*quirkproc)(ide_drive_t *);
        /* driver soft-power interface */
        int     (*busproc)(ide_drive_t *, int);
-//     /* host rate limiter */
-//     u8      (*ratemask)(ide_drive_t *);
-//     /* device rate limiter */
-//     u8      (*ratefilter)(ide_drive_t *, u8);
 #endif
+       u8 (*udma_filter)(ide_drive_t *);
 
        void (*ata_input_data)(ide_drive_t *, void *, u32);
        void (*ata_output_data)(ide_drive_t *, void *, u32);
@@ -866,16 +861,22 @@ typedef struct hwgroup_s {
        unsigned char cmd_buf[4];
 } ide_hwgroup_t;
 
-/* structure attached to the request for IDE_TASK_CMDS */
+typedef struct ide_driver_s ide_driver_t;
+
+extern struct semaphore ide_setting_sem;
+
+int set_io_32bit(ide_drive_t *, int);
+int set_pio_mode(ide_drive_t *, int);
+int set_using_dma(ide_drive_t *, int);
 
+#ifdef CONFIG_IDE_PROC_FS
 /*
  * configurable drive settings
  */
 
 #define TYPE_INT       0
-#define TYPE_INTA      1
-#define TYPE_BYTE      2
-#define TYPE_SHORT     3
+#define TYPE_BYTE      1
+#define TYPE_SHORT     2
 
 #define SETTING_READ   (1 << 0)
 #define SETTING_WRITE  (1 << 1)
@@ -885,8 +886,6 @@ typedef int (ide_procset_t)(ide_drive_t *, int);
 typedef struct ide_settings_s {
        char                    *name;
        int                     rw;
-       int                     read_ioctl;
-       int                     write_ioctl;
        int                     data_type;
        int                     min;
        int                     max;
@@ -898,12 +897,7 @@ typedef struct ide_settings_s {
        struct ide_settings_s   *next;
 } ide_settings_t;
 
-extern struct semaphore ide_setting_sem;
-extern int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set);
-extern ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name);
-extern int ide_read_setting(ide_drive_t *t, ide_settings_t *setting);
-extern int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val);
-extern void ide_add_generic_settings(ide_drive_t *drive);
+int ide_add_setting(ide_drive_t *, const char *, int, int, int, int, int, int, void *, ide_procset_t *set);
 
 /*
  * /proc/ide interface
@@ -915,15 +909,15 @@ typedef struct {
        write_proc_t    *write_proc;
 } ide_proc_entry_t;
 
-#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry *proc_ide_root;
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void ide_proc_register_port(ide_hwif_t *);
+void ide_proc_unregister_port(ide_hwif_t *);
+void ide_proc_register_driver(ide_drive_t *, ide_driver_t *);
+void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *);
+
+void ide_add_generic_settings(ide_drive_t *);
 
-extern void proc_ide_create(void);
-extern void proc_ide_destroy(void);
-extern void create_proc_ide_interfaces(void);
-void destroy_proc_ide_interface(ide_hwif_t *);
-extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
-extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -947,8 +941,13 @@ void ide_pci_create_host_proc(const char *, get_info_t *);
        return len;                     \
 }
 #else
-static inline void create_proc_ide_interfaces(void) { ; }
-static inline void destroy_proc_ide_interface(ide_hwif_t *hwif) { ; }
+static inline void proc_ide_create(void) { ; }
+static inline void proc_ide_destroy(void) { ; }
+static inline void ide_proc_register_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; }
+static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; }
+static inline void ide_add_generic_settings(ide_drive_t *drive) { ; }
 #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0;
 #endif
 
@@ -991,7 +990,7 @@ enum {
  * The gendriver.owner field should be set to the module owner of this driver.
  * The gendriver.name field should be set to the name of this driver
  */
-typedef struct ide_driver_s {
+struct ide_driver_s {
        const char                      *version;
        u8                              media;
        unsigned supports_dsc_overlap   : 1;
@@ -999,12 +998,14 @@ typedef struct ide_driver_s {
        int             (*end_request)(ide_drive_t *, int, int);
        ide_startstop_t (*error)(ide_drive_t *, struct request *rq, u8, u8);
        ide_startstop_t (*abort)(ide_drive_t *, struct request *rq);
-       ide_proc_entry_t        *proc;
        struct device_driver    gen_driver;
        int             (*probe)(ide_drive_t *);
        void            (*remove)(ide_drive_t *);
        void            (*shutdown)(ide_drive_t *);
-} ide_driver_t;
+#ifdef CONFIG_IDE_PROC_FS
+       ide_proc_entry_t        *proc;
+#endif
+};
 
 #define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
 
@@ -1204,9 +1205,14 @@ void ide_init_disk(struct gendisk *, ide_drive_t *);
 
 extern int ideprobe_init(void);
 
+#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
 extern void ide_scan_pcibus(int scan_direction) __init;
 extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
 #define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
+#else
+#define ide_pci_register_driver(d) pci_register_driver(d)
+#endif
+
 void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *);
 extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
 
@@ -1214,9 +1220,6 @@ extern void default_hwif_iops(ide_hwif_t *);
 extern void default_hwif_mmiops(ide_hwif_t *);
 extern void default_hwif_transport(ide_hwif_t *);
 
-void ide_register_subdriver(ide_drive_t *, ide_driver_t *);
-void ide_unregister_subdriver(ide_drive_t *, ide_driver_t *);
-
 #define ON_BOARD               1
 #define NEVER_BOARD            0
 
@@ -1257,6 +1260,7 @@ typedef struct ide_pci_device_s {
        unsigned int            extra;
        struct ide_pci_device_s *next;
        u8                      flags;
+       u8                      udma_mask;
 } ide_pci_device_t;
 
 extern int ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
@@ -1278,6 +1282,8 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *);
 int __ide_dma_bad_drive(ide_drive_t *);
 int __ide_dma_good_drive(ide_drive_t *);
 int ide_use_dma(ide_drive_t *);
+u8 ide_max_dma_mode(ide_drive_t *);
+int ide_tune_dma(ide_drive_t *);
 void ide_dma_off(ide_drive_t *);
 void ide_dma_verbose(ide_drive_t *);
 int ide_set_dma(ide_drive_t *);
@@ -1304,6 +1310,8 @@ extern int __ide_dma_timeout(ide_drive_t *);
 
 #else
 static inline int ide_use_dma(ide_drive_t *drive) { return 0; }
+static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; }
+static inline int ide_tune_dma(ide_drive_t *drive) { return 0; }
 static inline void ide_dma_off(ide_drive_t *drive) { ; }
 static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline int ide_set_dma(ide_drive_t *drive) { return 1; }
@@ -1348,8 +1356,7 @@ static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
 }
 
 /* ide-lib.c */
-extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
-extern u8 ide_rate_filter(u8 mode, u8 speed); 
+u8 ide_rate_filter(ide_drive_t *, u8);
 extern int ide_dma_enable(ide_drive_t *drive);
 extern char *ide_xfer_verbose(u8 xfer_rate);
 extern void ide_toggle_bounce(ide_drive_t *drive, int on);
index 795102309bf101e8a1d7be01e80cc97a0427fdfb..276ccaa2670c06892b8e5b402c1561750da6bc03 100644 (file)
@@ -65,9 +65,9 @@
        .posix_timers    = LIST_HEAD_INIT(sig.posix_timers),            \
        .cpu_timers     = INIT_CPU_TIMERS(sig.cpu_timers),              \
        .rlim           = INIT_RLIMITS,                                 \
-       .pgrp           = 1,                                            \
+       .pgrp           = 0,                                            \
        .tty_old_pgrp   = NULL,                                         \
-       { .__session      = 1},                                         \
+       { .__session      = 0},                                         \
 }
 
 extern struct nsproxy init_nsproxy;
@@ -84,10 +84,33 @@ extern struct nsproxy init_nsproxy;
        .count          = ATOMIC_INIT(1),                               \
        .action         = { { { .sa_handler = NULL, } }, },             \
        .siglock        = __SPIN_LOCK_UNLOCKED(sighand.siglock),        \
+       .signalfd_list  = LIST_HEAD_INIT(sighand.signalfd_list),        \
 }
 
 extern struct group_info init_groups;
 
+#define INIT_STRUCT_PID {                                              \
+       .count          = ATOMIC_INIT(1),                               \
+       .nr             = 0,                                            \
+       /* Don't put this struct pid in pid_hash */                     \
+       .pid_chain      = { .next = NULL, .pprev = NULL },              \
+       .tasks          = {                                             \
+               { .first = &init_task.pids[PIDTYPE_PID].node },         \
+               { .first = &init_task.pids[PIDTYPE_PGID].node },        \
+               { .first = &init_task.pids[PIDTYPE_SID].node },         \
+       },                                                              \
+       .rcu            = RCU_HEAD_INIT,                                \
+}
+
+#define INIT_PID_LINK(type)                                    \
+{                                                              \
+       .node = {                                               \
+               .next = NULL,                                   \
+               .pprev = &init_struct_pid.tasks[type].first,    \
+       },                                                      \
+       .pid = &init_struct_pid,                                \
+}
+
 /*
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -95,7 +118,7 @@ extern struct group_info init_groups;
 #define INIT_TASK(tsk) \
 {                                                                      \
        .state          = 0,                                            \
-       .thread_info    = &init_thread_info,                            \
+       .stack          = &init_thread_info,                            \
        .usage          = ATOMIC_INIT(2),                               \
        .flags          = 0,                                            \
        .lock_depth     = -1,                                           \
@@ -139,6 +162,11 @@ extern struct group_info init_groups;
        .cpu_timers     = INIT_CPU_TIMERS(tsk.cpu_timers),              \
        .fs_excl        = ATOMIC_INIT(0),                               \
        .pi_lock        = __SPIN_LOCK_UNLOCKED(tsk.pi_lock),            \
+       .pids = {                                                       \
+               [PIDTYPE_PID]  = INIT_PID_LINK(PIDTYPE_PID),            \
+               [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),           \
+               [PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),            \
+       },                                                              \
        INIT_TRACE_IRQFLAGS                                             \
        INIT_LOCKDEP                                                    \
 }
index f7b01b9a35b3a353789bf6ec2160c8d79d989f4e..5323f627585474b6c0a0fa9d5d585dec5b65224e 100644 (file)
@@ -241,6 +241,16 @@ static inline void __deprecated save_and_cli(unsigned long *x)
 #define save_and_cli(x)        save_and_cli(&x)
 #endif /* CONFIG_SMP */
 
+/* Some architectures might implement lazy enabling/disabling of
+ * interrupts. In some cases, such as stop_machine, we might want
+ * to ensure that after a local_irq_disable(), interrupts have
+ * really been disabled in hardware. Such architectures need to
+ * implement the following hook.
+ */
+#ifndef hard_irq_disable
+#define hard_irq_disable()     do { } while(0)
+#endif
+
 /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
    frequency threaded job scheduling. For almost all the purposes
    tasklets are more than enough. F.e. all serial device BHs et
index 09d8f105a5a82d0c0fde07b23bd80c63ff489f47..945ba3110874fcf96bc428aa142d611524536896 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 144b615f3a8999c800eddb4ad270c11419b044dc..eec0d13169a68f3d841ac10d281d375e09ba59dc 100644 (file)
@@ -41,6 +41,16 @@ extern const char linux_proc_banner[];
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
 
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ *
+ * A basic shift-right of a 64- or 32-bit quantity.  Use this to suppress
+ * the "right shift count >= width of type" warning when that quantity is
+ * 32-bits.
+ */
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+
 #define        KERN_EMERG      "<0>"   /* system is unusable                   */
 #define        KERN_ALERT      "<1>"   /* action must be taken immediately     */
 #define        KERN_CRIT       "<2>"   /* critical conditions                  */
@@ -203,6 +213,17 @@ extern enum system_states {
 
 extern void dump_stack(void);
 
+enum {
+       DUMP_PREFIX_NONE,
+       DUMP_PREFIX_ADDRESS,
+       DUMP_PREFIX_OFFSET
+};
+extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+                               size_t linebuflen);
+extern void print_hex_dump(const char *level, int prefix_type,
+                               void *buf, size_t len);
+#define hex_asc(x)     "0123456789abcdef"[x]
+
 #ifdef DEBUG
 /* If you are writing a driver, please use dev_dbg instead */
 #define pr_debug(fmt,arg...) \
index 1c65e7a9f186cceee83a1e5e199db44b4260daf2..00dd957e245b43839db5e0972e74ff541e4dafd1 100644 (file)
@@ -30,4 +30,7 @@ void kthread_bind(struct task_struct *k, unsigned int cpu);
 int kthread_stop(struct task_struct *k);
 int kthread_should_stop(void);
 
+int kthreadd(void *unused);
+extern struct task_struct *kthreadd_task;
+
 #endif /* _LINUX_KTHREAD_H */
index 81bb9c7a4eb3fec22b97ea1c2c1cd17e5baffd23..c762954bda148fa18ab13f6d1f71aab26d2e3441 100644 (file)
@@ -43,7 +43,7 @@
  * plain scalar nanosecond based representation can be selected by the
  * config switch CONFIG_KTIME_SCALAR.
  */
-typedef union {
+union ktime {
        s64     tv64;
 #if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
        struct {
@@ -54,7 +54,9 @@ typedef union {
 # endif
        } tv;
 #endif
-} ktime_t;
+};
+
+typedef union ktime ktime_t;           /* Kill this */
 
 #define KTIME_MAX                      ((s64)~((u64)1 << 63))
 #if (BITS_PER_LONG == 64)
index a9c6567fe70c02fa3493915c01da90738bbb3abb..9d713c03e3da681664b31fb55e0ecb82df5cc072 100644 (file)
@@ -14,6 +14,7 @@
 #define ISOFS_SUPER_MAGIC      0x9660
 #define JFFS2_SUPER_MAGIC      0x72b6
 #define KVMFS_SUPER_MAGIC      0x19700426
+#define ANON_INODE_FS_MAGIC    0x09041934
 
 #define MINIX_SUPER_MAGIC      0x137F          /* original minix fs */
 #define MINIX_SUPER_MAGIC2     0x138F          /* minix fs, 30 char names */
index 5cff2923092bfca0aaa9cd050f1855befbec03ad..37972704617f959c7abcd01d51c57684a72a6753 100644 (file)
@@ -94,6 +94,7 @@ struct mca_bus {
 struct mca_driver {
        const short             *id_table;
        void                    *driver_data;
+       int                     integrated_id;
        struct device_driver    driver;
 };
 #define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
@@ -125,6 +126,7 @@ extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
 extern struct bus_type mca_bus_type;
 
 extern int mca_register_driver(struct mca_driver *drv);
+extern int mca_register_driver_integrated(struct mca_driver *, int);
 extern void mca_unregister_driver(struct mca_driver *drv);
 
 /* WARNING: only called by the boot time device setup */
index 11ec45e9a13271630c02881fdacc1ff321aebe70..39fd9c8ddd4b27b2adcf14659e5b4477a3ba8194 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
  *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
new file mode 100644 (file)
index 0000000..4fb552d
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_CMD_H
+#define MLX4_CMD_H
+
+#include <linux/dma-mapping.h>
+
+enum {
+       /* initialization and general commands */
+       MLX4_CMD_SYS_EN          = 0x1,
+       MLX4_CMD_SYS_DIS         = 0x2,
+       MLX4_CMD_MAP_FA          = 0xfff,
+       MLX4_CMD_UNMAP_FA        = 0xffe,
+       MLX4_CMD_RUN_FW          = 0xff6,
+       MLX4_CMD_MOD_STAT_CFG    = 0x34,
+       MLX4_CMD_QUERY_DEV_CAP   = 0x3,
+       MLX4_CMD_QUERY_FW        = 0x4,
+       MLX4_CMD_ENABLE_LAM      = 0xff8,
+       MLX4_CMD_DISABLE_LAM     = 0xff7,
+       MLX4_CMD_QUERY_DDR       = 0x5,
+       MLX4_CMD_QUERY_ADAPTER   = 0x6,
+       MLX4_CMD_INIT_HCA        = 0x7,
+       MLX4_CMD_CLOSE_HCA       = 0x8,
+       MLX4_CMD_INIT_PORT       = 0x9,
+       MLX4_CMD_CLOSE_PORT      = 0xa,
+       MLX4_CMD_QUERY_HCA       = 0xb,
+       MLX4_CMD_SET_PORT        = 0xc,
+       MLX4_CMD_ACCESS_DDR      = 0x2e,
+       MLX4_CMD_MAP_ICM         = 0xffa,
+       MLX4_CMD_UNMAP_ICM       = 0xff9,
+       MLX4_CMD_MAP_ICM_AUX     = 0xffc,
+       MLX4_CMD_UNMAP_ICM_AUX   = 0xffb,
+       MLX4_CMD_SET_ICM_SIZE    = 0xffd,
+
+       /* TPT commands */
+       MLX4_CMD_SW2HW_MPT       = 0xd,
+       MLX4_CMD_QUERY_MPT       = 0xe,
+       MLX4_CMD_HW2SW_MPT       = 0xf,
+       MLX4_CMD_READ_MTT        = 0x10,
+       MLX4_CMD_WRITE_MTT       = 0x11,
+       MLX4_CMD_SYNC_TPT        = 0x2f,
+
+       /* EQ commands */
+       MLX4_CMD_MAP_EQ          = 0x12,
+       MLX4_CMD_SW2HW_EQ        = 0x13,
+       MLX4_CMD_HW2SW_EQ        = 0x14,
+       MLX4_CMD_QUERY_EQ        = 0x15,
+
+       /* CQ commands */
+       MLX4_CMD_SW2HW_CQ        = 0x16,
+       MLX4_CMD_HW2SW_CQ        = 0x17,
+       MLX4_CMD_QUERY_CQ        = 0x18,
+       MLX4_CMD_RESIZE_CQ       = 0x2c,
+
+       /* SRQ commands */
+       MLX4_CMD_SW2HW_SRQ       = 0x35,
+       MLX4_CMD_HW2SW_SRQ       = 0x36,
+       MLX4_CMD_QUERY_SRQ       = 0x37,
+       MLX4_CMD_ARM_SRQ         = 0x40,
+
+       /* QP/EE commands */
+       MLX4_CMD_RST2INIT_QP     = 0x19,
+       MLX4_CMD_INIT2RTR_QP     = 0x1a,
+       MLX4_CMD_RTR2RTS_QP      = 0x1b,
+       MLX4_CMD_RTS2RTS_QP      = 0x1c,
+       MLX4_CMD_SQERR2RTS_QP    = 0x1d,
+       MLX4_CMD_2ERR_QP         = 0x1e,
+       MLX4_CMD_RTS2SQD_QP      = 0x1f,
+       MLX4_CMD_SQD2SQD_QP      = 0x38,
+       MLX4_CMD_SQD2RTS_QP      = 0x20,
+       MLX4_CMD_2RST_QP         = 0x21,
+       MLX4_CMD_QUERY_QP        = 0x22,
+       MLX4_CMD_INIT2INIT_QP    = 0x2d,
+       MLX4_CMD_SUSPEND_QP      = 0x32,
+       MLX4_CMD_UNSUSPEND_QP    = 0x33,
+       /* special QP and management commands */
+       MLX4_CMD_CONF_SPECIAL_QP = 0x23,
+       MLX4_CMD_MAD_IFC         = 0x24,
+
+       /* multicast commands */
+       MLX4_CMD_READ_MCG        = 0x25,
+       MLX4_CMD_WRITE_MCG       = 0x26,
+       MLX4_CMD_MGID_HASH       = 0x27,
+
+       /* miscellaneous commands */
+       MLX4_CMD_DIAG_RPRT       = 0x30,
+       MLX4_CMD_NOP             = 0x31,
+
+       /* debug commands */
+       MLX4_CMD_QUERY_DEBUG_MSG = 0x2a,
+       MLX4_CMD_SET_DEBUG_MSG   = 0x2b,
+};
+
+enum {
+       MLX4_CMD_TIME_CLASS_A   = 10000,
+       MLX4_CMD_TIME_CLASS_B   = 10000,
+       MLX4_CMD_TIME_CLASS_C   = 10000,
+};
+
+enum {
+       MLX4_MAILBOX_SIZE       =  4096
+};
+
+struct mlx4_dev;
+
+struct mlx4_cmd_mailbox {
+       void                   *buf;
+       dma_addr_t              dma;
+};
+
+int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
+              int out_is_imm, u32 in_modifier, u8 op_modifier,
+              u16 op, unsigned long timeout);
+
+/* Invoke a command with no output parameter */
+static inline int mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u32 in_modifier,
+                          u8 op_modifier, u16 op, unsigned long timeout)
+{
+       return __mlx4_cmd(dev, in_param, NULL, 0, in_modifier,
+                         op_modifier, op, timeout);
+}
+
+/* Invoke a command with an output mailbox */
+static inline int mlx4_cmd_box(struct mlx4_dev *dev, u64 in_param, u64 out_param,
+                              u32 in_modifier, u8 op_modifier, u16 op,
+                              unsigned long timeout)
+{
+       return __mlx4_cmd(dev, in_param, &out_param, 0, in_modifier,
+                         op_modifier, op, timeout);
+}
+
+/*
+ * Invoke a command with an immediate output parameter (and copy the
+ * output into the caller's out_param pointer after the command
+ * executes).
+ */
+static inline int mlx4_cmd_imm(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
+                              u32 in_modifier, u8 op_modifier, u16 op,
+                              unsigned long timeout)
+{
+       return __mlx4_cmd(dev, in_param, out_param, 1, in_modifier,
+                         op_modifier, op, timeout);
+}
+
+struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev);
+void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox);
+
+#endif /* MLX4_CMD_H */
diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h
new file mode 100644 (file)
index 0000000..0181e0a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_CQ_H
+#define MLX4_CQ_H
+
+#include <linux/types.h>
+
+#include <linux/mlx4/device.h>
+#include <linux/mlx4/doorbell.h>
+
+struct mlx4_cqe {
+       __be32                  my_qpn;
+       __be32                  immed_rss_invalid;
+       __be32                  g_mlpath_rqpn;
+       u8                      sl;
+       u8                      reserved1;
+       __be16                  rlid;
+       u32                     reserved2;
+       __be32                  byte_cnt;
+       __be16                  wqe_index;
+       __be16                  checksum;
+       u8                      reserved3[3];
+       u8                      owner_sr_opcode;
+};
+
+struct mlx4_err_cqe {
+       __be32                  my_qpn;
+       u32                     reserved1[5];
+       __be16                  wqe_index;
+       u8                      vendor_err_syndrome;
+       u8                      syndrome;
+       u8                      reserved2[3];
+       u8                      owner_sr_opcode;
+};
+
+enum {
+       MLX4_CQE_OWNER_MASK     = 0x80,
+       MLX4_CQE_IS_SEND_MASK   = 0x40,
+       MLX4_CQE_OPCODE_MASK    = 0x1f
+};
+
+enum {
+       MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR              = 0x01,
+       MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR               = 0x02,
+       MLX4_CQE_SYNDROME_LOCAL_PROT_ERR                = 0x04,
+       MLX4_CQE_SYNDROME_WR_FLUSH_ERR                  = 0x05,
+       MLX4_CQE_SYNDROME_MW_BIND_ERR                   = 0x06,
+       MLX4_CQE_SYNDROME_BAD_RESP_ERR                  = 0x10,
+       MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR              = 0x11,
+       MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR          = 0x12,
+       MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR             = 0x13,
+       MLX4_CQE_SYNDROME_REMOTE_OP_ERR                 = 0x14,
+       MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR       = 0x15,
+       MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR             = 0x16,
+       MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR            = 0x22,
+};
+
+static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd,
+                              void __iomem *uar_page,
+                              spinlock_t *doorbell_lock)
+{
+       __be32 doorbell[2];
+       u32 sn;
+       u32 ci;
+
+       sn = cq->arm_sn & 3;
+       ci = cq->cons_index & 0xffffff;
+
+       *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci);
+
+       /*
+        * Make sure that the doorbell record in host memory is
+        * written before ringing the doorbell via PCI MMIO.
+        */
+       wmb();
+
+       doorbell[0] = cpu_to_be32(sn << 28 | cmd | cq->cqn);
+       doorbell[1] = cpu_to_be32(ci);
+
+       mlx4_write64(doorbell, uar_page + MLX4_CQ_DOORBELL, doorbell_lock);
+}
+
+static inline void mlx4_cq_set_ci(struct mlx4_cq *cq)
+{
+       *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff);
+}
+
+enum {
+       MLX4_CQ_DB_REQ_NOT_SOL          = 1 << 24,
+       MLX4_CQ_DB_REQ_NOT              = 2 << 24
+};
+
+#endif /* MLX4_CQ_H */
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
new file mode 100644 (file)
index 0000000..8c5f8fd
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_DEVICE_H
+#define MLX4_DEVICE_H
+
+#include <linux/pci.h>
+#include <linux/completion.h>
+#include <linux/radix-tree.h>
+
+#include <asm/atomic.h>
+
+enum {
+       MLX4_FLAG_MSI_X         = 1 << 0,
+};
+
+enum {
+       MLX4_MAX_PORTS          = 2
+};
+
+enum {
+       MLX4_DEV_CAP_FLAG_RC            = 1 <<  0,
+       MLX4_DEV_CAP_FLAG_UC            = 1 <<  1,
+       MLX4_DEV_CAP_FLAG_UD            = 1 <<  2,
+       MLX4_DEV_CAP_FLAG_SRQ           = 1 <<  6,
+       MLX4_DEV_CAP_FLAG_IPOIB_CSUM    = 1 <<  7,
+       MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1 <<  8,
+       MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1 <<  9,
+       MLX4_DEV_CAP_FLAG_MEM_WINDOW    = 1 << 16,
+       MLX4_DEV_CAP_FLAG_APM           = 1 << 17,
+       MLX4_DEV_CAP_FLAG_ATOMIC        = 1 << 18,
+       MLX4_DEV_CAP_FLAG_RAW_MCAST     = 1 << 19,
+       MLX4_DEV_CAP_FLAG_UD_AV_PORT    = 1 << 20,
+       MLX4_DEV_CAP_FLAG_UD_MCAST      = 1 << 21
+};
+
+enum mlx4_event {
+       MLX4_EVENT_TYPE_COMP               = 0x00,
+       MLX4_EVENT_TYPE_PATH_MIG           = 0x01,
+       MLX4_EVENT_TYPE_COMM_EST           = 0x02,
+       MLX4_EVENT_TYPE_SQ_DRAINED         = 0x03,
+       MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE    = 0x13,
+       MLX4_EVENT_TYPE_SRQ_LIMIT          = 0x14,
+       MLX4_EVENT_TYPE_CQ_ERROR           = 0x04,
+       MLX4_EVENT_TYPE_WQ_CATAS_ERROR     = 0x05,
+       MLX4_EVENT_TYPE_EEC_CATAS_ERROR    = 0x06,
+       MLX4_EVENT_TYPE_PATH_MIG_FAILED    = 0x07,
+       MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
+       MLX4_EVENT_TYPE_WQ_ACCESS_ERROR    = 0x11,
+       MLX4_EVENT_TYPE_SRQ_CATAS_ERROR    = 0x12,
+       MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR  = 0x08,
+       MLX4_EVENT_TYPE_PORT_CHANGE        = 0x09,
+       MLX4_EVENT_TYPE_EQ_OVERFLOW        = 0x0f,
+       MLX4_EVENT_TYPE_ECC_DETECT         = 0x0e,
+       MLX4_EVENT_TYPE_CMD                = 0x0a
+};
+
+enum {
+       MLX4_PORT_CHANGE_SUBTYPE_DOWN   = 1,
+       MLX4_PORT_CHANGE_SUBTYPE_ACTIVE = 4
+};
+
+enum {
+       MLX4_PERM_LOCAL_READ    = 1 << 10,
+       MLX4_PERM_LOCAL_WRITE   = 1 << 11,
+       MLX4_PERM_REMOTE_READ   = 1 << 12,
+       MLX4_PERM_REMOTE_WRITE  = 1 << 13,
+       MLX4_PERM_ATOMIC        = 1 << 14
+};
+
+enum {
+       MLX4_OPCODE_NOP                 = 0x00,
+       MLX4_OPCODE_SEND_INVAL          = 0x01,
+       MLX4_OPCODE_RDMA_WRITE          = 0x08,
+       MLX4_OPCODE_RDMA_WRITE_IMM      = 0x09,
+       MLX4_OPCODE_SEND                = 0x0a,
+       MLX4_OPCODE_SEND_IMM            = 0x0b,
+       MLX4_OPCODE_LSO                 = 0x0e,
+       MLX4_OPCODE_RDMA_READ           = 0x10,
+       MLX4_OPCODE_ATOMIC_CS           = 0x11,
+       MLX4_OPCODE_ATOMIC_FA           = 0x12,
+       MLX4_OPCODE_ATOMIC_MASK_CS      = 0x14,
+       MLX4_OPCODE_ATOMIC_MASK_FA      = 0x15,
+       MLX4_OPCODE_BIND_MW             = 0x18,
+       MLX4_OPCODE_FMR                 = 0x19,
+       MLX4_OPCODE_LOCAL_INVAL         = 0x1b,
+       MLX4_OPCODE_CONFIG_CMD          = 0x1f,
+
+       MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00,
+       MLX4_RECV_OPCODE_SEND           = 0x01,
+       MLX4_RECV_OPCODE_SEND_IMM       = 0x02,
+       MLX4_RECV_OPCODE_SEND_INVAL     = 0x03,
+
+       MLX4_CQE_OPCODE_ERROR           = 0x1e,
+       MLX4_CQE_OPCODE_RESIZE          = 0x16,
+};
+
+enum {
+       MLX4_STAT_RATE_OFFSET   = 5
+};
+
+struct mlx4_caps {
+       u64                     fw_ver;
+       int                     num_ports;
+       int                     vl_cap;
+       int                     mtu_cap;
+       int                     gid_table_len;
+       int                     pkey_table_len;
+       int                     local_ca_ack_delay;
+       int                     num_uars;
+       int                     bf_reg_size;
+       int                     bf_regs_per_page;
+       int                     max_sq_sg;
+       int                     max_rq_sg;
+       int                     num_qps;
+       int                     max_wqes;
+       int                     max_sq_desc_sz;
+       int                     max_rq_desc_sz;
+       int                     max_qp_init_rdma;
+       int                     max_qp_dest_rdma;
+       int                     reserved_qps;
+       int                     sqp_start;
+       int                     num_srqs;
+       int                     max_srq_wqes;
+       int                     max_srq_sge;
+       int                     reserved_srqs;
+       int                     num_cqs;
+       int                     max_cqes;
+       int                     reserved_cqs;
+       int                     num_eqs;
+       int                     reserved_eqs;
+       int                     num_mpts;
+       int                     num_mtt_segs;
+       int                     fmr_reserved_mtts;
+       int                     reserved_mtts;
+       int                     reserved_mrws;
+       int                     reserved_uars;
+       int                     num_mgms;
+       int                     num_amgms;
+       int                     reserved_mcgs;
+       int                     num_qp_per_mgm;
+       int                     num_pds;
+       int                     reserved_pds;
+       int                     mtt_entry_sz;
+       u32                     page_size_cap;
+       u32                     flags;
+       u16                     stat_rate_support;
+       u8                      port_width_cap;
+};
+
+struct mlx4_buf_list {
+       void                   *buf;
+       dma_addr_t              map;
+};
+
+struct mlx4_buf {
+       union {
+               struct mlx4_buf_list    direct;
+               struct mlx4_buf_list   *page_list;
+       } u;
+       int                     nbufs;
+       int                     npages;
+       int                     page_shift;
+};
+
+struct mlx4_mtt {
+       u32                     first_seg;
+       int                     order;
+       int                     page_shift;
+};
+
+struct mlx4_mr {
+       struct mlx4_mtt         mtt;
+       u64                     iova;
+       u64                     size;
+       u32                     key;
+       u32                     pd;
+       u32                     access;
+       int                     enabled;
+};
+
+struct mlx4_uar {
+       unsigned long           pfn;
+       int                     index;
+};
+
+struct mlx4_cq {
+       void (*comp)            (struct mlx4_cq *);
+       void (*event)           (struct mlx4_cq *, enum mlx4_event);
+
+       struct mlx4_uar        *uar;
+
+       u32                     cons_index;
+
+       __be32                 *set_ci_db;
+       __be32                 *arm_db;
+       int                     arm_sn;
+
+       int                     cqn;
+
+       atomic_t                refcount;
+       struct completion       free;
+};
+
+struct mlx4_qp {
+       void (*event)           (struct mlx4_qp *, enum mlx4_event);
+
+       int                     qpn;
+
+       atomic_t                refcount;
+       struct completion       free;
+};
+
+struct mlx4_srq {
+       void (*event)           (struct mlx4_srq *, enum mlx4_event);
+
+       int                     srqn;
+       int                     max;
+       int                     max_gs;
+       int                     wqe_shift;
+
+       atomic_t                refcount;
+       struct completion       free;
+};
+
+struct mlx4_av {
+       __be32                  port_pd;
+       u8                      reserved1;
+       u8                      g_slid;
+       __be16                  dlid;
+       u8                      reserved2;
+       u8                      gid_index;
+       u8                      stat_rate;
+       u8                      hop_limit;
+       __be32                  sl_tclass_flowlabel;
+       u8                      dgid[16];
+};
+
+struct mlx4_dev {
+       struct pci_dev         *pdev;
+       unsigned long           flags;
+       struct mlx4_caps        caps;
+       struct radix_tree_root  qp_table_tree;
+};
+
+struct mlx4_init_port_param {
+       int                     set_guid0;
+       int                     set_node_guid;
+       int                     set_si_guid;
+       u16                     mtu;
+       int                     port_width_cap;
+       u16                     vl_cap;
+       u16                     max_gid;
+       u16                     max_pkey;
+       u64                     guid0;
+       u64                     node_guid;
+       u64                     si_guid;
+};
+
+int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
+                  struct mlx4_buf *buf);
+void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf);
+
+int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn);
+void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn);
+
+int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar);
+void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar);
+
+int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
+                 struct mlx4_mtt *mtt);
+void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt);
+u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt);
+
+int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
+                 int npages, int page_shift, struct mlx4_mr *mr);
+void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr);
+int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr);
+int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                  int start_index, int npages, u64 *page_list);
+int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                      struct mlx4_buf *buf);
+
+int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
+                 struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq);
+void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp);
+void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp);
+
+int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
+                  u64 db_rec, struct mlx4_srq *srq);
+void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq);
+int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark);
+
+int mlx4_INIT_PORT(struct mlx4_dev *dev, struct mlx4_init_port_param *param, int port);
+int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port);
+
+int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]);
+int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]);
+
+#endif /* MLX4_DEVICE_H */
diff --git a/include/linux/mlx4/doorbell.h b/include/linux/mlx4/doorbell.h
new file mode 100644 (file)
index 0000000..3f2da44
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2004 Topspin Communications.  All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_DOORBELL_H
+#define MLX4_DOORBELL_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define MLX4_SEND_DOORBELL    0x14
+#define MLX4_CQ_DOORBELL      0x20
+
+#if BITS_PER_LONG == 64
+/*
+ * Assume that we can just write a 64-bit doorbell atomically.  s390
+ * actually doesn't have writeq() but S/390 systems don't even have
+ * PCI so we won't worry about it.
+ */
+
+#define MLX4_DECLARE_DOORBELL_LOCK(name)
+#define MLX4_INIT_DOORBELL_LOCK(ptr)    do { } while (0)
+#define MLX4_GET_DOORBELL_LOCK(ptr)      (NULL)
+
+static inline void mlx4_write64_raw(__be64 val, void __iomem *dest)
+{
+       __raw_writeq((__force u64) val, dest);
+}
+
+static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
+                               spinlock_t *doorbell_lock)
+{
+       __raw_writeq(*(u64 *) val, dest);
+}
+
+#else
+
+/*
+ * Just fall back to a spinlock to protect the doorbell if
+ * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit
+ * MMIO writes.
+ */
+
+#define MLX4_DECLARE_DOORBELL_LOCK(name) spinlock_t name;
+#define MLX4_INIT_DOORBELL_LOCK(ptr)     spin_lock_init(ptr)
+#define MLX4_GET_DOORBELL_LOCK(ptr)      (ptr)
+
+static inline void mlx4_write64_raw(__be64 val, void __iomem *dest)
+{
+       __raw_writel(((__force u32 *) &val)[0], dest);
+       __raw_writel(((__force u32 *) &val)[1], dest + 4);
+}
+
+static inline void mlx4_write64(__be32 val[2], void __iomem *dest,
+                               spinlock_t *doorbell_lock)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(doorbell_lock, flags);
+       __raw_writel((__force u32) val[0], dest);
+       __raw_writel((__force u32) val[1], dest + 4);
+       spin_unlock_irqrestore(doorbell_lock, flags);
+}
+
+#endif
+
+#endif /* MLX4_DOORBELL_H */
diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h
new file mode 100644 (file)
index 0000000..1b835ca
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2006 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_DRIVER_H
+#define MLX4_DRIVER_H
+
+#include <linux/device.h>
+
+struct mlx4_dev;
+
+enum mlx4_dev_event {
+       MLX4_DEV_EVENT_CATASTROPHIC_ERROR,
+       MLX4_DEV_EVENT_PORT_UP,
+       MLX4_DEV_EVENT_PORT_DOWN,
+       MLX4_DEV_EVENT_PORT_REINIT,
+};
+
+struct mlx4_interface {
+       void *                  (*add)   (struct mlx4_dev *dev);
+       void                    (*remove)(struct mlx4_dev *dev, void *context);
+       void                    (*event) (struct mlx4_dev *dev, void *context,
+                                         enum mlx4_dev_event event, int subtype,
+                                         int port);
+       struct list_head        list;
+};
+
+int mlx4_register_interface(struct mlx4_interface *intf);
+void mlx4_unregister_interface(struct mlx4_interface *intf);
+
+#endif /* MLX4_DRIVER_H */
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
new file mode 100644 (file)
index 0000000..9eeb61a
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_QP_H
+#define MLX4_QP_H
+
+#include <linux/types.h>
+
+#include <linux/mlx4/device.h>
+
+#define MLX4_INVALID_LKEY      0x100
+
+enum mlx4_qp_optpar {
+       MLX4_QP_OPTPAR_ALT_ADDR_PATH            = 1 << 0,
+       MLX4_QP_OPTPAR_RRE                      = 1 << 1,
+       MLX4_QP_OPTPAR_RAE                      = 1 << 2,
+       MLX4_QP_OPTPAR_RWE                      = 1 << 3,
+       MLX4_QP_OPTPAR_PKEY_INDEX               = 1 << 4,
+       MLX4_QP_OPTPAR_Q_KEY                    = 1 << 5,
+       MLX4_QP_OPTPAR_RNR_TIMEOUT              = 1 << 6,
+       MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH        = 1 << 7,
+       MLX4_QP_OPTPAR_SRA_MAX                  = 1 << 8,
+       MLX4_QP_OPTPAR_RRA_MAX                  = 1 << 9,
+       MLX4_QP_OPTPAR_PM_STATE                 = 1 << 10,
+       MLX4_QP_OPTPAR_RETRY_COUNT              = 1 << 12,
+       MLX4_QP_OPTPAR_RNR_RETRY                = 1 << 13,
+       MLX4_QP_OPTPAR_ACK_TIMEOUT              = 1 << 14,
+       MLX4_QP_OPTPAR_SCHED_QUEUE              = 1 << 16
+};
+
+enum mlx4_qp_state {
+       MLX4_QP_STATE_RST                       = 0,
+       MLX4_QP_STATE_INIT                      = 1,
+       MLX4_QP_STATE_RTR                       = 2,
+       MLX4_QP_STATE_RTS                       = 3,
+       MLX4_QP_STATE_SQER                      = 4,
+       MLX4_QP_STATE_SQD                       = 5,
+       MLX4_QP_STATE_ERR                       = 6,
+       MLX4_QP_STATE_SQ_DRAINING               = 7,
+       MLX4_QP_NUM_STATE
+};
+
+enum {
+       MLX4_QP_ST_RC                           = 0x0,
+       MLX4_QP_ST_UC                           = 0x1,
+       MLX4_QP_ST_RD                           = 0x2,
+       MLX4_QP_ST_UD                           = 0x3,
+       MLX4_QP_ST_MLX                          = 0x7
+};
+
+enum {
+       MLX4_QP_PM_MIGRATED                     = 0x3,
+       MLX4_QP_PM_ARMED                        = 0x0,
+       MLX4_QP_PM_REARM                        = 0x1
+};
+
+enum {
+       /* params1 */
+       MLX4_QP_BIT_SRE                         = 1 << 15,
+       MLX4_QP_BIT_SWE                         = 1 << 14,
+       MLX4_QP_BIT_SAE                         = 1 << 13,
+       /* params2 */
+       MLX4_QP_BIT_RRE                         = 1 << 15,
+       MLX4_QP_BIT_RWE                         = 1 << 14,
+       MLX4_QP_BIT_RAE                         = 1 << 13,
+       MLX4_QP_BIT_RIC                         = 1 <<  4,
+};
+
+struct mlx4_qp_path {
+       u8                      fl;
+       u8                      reserved1[2];
+       u8                      pkey_index;
+       u8                      reserved2;
+       u8                      grh_mylmc;
+       __be16                  rlid;
+       u8                      ackto;
+       u8                      mgid_index;
+       u8                      static_rate;
+       u8                      hop_limit;
+       __be32                  tclass_flowlabel;
+       u8                      rgid[16];
+       u8                      sched_queue;
+       u8                      snooper_flags;
+       u8                      reserved3[2];
+       u8                      counter_index;
+       u8                      reserved4[7];
+};
+
+struct mlx4_qp_context {
+       __be32                  flags;
+       __be32                  pd;
+       u8                      mtu_msgmax;
+       u8                      rq_size_stride;
+       u8                      sq_size_stride;
+       u8                      rlkey;
+       __be32                  usr_page;
+       __be32                  local_qpn;
+       __be32                  remote_qpn;
+       struct                  mlx4_qp_path pri_path;
+       struct                  mlx4_qp_path alt_path;
+       __be32                  params1;
+       u32                     reserved1;
+       __be32                  next_send_psn;
+       __be32                  cqn_send;
+       u32                     reserved2[2];
+       __be32                  last_acked_psn;
+       __be32                  ssn;
+       __be32                  params2;
+       __be32                  rnr_nextrecvpsn;
+       __be32                  srcd;
+       __be32                  cqn_recv;
+       __be64                  db_rec_addr;
+       __be32                  qkey;
+       __be32                  srqn;
+       __be32                  msn;
+       __be16                  rq_wqe_counter;
+       __be16                  sq_wqe_counter;
+       u32                     reserved3[2];
+       __be32                  param3;
+       __be32                  nummmcpeers_basemkey;
+       u8                      log_page_size;
+       u8                      reserved4[2];
+       u8                      mtt_base_addr_h;
+       __be32                  mtt_base_addr_l;
+       u32                     reserved5[10];
+};
+
+enum {
+       MLX4_WQE_CTRL_FENCE     = 1 << 6,
+       MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2,
+       MLX4_WQE_CTRL_SOLICITED = 1 << 1,
+};
+
+struct mlx4_wqe_ctrl_seg {
+       __be32                  owner_opcode;
+       u8                      reserved2[3];
+       u8                      fence_size;
+       /*
+        * High 24 bits are SRC remote buffer; low 8 bits are flags:
+        * [7]   SO (strong ordering)
+        * [5]   TCP/UDP checksum
+        * [4]   IP checksum
+        * [3:2] C (generate completion queue entry)
+        * [1]   SE (solicited event)
+        */
+       __be32                  srcrb_flags;
+       /*
+        * imm is immediate data for send/RDMA write w/ immediate;
+        * also invalidation key for send with invalidate; input
+        * modifier for WQEs on CCQs.
+        */
+       __be32                  imm;
+};
+
+enum {
+       MLX4_WQE_MLX_VL15       = 1 << 17,
+       MLX4_WQE_MLX_SLR        = 1 << 16
+};
+
+struct mlx4_wqe_mlx_seg {
+       u8                      owner;
+       u8                      reserved1[2];
+       u8                      opcode;
+       u8                      reserved2[3];
+       u8                      size;
+       /*
+        * [17]    VL15
+        * [16]    SLR
+        * [15:12] static rate
+        * [11:8]  SL
+        * [4]     ICRC
+        * [3:2]   C
+        * [0]     FL (force loopback)
+        */
+       __be32                  flags;
+       __be16                  rlid;
+       u16                     reserved3;
+};
+
+struct mlx4_wqe_datagram_seg {
+       __be32                  av[8];
+       __be32                  dqpn;
+       __be32                  qkey;
+       __be32                  reservd[2];
+};
+
+struct mlx4_wqe_bind_seg {
+       __be32                  flags1;
+       __be32                  flags2;
+       __be32                  new_rkey;
+       __be32                  lkey;
+       __be64                  addr;
+       __be64                  length;
+};
+
+struct mlx4_wqe_fmr_seg {
+       __be32                  flags;
+       __be32                  mem_key;
+       __be64                  buf_list;
+       __be64                  start_addr;
+       __be64                  reg_len;
+       __be32                  offset;
+       __be32                  page_size;
+       u32                     reserved[2];
+};
+
+struct mlx4_wqe_fmr_ext_seg {
+       u8                      flags;
+       u8                      reserved;
+       __be16                  app_mask;
+       __be16                  wire_app_tag;
+       __be16                  mem_app_tag;
+       __be32                  wire_ref_tag_base;
+       __be32                  mem_ref_tag_base;
+};
+
+struct mlx4_wqe_local_inval_seg {
+       u8                      flags;
+       u8                      reserved1[3];
+       __be32                  mem_key;
+       u8                      reserved2[3];
+       u8                      guest_id;
+       __be64                  pa;
+};
+
+struct mlx4_wqe_raddr_seg {
+       __be64                  raddr;
+       __be32                  rkey;
+       u32                     reserved;
+};
+
+struct mlx4_wqe_atomic_seg {
+       __be64                  swap_add;
+       __be64                  compare;
+};
+
+struct mlx4_wqe_data_seg {
+       __be32                  byte_count;
+       __be32                  lkey;
+       __be64                  addr;
+};
+
+struct mlx4_wqe_inline_seg {
+       __be32                  byte_count;
+};
+
+int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+                  enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state,
+                  struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar,
+                  int sqd_event, struct mlx4_qp *qp);
+
+static inline struct mlx4_qp *__mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
+{
+       return radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1));
+}
+
+void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp);
+
+#endif /* MLX4_QP_H */
diff --git a/include/linux/mlx4/srq.h b/include/linux/mlx4/srq.h
new file mode 100644 (file)
index 0000000..799a069
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef MLX4_SRQ_H
+#define MLX4_SRQ_H
+
+struct mlx4_wqe_srq_next_seg {
+       u16                     reserved1;
+       __be16                  next_wqe_index;
+       u32                     reserved2[3];
+};
+
+#endif /* MLX4_SRQ_H */
index e30687bad07590c11acf6c43debb041d5db89316..d5bb1796e12b19a1dde4960c2f10d0064a8867b9 100644 (file)
@@ -50,13 +50,16 @@ struct page {
            spinlock_t ptl;
 #endif
            struct {                    /* SLUB uses */
-               struct page *first_page;        /* Compound pages */
+               void **lockless_freelist;
                struct kmem_cache *slab;        /* Pointer to slab */
            };
+           struct {
+               struct page *first_page;        /* Compound pages */
+           };
        };
        union {
                pgoff_t index;          /* Our offset within mapping. */
-               void *freelist;         /* SLUB: pointer to free object */
+               void *freelist;         /* SLUB: freelist req. slab lock */
        };
        struct list_head lru;           /* Pageout list, eg. active_list
                                         * protected by zone->lru_lock !
index 2f1544e83042af69d45862f216781de0fe22d9fe..d09b1345a3a14fcf7f5115a2d6efc092e25bd8ed 100644 (file)
@@ -83,6 +83,9 @@ struct per_cpu_pages {
 
 struct per_cpu_pageset {
        struct per_cpu_pages pcp[2];    /* 0: hot.  1: cold */
+#ifdef CONFIG_NUMA
+       s8 expire;
+#endif
 #ifdef CONFIG_SMP
        s8 stat_threshold;
        s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS];
index 6d3dc9c4ff9622163b0ff35759f13b62afc23641..e6e0f86ef5fc8b2302d2711b5c8f99ccfd437e54 100644 (file)
@@ -124,7 +124,7 @@ extern struct module __this_module;
  */
 #define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
 
-/* Author, ideally of form NAME <EMAIL>[, NAME <EMAIL>]*[ and NAME <EMAIL>] */
+/* Author, ideally of form NAME[, NAME]*[ and NAME] */
 #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
   
 /* What your module does. */
@@ -356,6 +356,9 @@ struct module
           keeping pointers to this stuff */
        char *args;
 };
+#ifndef MODULE_ARCH_INIT
+#define MODULE_ARCH_INIT {}
+#endif
 
 /* FIXME: It'd be nice to isolate modules during init, too, so they
    aren't used before they (may) fail.  But presently too much code
index dab69afee2fa457b3d6feaf8bda7d3701d71c4ca..6d3047d8c91c877b9243a5093557ef77c5e61774 100644 (file)
@@ -33,7 +33,7 @@ struct mnt_namespace;
 
 #define MNT_SHARED     0x1000  /* if the vfsmount is a shared mount */
 #define MNT_UNBINDABLE 0x2000  /* if the vfsmount is a unbindable mount */
-#define MNT_PNODE_MASK 0x3000  /* propogation flag mask */
+#define MNT_PNODE_MASK 0x3000  /* propagation flag mask */
 
 struct vfsmount {
        struct list_head mnt_hash;
index cc5fb75af78a25e22c55ba868e4612e09331fbe1..068a0c9946af7e1f780f8cd287a517a14852286b 100644 (file)
@@ -12,7 +12,6 @@
 #ifdef CONFIG_BLOCK
 
 struct writeback_control;
-typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
 
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
                                unsigned nr_pages, get_block_t get_block);
index 45d482ce8397cf2920ac44919121bf3cb334100a..fd64ccfbce02874fd2600b79dc02d84767bde7ae 100644 (file)
@@ -9,10 +9,6 @@
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
 
-#ifndef __KERNEL__
-#error This is a kernel header. Perhaps include mtd-user.h instead?
-#endif
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
@@ -137,9 +133,6 @@ struct mtd_info {
        int numeraseregions;
        struct mtd_erase_region_info *eraseregions;
 
-       /* This really shouldn't be here. It can go away in 2.5 */
-       u_int32_t bank_size;
-
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
        /* This stuff for eXecute-In-Place */
index cf197ad62da6cd8801102946609ad1bd3fd5549b..d2365c8dcacc86ebf872a2124b3dc16201c09877 100644 (file)
@@ -560,6 +560,7 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @chip_delay:                R/B delay value in us
  * @options:           Option flags, e.g. 16bit buswidth
  * @ecclayout:         ecc layout info structure
+ * @part_probe_types:  NULL-terminated array of probe types
  * @priv:              hardware controller specific settings
  */
 struct platform_nand_chip {
@@ -570,6 +571,7 @@ struct platform_nand_chip {
        struct nand_ecclayout   *ecclayout;
        int                     chip_delay;
        unsigned int            options;
+       const char              **part_probe_types;
        void                    *priv;
 };
 
@@ -578,6 +580,8 @@ struct platform_nand_chip {
  * @hwcontrol:         platform specific hardware control structure
  * @dev_ready:         platform specific function to read ready/busy pin
  * @select_chip:       platform specific chip select function
+ * @cmd_ctrl:          platform specific function for controlling
+ *                     ALE/CLE/nCE. Also used to write command and address
  * @priv:              private data to transport driver specific settings
  *
  * All fields are optional and depend on the hardware driver requirements
@@ -586,9 +590,21 @@ struct platform_nand_ctrl {
        void            (*hwcontrol)(struct mtd_info *mtd, int cmd);
        int             (*dev_ready)(struct mtd_info *mtd);
        void            (*select_chip)(struct mtd_info *mtd, int chip);
+       void            (*cmd_ctrl)(struct mtd_info *mtd, int dat,
+                                   unsigned int ctrl);
        void            *priv;
 };
 
+/**
+ * struct platform_nand_data - container structure for platform-specific data
+ * @chip:              chip level chip structure
+ * @ctrl:              controller level device structure
+ */
+struct platform_nand_data {
+       struct platform_nand_chip       chip;
+       struct platform_nand_ctrl       ctrl;
+};
+
 /* Some helpers to access the data structures */
 static inline
 struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
index b81bc2adaeff138095b0db333948f5c03db8d610..0d50ea3df6896ebcf9a60f216a0d72ba9bd14de8 100644 (file)
@@ -121,11 +121,12 @@ static inline int fastcall mutex_is_locked(struct mutex *lock)
  * Also see Documentation/mutex-design.txt.
  */
 extern void fastcall mutex_lock(struct mutex *lock);
-extern int fastcall mutex_lock_interruptible(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass);
+extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
+                                       unsigned int subclass);
 #else
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
index 30446222b39600eb9fa4501e5b8712875e7e14d9..f671cd2f133fd55377f925d59ff224b343993dec 100644 (file)
@@ -467,6 +467,8 @@ struct net_device
        /* device index hash chain */
        struct hlist_node       index_hlist;
 
+       struct net_device       *link_watch_next;
+
        /* register/unregister state machine */
        enum { NETREG_UNINITIALIZED=0,
               NETREG_REGISTERED,       /* completed register_netdevice */
index 022edfa97ed977dfe6fd8f74b28472804067d5a8..7e733a6ba4f6b91031051fc08f7f4f0ca599593b 100644 (file)
@@ -54,6 +54,14 @@ struct xt_entry_target
        unsigned char data[0];
 };
 
+#define XT_TARGET_INIT(__name, __size)                                        \
+{                                                                             \
+       .target.u.user = {                                                     \
+               .target_size    = XT_ALIGN(__size),                            \
+               .name           = __name,                                      \
+       },                                                                     \
+}
+
 struct xt_standard_target
 {
        struct xt_entry_target target;
index 24c8786d12e9f0bc2af9b3fde7bf092ad87439be..584cd1b18f12db6b2ed8520e86343fe9949f7858 100644 (file)
@@ -238,6 +238,47 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
  */
 #ifdef __KERNEL__
 
+/* Standard entry. */
+struct arpt_standard
+{
+       struct arpt_entry entry;
+       struct arpt_standard_target target;
+};
+
+struct arpt_error_target
+{
+       struct arpt_entry_target target;
+       char errorname[ARPT_FUNCTION_MAXNAMELEN];
+};
+
+struct arpt_error
+{
+       struct arpt_entry entry;
+       struct arpt_error_target target;
+};
+
+#define ARPT_ENTRY_INIT(__size)                                                       \
+{                                                                             \
+       .target_offset  = sizeof(struct arpt_entry),                           \
+       .next_offset    = (__size),                                            \
+}
+
+#define ARPT_STANDARD_INIT(__verdict)                                         \
+{                                                                             \
+       .entry          = ARPT_ENTRY_INIT(sizeof(struct arpt_standard)),       \
+       .target         = XT_TARGET_INIT(ARPT_STANDARD_TARGET,                 \
+                                        sizeof(struct arpt_standard_target)), \
+       .target.verdict = -(__verdict) - 1,                                    \
+}
+
+#define ARPT_ERROR_INIT                                                               \
+{                                                                             \
+       .entry          = ARPT_ENTRY_INIT(sizeof(struct arpt_error)),          \
+       .target         = XT_TARGET_INIT(ARPT_ERROR_TARGET,                    \
+                                        sizeof(struct arpt_error_target)),    \
+       .target.errorname = "ERROR",                                           \
+}
+
 #define arpt_register_target(tgt)      \
 ({     (tgt)->family = NF_ARP;         \
        xt_register_target(tgt); })
index 9527296595cd41f9cf1b437e7d204b687ee83ea1..2f46dd728ee1fa9596e4a491782543fc44946012 100644 (file)
@@ -295,6 +295,28 @@ struct ipt_error
        struct ipt_error_target target;
 };
 
+#define IPT_ENTRY_INIT(__size)                                                \
+{                                                                             \
+       .target_offset  = sizeof(struct ipt_entry),                            \
+       .next_offset    = (__size),                                            \
+}
+
+#define IPT_STANDARD_INIT(__verdict)                                          \
+{                                                                             \
+       .entry          = IPT_ENTRY_INIT(sizeof(struct ipt_standard)),         \
+       .target         = XT_TARGET_INIT(IPT_STANDARD_TARGET,                  \
+                                        sizeof(struct xt_standard_target)),   \
+       .target.verdict = -(__verdict) - 1,                                    \
+}
+
+#define IPT_ERROR_INIT                                                        \
+{                                                                             \
+       .entry          = IPT_ENTRY_INIT(sizeof(struct ipt_error)),            \
+       .target         = XT_TARGET_INIT(IPT_ERROR_TARGET,                     \
+                                        sizeof(struct ipt_error_target)),     \
+       .target.errorname = "ERROR",                                           \
+}
+
 extern unsigned int ipt_do_table(struct sk_buff **pskb,
                                 unsigned int hook,
                                 const struct net_device *in,
index 61aa10412fc8b52c81229c1ee466678bd73b4840..4686f8342cbd73db22f6fd847f51f647f6e6c661 100644 (file)
@@ -123,6 +123,28 @@ struct ip6t_error
        struct ip6t_error_target target;
 };
 
+#define IP6T_ENTRY_INIT(__size)                                                       \
+{                                                                             \
+       .target_offset  = sizeof(struct ip6t_entry),                           \
+       .next_offset    = (__size),                                            \
+}
+
+#define IP6T_STANDARD_INIT(__verdict)                                         \
+{                                                                             \
+       .entry          = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)),       \
+       .target         = XT_TARGET_INIT(IP6T_STANDARD_TARGET,                 \
+                                        sizeof(struct ip6t_standard_target)), \
+       .target.verdict = -(__verdict) - 1,                                    \
+}
+
+#define IP6T_ERROR_INIT                                                               \
+{                                                                             \
+       .entry          = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)),          \
+       .target         = XT_TARGET_INIT(IP6T_ERROR_TARGET,                    \
+                                        sizeof(struct ip6t_error_target)),    \
+       .target.errorname = "ERROR",                                           \
+}
+
 /*
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use
index 409b6e02f337cdf757ecfbf90fb009a6632aa611..c9c05a78e9bb32438f866b9d99564cf87ff02287 100644 (file)
@@ -44,7 +44,6 @@
 #define NFS4_ACL_MAX 170
 
 struct nfs4_acl *nfs4_acl_new(int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
 int nfs4_acl_get_whotype(char *, u32);
 int nfs4_acl_write_who(int who, char *p);
 int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
index 10a43ed0527eb0215acba9078786105fb1f8b8de..9431101bf8769508db8dc6263927049d1cfdb9df 100644 (file)
@@ -112,32 +112,40 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
 
 #ifdef __KERNEL__
 
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *,
-               struct notifier_block *);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *,
-               struct notifier_block *);
-extern int raw_notifier_chain_register(struct raw_notifier_head *,
-               struct notifier_block *);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
-               struct notifier_block *);
-
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
-               struct notifier_block *);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *,
-               struct notifier_block *);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
-               struct notifier_block *);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
-               struct notifier_block *);
-
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+               struct notifier_block *nb);
+extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+               struct notifier_block *nb);
+extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+               struct notifier_block *nb);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+               struct notifier_block *nb);
+
+extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+               struct notifier_block *nb);
+extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
+               struct notifier_block *nb);
+extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+               struct notifier_block *nb);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+               struct notifier_block *nb);
+
+extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
                unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
+extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
                unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *,
+extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
                unsigned long val, void *v);
+extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
 
 #define NOTIFY_DONE            0x0000          /* Don't care */
 #define NOTIFY_OK              0x0001          /* Suits me */
@@ -186,6 +194,20 @@ extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
 #define CPU_DOWN_PREPARE       0x0005 /* CPU (unsigned)v going down */
 #define CPU_DOWN_FAILED                0x0006 /* CPU (unsigned)v NOT going down */
 #define CPU_DEAD               0x0007 /* CPU (unsigned)v dead */
+#define CPU_LOCK_ACQUIRE       0x0008 /* Acquire all hotcpu locks */
+#define CPU_LOCK_RELEASE       0x0009 /* Release all hotcpu locks */
+
+/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
+ * operation in progress
+ */
+#define CPU_TASKS_FROZEN       0x0010
+
+#define CPU_ONLINE_FROZEN      (CPU_ONLINE | CPU_TASKS_FROZEN)
+#define CPU_UP_PREPARE_FROZEN  (CPU_UP_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN)
+#define CPU_DOWN_PREPARE_FROZEN        (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
+#define CPU_DEAD_FROZEN                (CPU_DEAD | CPU_TASKS_FROZEN)
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_NOTIFIER_H */
index 2ac27f9997dd99b00324cb50419b13d2e1b0b139..1e0e4e3423a628a7983520762b7364038fbbe628 100644 (file)
@@ -51,6 +51,8 @@ struct pid
        struct rcu_head rcu;
 };
 
+extern struct pid init_struct_pid;
+
 struct pid_link
 {
        struct hlist_node node;
@@ -76,8 +78,7 @@ extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
  * write-held.
  */
 extern int FASTCALL(attach_pid(struct task_struct *task,
-                               enum pid_type type, int nr));
-
+                               enum pid_type type, struct pid *pid));
 extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
 extern void FASTCALL(transfer_pid(struct task_struct *old,
                                  struct task_struct *new, enum pid_type));
index 6e8fa3049e5d097fc5f96400350240e5224ca48e..87545e0f0b5814bdf6dc115165851b062a3df8b6 100644 (file)
@@ -107,26 +107,11 @@ typedef int __bitwise suspend_state_t;
 #define PM_SUSPEND_ON          ((__force suspend_state_t) 0)
 #define PM_SUSPEND_STANDBY     ((__force suspend_state_t) 1)
 #define PM_SUSPEND_MEM         ((__force suspend_state_t) 3)
-#define PM_SUSPEND_DISK                ((__force suspend_state_t) 4)
-#define PM_SUSPEND_MAX         ((__force suspend_state_t) 5)
-
-typedef int __bitwise suspend_disk_method_t;
-
-/* invalid must be 0 so struct pm_ops initialisers can leave it out */
-#define PM_DISK_INVALID                ((__force suspend_disk_method_t) 0)
-#define        PM_DISK_PLATFORM        ((__force suspend_disk_method_t) 1)
-#define        PM_DISK_SHUTDOWN        ((__force suspend_disk_method_t) 2)
-#define        PM_DISK_REBOOT          ((__force suspend_disk_method_t) 3)
-#define        PM_DISK_TEST            ((__force suspend_disk_method_t) 4)
-#define        PM_DISK_TESTPROC        ((__force suspend_disk_method_t) 5)
-#define        PM_DISK_MAX             ((__force suspend_disk_method_t) 6)
+#define PM_SUSPEND_MAX         ((__force suspend_state_t) 4)
 
 /**
  * struct pm_ops - Callbacks for managing platform dependent suspend states.
  * @valid: Callback to determine whether the given state can be entered.
- *     If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
- *     always valid and never passed to this call. If not assigned,
- *     no suspend states are valid.
  *     Valid states are advertised in /sys/power/state but can still
  *     be rejected by prepare or enter if the conditions aren't right.
  *     There is a %pm_valid_only_mem function available that can be assigned
@@ -140,24 +125,12 @@ typedef int __bitwise suspend_disk_method_t;
  *
  * @finish: Called when the system has left the given state and all devices
  *     are resumed. The return value is ignored.
- *
- * @pm_disk_mode: The generic code always allows one of the shutdown methods
- *     %PM_DISK_SHUTDOWN, %PM_DISK_REBOOT, %PM_DISK_TEST and
- *     %PM_DISK_TESTPROC. If this variable is set, the mode it is set
- *     to is allowed in addition to those modes and is also made default.
- *     When this mode is sent selected, the @prepare call will be called
- *     before suspending to disk (if present), the @enter call should be
- *     present and will be called after all state has been saved and the
- *     machine is ready to be powered off; the @finish callback is called
- *     after state has been restored. All these calls are called with
- *     %PM_SUSPEND_DISK as the state.
  */
 struct pm_ops {
        int (*valid)(suspend_state_t state);
        int (*prepare)(suspend_state_t state);
        int (*enter)(suspend_state_t state);
        int (*finish)(suspend_state_t state);
-       suspend_disk_method_t pm_disk_mode;
 };
 
 /**
@@ -276,8 +249,6 @@ extern void device_power_up(void);
 extern void device_resume(void);
 
 #ifdef CONFIG_PM
-extern suspend_disk_method_t pm_disk_mode;
-
 extern int device_suspend(pm_message_t state);
 extern int device_prepare_suspend(pm_message_t state);
 
index 37ca57392addbfe69f0707d8b493653b4ccaa6ca..5ad913ff02b2c47cc1bf771b64dabaa470f5a975 100644 (file)
@@ -226,7 +226,7 @@ extern unsigned int pmu_power_flags;
 extern void pmu_backlight_init(void);
 
 /* some code needs to know if the PMU was suspended for hibernation */
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
 extern int pmu_sys_suspended;
 #else
 /* if power management is not configured it can't be suspended */
index 0deb842541acee1aad74d1e742895ba9812d0661..f9e77d2ee3201ea3565a409216c601734fc17140 100644 (file)
@@ -87,10 +87,10 @@ do {                                                                        \
  * management of their lifetimes must be completely managed by API users.
  *
  * For API usage, in general,
- * - any function _modifying_ the the tree or tags (inserting or deleting
+ * - any function _modifying_ the tree or tags (inserting or deleting
  *   items, setting or clearing tags must exclude other modifications, and
  *   exclude any functions reading the tree.
- * - any function _reading_ the the tree or tags (looking up items or tags,
+ * - any function _reading_ the tree or tags (looking up items or tags,
  *   gang lookups) must exclude modifications to the tree, but may occur
  *   concurrently with other readers.
  *
index 759a0f97bec23db4e26bddcfe124e095ced54b3a..6cd8c4425fc7d5dfb400b37b436c960bf6e163d7 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/fs.h>
@@ -38,7 +39,7 @@ struct rchan_buf
        size_t subbufs_consumed;        /* count of sub-buffers consumed */
        struct rchan *chan;             /* associated channel */
        wait_queue_head_t read_wait;    /* reader wait queue */
-       struct delayed_work wake_readers; /* reader wake-up work struct */
+       struct timer_list timer;        /* reader wake-up timer */
        struct dentry *dentry;          /* channel file dentry */
        struct kref kref;               /* channel buffer refcount */
        struct page **page_array;       /* array of current buffer pages */
index ace25acfdc97375d0d403afb4bf12c08443e6309..746580c1939c028d8f8ef8dc6bb460e5ed6dfc17 100644 (file)
@@ -34,6 +34,7 @@
  * @prim:      Primitive element, index form
  * @iprim:     prim-th root of 1, index form
  * @gfpoly:    The primitive generator polynominal
+ * @gffunc:    Function to generate the field, if non-canonical representation
  * @users:     Users of this structure
  * @list:      List entry for the rs control list
 */
@@ -48,6 +49,7 @@ struct rs_control {
        int             prim;
        int             iprim;
        int             gfpoly;
+       int             (*gffunc)(int);
        int             users;
        struct list_head list;
 };
@@ -77,6 +79,8 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
 /* Create or get a matching rs control structure */
 struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                           int nroots);
+struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
+                                         int fcr, int prim, int nroots);
 
 /* Release a rs control structure */
 void free_rs(struct rs_control *rs);
index 3d95c480f58df881a142cd4221b9d4ec0c382b94..97c0c7da58efe896e519ef3a5a338da716c2b052 100644 (file)
@@ -391,6 +391,7 @@ struct sighand_struct {
        atomic_t                count;
        struct k_sigaction      action[_NSIG];
        spinlock_t              siglock;
+       struct list_head        signalfd_list;
 };
 
 struct pacct_struct {
@@ -469,6 +470,7 @@ struct signal_struct {
        cputime_t utime, stime, cutime, cstime;
        unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
        unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
+       unsigned long inblock, oublock, cinblock, coublock;
 
        /*
         * Cumulative ns of scheduled CPU time for dead threads in the
@@ -817,7 +819,7 @@ struct prio_array;
 
 struct task_struct {
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
-       struct thread_info *thread_info;
+       void *stack;
        atomic_t usage;
        unsigned int flags;     /* per process flags, defined below */
        unsigned int ptrace;
@@ -1317,6 +1319,7 @@ extern int in_egroup_p(gid_t);
 
 extern void proc_caches_init(void);
 extern void flush_signals(struct task_struct *);
+extern void ignore_signals(struct task_struct *);
 extern void flush_signal_handlers(struct task_struct *, int force_default);
 extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
 
@@ -1512,8 +1515,8 @@ static inline void unlock_task_sighand(struct task_struct *tsk,
 
 #ifndef __HAVE_THREAD_FUNCTIONS
 
-#define task_thread_info(task) (task)->thread_info
-#define task_stack_page(task) ((void*)((task)->thread_info))
+#define task_thread_info(task) ((struct thread_info *)(task)->stack)
+#define task_stack_page(task)  ((task)->stack)
 
 static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
 {
@@ -1523,7 +1526,7 @@ static inline void setup_thread_stack(struct task_struct *p, struct task_struct
 
 static inline unsigned long *end_of_stack(struct task_struct *p)
 {
-       return (unsigned long *)(p->thread_info + 1);
+       return (unsigned long *)(task_thread_info(p) + 1);
 }
 
 #endif
index 47e82c120f9ab662963ab17a25fd43417a03998b..9eb9e0fe03312614b8702e0435c1604b928e4190 100644 (file)
@@ -322,7 +322,7 @@ struct request_sock;
  *     @dir contains the inode structure of parent of the new file.
  *     @dentry contains the dentry structure of the new file.
  *     @mode contains the mode of the new file.
- *     @dev contains the the device number.
+ *     @dev contains the device number.
  *     Return 0 if permission is granted.
  * @inode_rename:
  *     Check for permission to rename a file or directory.
index 14749056dd630ac0072439ed53225caac9025c2f..9a5eac508e5e2497b5936e7b6a07166958af52b4 100644 (file)
@@ -233,6 +233,7 @@ static inline int valid_signal(unsigned long sig)
        return sig <= _NSIG ? 1 : 0;
 }
 
+extern int next_signal(struct sigpending *pending, sigset_t *mask);
 extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_sigpending(void __user *, unsigned long);
@@ -243,6 +244,131 @@ extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
 
 extern struct kmem_cache *sighand_cachep;
 
+/*
+ * In POSIX a signal is sent either to a specific thread (Linux task)
+ * or to the process as a whole (Linux thread group).  How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later.  When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ *   ignore    - Nothing Happens
+ *   terminate - kill the process, i.e. all threads in the group,
+ *               similar to exit_group.  The group leader (only) reports
+ *               WIFSIGNALED status to its parent.
+ *   coredump  - write a core dump file describing all threads using
+ *               the same mm and then kill all those threads
+ *   stop      - stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ *     +--------------------+------------------+
+ *     |  POSIX signal      |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGHUP            |  terminate       |
+ *     |  SIGINT            |  terminate       |
+ *     |  SIGQUIT           |  coredump        |
+ *     |  SIGILL            |  coredump        |
+ *     |  SIGTRAP           |  coredump        |
+ *     |  SIGABRT/SIGIOT    |  coredump        |
+ *     |  SIGBUS            |  coredump        |
+ *     |  SIGFPE            |  coredump        |
+ *     |  SIGKILL           |  terminate(+)    |
+ *     |  SIGUSR1           |  terminate       |
+ *     |  SIGSEGV           |  coredump        |
+ *     |  SIGUSR2           |  terminate       |
+ *     |  SIGPIPE           |  terminate       |
+ *     |  SIGALRM           |  terminate       |
+ *     |  SIGTERM           |  terminate       |
+ *     |  SIGCHLD           |  ignore          |
+ *     |  SIGCONT           |  ignore(*)       |
+ *     |  SIGSTOP           |  stop(*)(+)      |
+ *     |  SIGTSTP           |  stop(*)         |
+ *     |  SIGTTIN           |  stop(*)         |
+ *     |  SIGTTOU           |  stop(*)         |
+ *     |  SIGURG            |  ignore          |
+ *     |  SIGXCPU           |  coredump        |
+ *     |  SIGXFSZ           |  coredump        |
+ *     |  SIGVTALRM         |  terminate       |
+ *     |  SIGPROF           |  terminate       |
+ *     |  SIGPOLL/SIGIO     |  terminate       |
+ *     |  SIGSYS/SIGUNUSED  |  coredump        |
+ *     |  SIGSTKFLT         |  terminate       |
+ *     |  SIGWINCH          |  ignore          |
+ *     |  SIGPWR            |  terminate       |
+ *     |  SIGRTMIN-SIGRTMAX |  terminate       |
+ *     +--------------------+------------------+
+ *     |  non-POSIX signal  |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGEMT            |  coredump        |
+ *     +--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)").  This happens regardless of blocking,
+ * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
+ */
+
+#ifdef SIGEMT
+#define SIGEMT_MASK    rt_sigmask(SIGEMT)
+#else
+#define SIGEMT_MASK    0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define rt_sigmask(sig)        (1ULL << ((sig)-1))
+#else
+#define rt_sigmask(sig)        sigmask(sig)
+#endif
+#define siginmask(sig, mask) (rt_sigmask(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+       rt_sigmask(SIGKILL)   |  rt_sigmask(SIGSTOP))
+
+#define SIG_KERNEL_STOP_MASK (\
+       rt_sigmask(SIGSTOP)   |  rt_sigmask(SIGTSTP)   | \
+       rt_sigmask(SIGTTIN)   |  rt_sigmask(SIGTTOU)   )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+        rt_sigmask(SIGQUIT)   |  rt_sigmask(SIGILL)    | \
+       rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGABRT)   | \
+        rt_sigmask(SIGFPE)    |  rt_sigmask(SIGSEGV)   | \
+       rt_sigmask(SIGBUS)    |  rt_sigmask(SIGSYS)    | \
+        rt_sigmask(SIGXCPU)   |  rt_sigmask(SIGXFSZ)   | \
+       SIGEMT_MASK                                    )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+        rt_sigmask(SIGCONT)   |  rt_sigmask(SIGCHLD)   | \
+       rt_sigmask(SIGWINCH)  |  rt_sigmask(SIGURG)    )
+
+#define sig_kernel_only(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
+
+#define sig_needs_tasklist(sig)        ((sig) == SIGCONT)
+
+#define sig_user_defined(t, signr) \
+       (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&  \
+        ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
+
+#define sig_fatal(t, signr) \
+       (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+        (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SIGNAL_H */
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
new file mode 100644 (file)
index 0000000..5104294
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  include/linux/signalfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_SIGNALFD_H
+#define _LINUX_SIGNALFD_H
+
+
+struct signalfd_siginfo {
+       __u32 signo;
+       __s32 err;
+       __s32 code;
+       __u32 pid;
+       __u32 uid;
+       __s32 fd;
+       __u32 tid;
+       __u32 band;
+       __u32 overrun;
+       __u32 trapno;
+       __s32 status;
+       __s32 svint;
+       __u64 svptr;
+       __u64 utime;
+       __u64 stime;
+       __u64 addr;
+
+       /*
+        * Pad strcture to 128 bytes. Remember to update the
+        * pad size when you add new memebers. We use a fixed
+        * size structure to avoid compatibility problems with
+        * future versions, and we leave extra space for additional
+        * members. We use fixed size members because this strcture
+        * comes out of a read(2) and we really don't want to have
+        * a compat on read(2).
+        */
+       __u8 __pad[48];
+};
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SIGNALFD
+
+/*
+ * Deliver the signal to listening signalfd. This must be called
+ * with the sighand lock held. Same are the following that end up
+ * calling signalfd_deliver().
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig);
+
+/*
+ * No need to fall inside signalfd_deliver() if no signal listeners
+ * are available.
+ */
+static inline void signalfd_notify(struct task_struct *tsk, int sig)
+{
+       if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+               signalfd_deliver(tsk, sig);
+}
+
+/*
+ * The signal -1 is used to notify the signalfd that the sighand
+ * is on its way to be detached.
+ */
+static inline void signalfd_detach_locked(struct task_struct *tsk)
+{
+       if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+               signalfd_deliver(tsk, -1);
+}
+
+static inline void signalfd_detach(struct task_struct *tsk)
+{
+       struct sighand_struct *sighand = tsk->sighand;
+
+       if (unlikely(!list_empty(&sighand->signalfd_list))) {
+               spin_lock_irq(&sighand->siglock);
+               signalfd_deliver(tsk, -1);
+               spin_unlock_irq(&sighand->siglock);
+       }
+}
+
+#else /* CONFIG_SIGNALFD */
+
+#define signalfd_deliver(t, s) do { } while (0)
+#define signalfd_notify(t, s) do { } while (0)
+#define signalfd_detach_locked(t) do { } while (0)
+#define signalfd_detach(t) do { } while (0)
+
+#endif /* CONFIG_SIGNALFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SIGNALFD_H */
+
index 7ba23ec8211b11f22edd21369f824d81b5a2ee52..3f70149eabbb2e7d40c91ce069cce466c3162615 100644 (file)
@@ -83,7 +83,6 @@ void smp_prepare_boot_cpu(void);
  *     These macros fold the SMP functionality into a single CPU system
  */
 #define raw_smp_processor_id()                 0
-#define hard_smp_processor_id()                        0
 static inline int up_smp_call_function(void)
 {
        return 0;
index f56d2473495004a6958b95fc5a07b54f28a5aba8..34d4b075f7b86013a3399a928dfe303147bbffba 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
 
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
index 35fa4d5aadd06e4685339abe13ff9986535645cf..4a7ae8ab6eb873e75aa2f14c59fc40332dd7da48 100644 (file)
@@ -396,4 +396,23 @@ char *                svc_print_addr(struct svc_rqst *, char *, size_t);
 
 #define        RPC_MAX_ADDRBUFLEN      (63U)
 
+/*
+ * When we want to reduce the size of the reserved space in the response
+ * buffer, we need to take into account the size of any checksum data that
+ * may be at the end of the packet. This is difficult to determine exactly
+ * for all cases without actually generating the checksum, so we just use a
+ * static value.
+ */
+static inline void
+svc_reserve_auth(struct svc_rqst *rqstp, int space)
+{
+       int                     added_space = 0;
+
+       switch(rqstp->rq_authop->flavour) {
+               case RPC_AUTH_GSS:
+                       added_space = RPC_MAX_AUTH_SIZE;
+       }
+       return svc_reserve(rqstp, space + added_space);
+}
+
 #endif /* SUNRPC_SVC_H */
index 7909687557bf70f29b4bf18f9021061933d72cad..e21dd93ac4b7c3a197f8b1d843d2afbddadc8ff0 100644 (file)
@@ -37,7 +37,8 @@ struct svc_sock {
 
        atomic_t                sk_reserved;    /* space on outq that is reserved */
 
-       spinlock_t              sk_defer_lock;  /* protects sk_deferred */
+       spinlock_t              sk_lock;        /* protects sk_deferred and
+                                                * sk_info_authunix */
        struct list_head        sk_deferred;    /* deferred requests that need to
                                                 * be revisted */
        struct mutex            sk_mutex;       /* to serialize sending data */
index 9d2aa1a12aa02803ab109297b7dd2da00cfd4a62..9c7cb643066660e36ccef3c44eecde72d1e453a0 100644 (file)
@@ -32,18 +32,51 @@ static inline int pm_prepare_console(void) { return 0; }
 static inline void pm_restore_console(void) {}
 #endif
 
+/**
+ * struct hibernation_ops - hibernation platform support
+ *
+ * The methods in this structure allow a platform to override the default
+ * mechanism of shutting down the machine during a hibernation transition.
+ *
+ * All three methods must be assigned.
+ *
+ * @prepare: prepare system for hibernation
+ * @enter: shut down system after state has been saved to disk
+ * @finish: finish/clean up after state has been reloaded
+ */
+struct hibernation_ops {
+       int (*prepare)(void);
+       int (*enter)(void);
+       void (*finish)(void);
+};
+
 #if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
 /* kernel/power/snapshot.c */
-extern void __init register_nosave_region(unsigned long, unsigned long);
+extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
+static inline void register_nosave_region(unsigned long b, unsigned long e)
+{
+       __register_nosave_region(b, e, 0);
+}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e)
+{
+       __register_nosave_region(b, e, 1);
+}
 extern int swsusp_page_is_forbidden(struct page *);
 extern void swsusp_set_page_free(struct page *);
 extern void swsusp_unset_page_free(struct page *);
 extern unsigned long get_safe_page(gfp_t gfp_mask);
+
+extern void hibernation_set_ops(struct hibernation_ops *ops);
+extern int hibernate(void);
 #else
 static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
 static inline void swsusp_set_page_free(struct page *p) {}
 static inline void swsusp_unset_page_free(struct page *p) {}
+
+static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
+static inline int hibernate(void) { return -ENOSYS; }
 #endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
 
 void save_processor_state(void);
index e1cc552e04fea57c445682440fee6185122c67a5..13ad0b82ac286a37355a321928cbcd7dd5f31944 100644 (file)
@@ -113,6 +113,8 @@ void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect);
 void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit);
 void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor);
 int svga_get_tilemax(struct fb_info *info);
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+                  struct fb_var_screeninfo *var);
 
 int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node);
 int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node);
index c8b042667af1fb70e1326bbec1c0b7b8474017f5..5562fbf72095cf5ba3b3688f8aebbc6cb983f85c 100644 (file)
@@ -291,4 +291,28 @@ struct gpio_desc {
 #define MGSL_IOCGGPIO          _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc)
 #define MGSL_IOCWAITGPIO       _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc)
 
+#ifdef __KERNEL__
+/* provide 32 bit ioctl compatibility on 64 bit systems */
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+struct MGSL_PARAMS32 {
+       compat_ulong_t  mode;
+       unsigned char   loopback;
+       unsigned short  flags;
+       unsigned char   encoding;
+       compat_ulong_t  clock_speed;
+       unsigned char   addr_filter;
+       unsigned short  crc_type;
+       unsigned char   preamble_length;
+       unsigned char   preamble;
+       compat_ulong_t  data_rate;
+       unsigned char   data_bits;
+       unsigned char   stop_bits;
+       unsigned char   parity;
+};
+#define MGSL_IOCSPARAMS32 _IOW(MGSL_MAGIC_IOC,0,struct MGSL_PARAMS32)
+#define MGSL_IOCGPARAMS32 _IOR(MGSL_MAGIC_IOC,1,struct MGSL_PARAMS32)
+#endif
+#endif
+
 #endif /* _SYNCLINK_H_ */
index 1912c6cbef553cd1d05795c223df8f8e4425af16..b02070eac422a31371b852cc50ade987b56e7660 100644 (file)
@@ -576,6 +576,8 @@ asmlinkage long sys_fstatat64(int dfd, char __user *filename,
                               struct stat64 __user *statbuf, int flag);
 asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf,
                               int bufsiz);
+asmlinkage long sys_utimensat(int dfd, char __user *filename,
+                               struct timespec __user *utimes, int flags);
 asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename,
                                     struct compat_timeval __user *t);
 asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
@@ -602,6 +604,10 @@ asmlinkage long sys_get_robust_list(int pid,
 asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
                                    size_t len);
 asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+                           const struct itimerspec __user *utmr);
+asmlinkage long sys_eventfd(unsigned int count);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
index df2a319106b2bd82e1518fdbf307d97bb96c8ed5..1218733ec6b58c27ea894f13a7b61f2f7f9d1623 100644 (file)
@@ -10,11 +10,29 @@ static inline void task_io_account_read(size_t bytes)
        current->ioac.read_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+       return p->ioac.read_bytes >> 9;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
        current->ioac.write_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+       return p->ioac.write_bytes >> 9;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
        current->ioac.cancelled_write_bytes += bytes;
@@ -31,10 +49,20 @@ static inline void task_io_account_read(size_t bytes)
 {
 }
 
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+       return 0;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
 }
 
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+       return 0;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
 }
index 2a196982601f8b6647d2137a1e97df2a94c2bd91..6b3a31805c72ff2e5d450697e15afc5e507d2599 100644 (file)
@@ -63,6 +63,7 @@ enum {
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
+#define TIFM_CTRL_POWER_MASK      0x00000007
 
 #define TIFM_SOCK_STATE_OCCUPIED  0x00000008
 #define TIFM_SOCK_STATE_POWERED   0x00000080
diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h
new file mode 100644 (file)
index 0000000..cf2b10d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ *  include/linux/timerfd.h
+ *
+ *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_TIMERFD_H
+#define _LINUX_TIMERFD_H
+
+
+#define TFD_TIMER_ABSTIME (1 << 0)
+
+
+
+#endif /* _LINUX_TIMERFD_H */
+
index 659487e3ebeb0c99fcb60526b41cf90a1712877a..85c95cd39bc30faeede4c57fe083d6e943cecfa9 100644 (file)
  *     This routine allows the tty driver to implement
  *     device-specific ioctl's.  If the ioctl number passed in cmd
  *     is not recognized by the driver, it should return ENOIOCTLCMD.
+ *
+ * long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+ *                     unsigned int cmd, unsigned long arg);
+ *
+ *     implement ioctl processing for 32 bit process on 64 bit system
  * 
  * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
  *
@@ -132,6 +137,8 @@ struct tty_operations {
        int  (*chars_in_buffer)(struct tty_struct *tty);
        int  (*ioctl)(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg);
+       long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+                            unsigned int cmd, unsigned long arg);
        void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
        void (*throttle)(struct tty_struct * tty);
        void (*unthrottle)(struct tty_struct * tty);
@@ -193,6 +200,8 @@ struct tty_driver {
        int  (*chars_in_buffer)(struct tty_struct *tty);
        int  (*ioctl)(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg);
+       long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+                            unsigned int cmd, unsigned long arg);
        void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
        void (*throttle)(struct tty_struct * tty);
        void (*unthrottle)(struct tty_struct * tty);
index d75932e2771094c7066667a0c6357eb079f480b5..6226504d91080bd10b9eb91e7a6adf4cbc3ab579 100644 (file)
  *     low-level driver can "grab" an ioctl request before the line
  *     discpline has a chance to see it.
  * 
+ * long        (*compat_ioctl)(struct tty_struct * tty, struct file * file,
+ *                     unsigned int cmd, unsigned long arg);
+ *
+ *      Process ioctl calls from 32-bit process on 64-bit system
+ *
  * void        (*set_termios)(struct tty_struct *tty, struct ktermios * old);
  *
  *     This function notifies the line discpline that a change has
@@ -118,6 +123,8 @@ struct tty_ldisc {
                         const unsigned char * buf, size_t nr); 
        int     (*ioctl)(struct tty_struct * tty, struct file * file,
                         unsigned int cmd, unsigned long arg);
+       long    (*compat_ioctl)(struct tty_struct * tty, struct file * file,
+                               unsigned int cmd, unsigned long arg);
        void    (*set_termios)(struct tty_struct *tty, struct ktermios * old);
        unsigned int (*poll)(struct tty_struct *, struct file *,
                             struct poll_table_struct *);
index cfbd2bb8fa2c495d33bc4de0fcbd8338115f83f6..94bd38a6d947be480281f3a8e4de4edff7f03c84 100644 (file)
@@ -126,7 +126,7 @@ enum usb_interface_condition {
  * Each interface may have alternate settings.  The initial configuration
  * of a device sets altsetting 0, but the device driver can change
  * that setting using usb_set_interface().  Alternate settings are often
- * used to control the the use of periodic endpoints, such as by having
+ * used to control the use of periodic endpoints, such as by having
  * different endpoints use different amounts of reserved USB bandwidth.
  * All standards-conformant USB devices that use isochronous endpoints
  * will use them in non-default settings.
index acb1f105870c9f4f2535259d46bfa9371ab1a612..d9325cf8a1342476c3989e791167d86f54a418e7 100644 (file)
@@ -212,8 +212,6 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
 void refresh_cpu_vm_stats(int);
-void refresh_vm_stats(void);
-
 #else /* CONFIG_SMP */
 
 /*
@@ -260,7 +258,6 @@ static inline void __dec_zone_page_state(struct page *page,
 #define mod_zone_page_state __mod_zone_page_state
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
-static inline void refresh_vm_stats(void) { }
 #endif
 
 #endif /* _LINUX_VMSTAT_H */
index f16ba1e0687d8d14e8e1ecd345e4d7648f8920d3..d555f31c0746a31a50f376ca41ed2cbcf48742fe 100644 (file)
@@ -24,15 +24,13 @@ typedef void (*work_func_t)(struct work_struct *work);
 struct work_struct {
        atomic_long_t data;
 #define WORK_STRUCT_PENDING 0          /* T if work item pending execution */
-#define WORK_STRUCT_NOAUTOREL 1                /* F if work item automatically released on exec */
 #define WORK_STRUCT_FLAG_MASK (3UL)
 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
        struct list_head entry;
        work_func_t func;
 };
 
-#define WORK_DATA_INIT(autorelease) \
-       ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL)
+#define WORK_DATA_INIT()       ATOMIC_LONG_INIT(0)
 
 struct delayed_work {
        struct work_struct work;
@@ -44,14 +42,8 @@ struct execute_work {
 };
 
 #define __WORK_INITIALIZER(n, f) {                             \
-       .data = WORK_DATA_INIT(0),                              \
-        .entry = { &(n).entry, &(n).entry },                   \
-       .func = (f),                                            \
-       }
-
-#define __WORK_INITIALIZER_NAR(n, f) {                         \
-       .data = WORK_DATA_INIT(1),                              \
-        .entry = { &(n).entry, &(n).entry },                   \
+       .data = WORK_DATA_INIT(),                               \
+       .entry  = { &(n).entry, &(n).entry },                   \
        .func = (f),                                            \
        }
 
@@ -60,23 +52,12 @@ struct execute_work {
        .timer = TIMER_INITIALIZER(NULL, 0, 0),                 \
        }
 
-#define __DELAYED_WORK_INITIALIZER_NAR(n, f) {                 \
-       .work = __WORK_INITIALIZER_NAR((n).work, (f)),          \
-       .timer = TIMER_INITIALIZER(NULL, 0, 0),                 \
-       }
-
 #define DECLARE_WORK(n, f)                                     \
        struct work_struct n = __WORK_INITIALIZER(n, f)
 
-#define DECLARE_WORK_NAR(n, f)                                 \
-       struct work_struct n = __WORK_INITIALIZER_NAR(n, f)
-
 #define DECLARE_DELAYED_WORK(n, f)                             \
        struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
 
-#define DECLARE_DELAYED_WORK_NAR(n, f)                 \
-       struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f)
-
 /*
  * initialize a work item's function pointer
  */
@@ -95,16 +76,9 @@ struct execute_work {
  * assignment of the work data initializer allows the compiler
  * to generate better code.
  */
-#define INIT_WORK(_work, _func)                                        \
-       do {                                                    \
-               (_work)->data = (atomic_long_t) WORK_DATA_INIT(0);      \
-               INIT_LIST_HEAD(&(_work)->entry);                \
-               PREPARE_WORK((_work), (_func));                 \
-       } while (0)
-
-#define INIT_WORK_NAR(_work, _func)                                    \
+#define INIT_WORK(_work, _func)                                                \
        do {                                                            \
-               (_work)->data = (atomic_long_t) WORK_DATA_INIT(1);      \
+               (_work)->data = (atomic_long_t) WORK_DATA_INIT();       \
                INIT_LIST_HEAD(&(_work)->entry);                        \
                PREPARE_WORK((_work), (_func));                         \
        } while (0)
@@ -115,12 +89,6 @@ struct execute_work {
                init_timer(&(_work)->timer);                    \
        } while (0)
 
-#define INIT_DELAYED_WORK_NAR(_work, _func)                    \
-       do {                                                    \
-               INIT_WORK_NAR(&(_work)->work, (_func));         \
-               init_timer(&(_work)->timer);                    \
-       } while (0)
-
 #define INIT_DELAYED_WORK_DEFERRABLE(_work, _func)                     \
        do {                                                    \
                INIT_WORK(&(_work)->work, (_func));             \
@@ -143,24 +111,10 @@ struct execute_work {
        work_pending(&(w)->work)
 
 /**
- * work_release - Release a work item under execution
- * @work: The work item to release
- *
- * This is used to release a work item that has been initialised with automatic
- * release mode disabled (WORK_STRUCT_NOAUTOREL is set).  This gives the work
- * function the opportunity to grab auxiliary data from the container of the
- * work_struct before clearing the pending bit as the work_struct may be
- * subject to deallocation the moment the pending bit is cleared.
- *
- * In such a case, this should be called in the work function after it has
- * fetched any data it may require from the containter of the work_struct.
- * After this function has been called, the work_struct may be scheduled for
- * further execution or it may be deallocated unless other precautions are
- * taken.
- *
- * This should also be used to release a delayed work item.
+ * work_clear_pending - for internal use only, mark a work item as not pending
+ * @work: The work item in question
  */
-#define work_release(work) \
+#define work_clear_pending(work) \
        clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
 
 
@@ -174,27 +128,28 @@ extern struct workqueue_struct *__create_workqueue(const char *name,
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
 extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
-extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay));
+extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq,
+                       struct delayed_work *work, unsigned long delay));
 extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
-       struct delayed_work *work, unsigned long delay);
+                       struct delayed_work *work, unsigned long delay);
+
 extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq));
+extern void flush_scheduled_work(void);
 
 extern int FASTCALL(schedule_work(struct work_struct *work));
-extern int FASTCALL(run_scheduled_work(struct work_struct *work));
-extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay));
-
-extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay);
+extern int FASTCALL(schedule_delayed_work(struct delayed_work *work,
+                                       unsigned long delay));
+extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
+                                       unsigned long delay);
 extern int schedule_on_each_cpu(work_func_t func);
-extern void flush_scheduled_work(void);
 extern int current_is_keventd(void);
 extern int keventd_up(void);
 
 extern void init_workqueues(void);
-void cancel_rearming_delayed_work(struct delayed_work *work);
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *,
-                                      struct delayed_work *);
 int execute_in_process_context(work_func_t fn, struct execute_work *);
 
+extern void cancel_work_sync(struct work_struct *work);
+
 /*
  * Kill off a pending schedule_delayed_work().  Note that the work callback
  * function may still be running on return from cancel_delayed_work(), unless
@@ -207,8 +162,18 @@ static inline int cancel_delayed_work(struct delayed_work *work)
 
        ret = del_timer(&work->timer);
        if (ret)
-               work_release(&work->work);
+               work_clear_pending(&work->work);
        return ret;
 }
 
+extern void cancel_rearming_delayed_work(struct delayed_work *work);
+
+/* Obsolete. use cancel_rearming_delayed_work() */
+static inline
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+                                       struct delayed_work *work)
+{
+       cancel_rearming_delayed_work(work);
+}
+
 #endif
index daa6c125f66e937e26884aeaeabab2b4525f72c0..050915b59576670edc708076b002033074c2605f 100644 (file)
@@ -111,9 +111,15 @@ balance_dirty_pages_ratelimited(struct address_space *mapping)
        balance_dirty_pages_ratelimited_nr(mapping, 1);
 }
 
+typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
+                               void *data);
+
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-extern int generic_writepages(struct address_space *mapping,
-                             struct writeback_control *wbc);
+int generic_writepages(struct address_space *mapping,
+                      struct writeback_control *wbc);
+int write_cache_pages(struct address_space *mapping,
+                     struct writeback_control *wbc, writepage_t writepage,
+                     void *data);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 int sync_page_range(struct inode *inode, struct address_space *mapping,
                        loff_t pos, loff_t count);
index d56b2923d61a1cf2093229309f47ef03ae3d98f4..bbd85cd61ed5d57482ed0180998f808414078054 100644 (file)
@@ -1291,6 +1291,8 @@ extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
 extern const struct ieee80211_channel *ieee80211_get_channel(struct
                                                             ieee80211_device
                                                             *ieee, u8 channel);
+extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
+                                     u8 channel);
 
 /* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
index 7a209f61c48259550a0a163e8f42b1df993598c9..0df574931522d852269946e80865cad5913778eb 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index 89fe534045f1c61f8cd6c3bad1e7905911f57d7e..36bee441aa56cec008017badcdb235487f947cd8 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index 2007c5a0a43f8d9d25f409c0d121ff4952d70eec..fcc896491a95396209e36429b3ab87778c50487d 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 4ca3d2071b0392da937b077ba0b361a12817d844..89747f06d9ebc9dc17645b2ecda220c601c273d4 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index c41196b879556fa2ccd5d73917b75cb599f27d47..83f78081799c2365b3e2039a9a82f46038afe322 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index 736dabe211e34ff8d57ca157f05ff6cfd8ad36fb..fa8455eda28068df1f41f81cf65b4509c4d61af4 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 9592c374b41d536e182930ff6f16f7a70d71a813..73cacb3ac16cae48a2e494ec10874bb8258b44db 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 9a9b3619d305a03eaa8c2f343e4f5202e493d5a4..0062347600b9d7796cc969c20651e7115009fed1 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index b9baac9eb8b676e585139d95132ee5b4cefb441e..6d9539f05806a63efc03757bcadca6b496c59ae8 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 1720539ac2c1b0270e1358e6a6541e34dc709005..a5a2539485bddf24bd7d43eea82b56fe93e39237 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index ca51d5b7c999871e8acbd222f8ee15e74c4f9d28..92f3b0e1029b4314c113732702b53508a7bbb09a 100644 (file)
@@ -16,7 +16,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index e77eb88d9226b5e991047f3e97f54e02e24a94d5..f0248fb8e196f0c5b4cd669cefe34f536d374bf9 100644 (file)
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index e212b9bc2503d64439cd70c3ffa4d080d15751dd..3ffc1d0f93d6ac40178911208e07279f20f7ece3 100644 (file)
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 03c6f81a502a267b5ce1c034688e8f7632ecfedb..e03ae4ae3963fa112606e8f372fa0a4083e40bbb 100644 (file)
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index c463f8bca85601ec457a4bdb1991c7fcb8738efe..1906eb71422e2d401abaeb0c0310ba2db15a5699 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 72b446c1e22c805bbf0ff8d6ed27f02b478a430b..86f0dbb8ee5d1ae69b5373515b871fbcf0c5b43b 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charg.
  *     
index 335b0ace96659e14d54363311ebf47d510961574..37f512bd673321e2fb0eed0bd8ce2653cfe7b850 100644 (file)
@@ -21,7 +21,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *     
index a899e5837be84525771fae96fcaba8d66368ea49..cf80c1af5854a4d7c9351bb8922fd3892884a887 100644 (file)
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 3a605d37ddbf0c820437a582fb4c16d71827a8fe..c0d938847bd3ba8fbd2e3d0b163074e25977a64b 100644 (file)
@@ -26,7 +26,7 @@
  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  *     MA 02111-1307 USA
  *
- *     Michel Dänzer <daenzer@debian.org>, 10/2001
+ *     Michel Dänzer <daenzer@debian.org>, 10/2001
  *     - simplify irda_pv_t to avoid endianness issues
  *     
  ********************************************************************/
index cb61568547d1328e8d59daf26920bea600a20013..cb2615ccf761d68123406d3600646d147a6e2f47 100644 (file)
@@ -18,7 +18,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 98768b3f9e313c5132befcf931dc713b7f682558..2942ad6ab932eb5e0f0fbbd8395803175b4592aa 100644 (file)
@@ -17,7 +17,7 @@
  *     published by the Free Software Foundation; either version 2 of 
  *     the License, or (at your option) any later version.
  *
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
  *     provide warranty for any of this software. This material is 
  *     provided "AS-IS" and at no charge.
  *
index 1c6b8bd09b9a2a5fd7bea34fc26e7ff78ec4f02e..4732432f8eb0942fe90f11dea289344958c2b9a3 100644 (file)
@@ -183,13 +183,6 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct);
 
 extern void nf_conntrack_flush(void);
 
-extern struct nf_conntrack_helper *
-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
-extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
-
-extern struct nf_conntrack_helper *
-__nf_conntrack_helper_find_byname(const char *name);
-
 extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
                                const struct nf_conntrack_tuple *orig);
 
index f32f714e5d9269f123be866e9ad1b6a212c512b5..96a58d8e1d3f8011226862e8ae765b90683c7ace 100644 (file)
@@ -56,9 +56,6 @@ struct nf_conntrack_l3proto
         */
        int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
 
-       /* Called when a conntrack entry is destroyed */
-       void (*destroy)(struct nf_conn *conntrack);
-
        /*
         * Called before tracking. 
         *      *dataoff: offset of protocol header (TCP, UDP,...) in *pskb
index e76565459ad9ef80a50a3bb262fd5a46f4939dad..f9743187d57fde824805695278254df47f1b8623 100644 (file)
@@ -10,16 +10,11 @@ extern int nf_nat_rule_find(struct sk_buff **pskb,
                            unsigned int hooknum,
                            const struct net_device *in,
                            const struct net_device *out,
-                           struct nf_conn *ct,
-                           struct nf_nat_info *info);
+                           struct nf_conn *ct);
 
 extern unsigned int
-alloc_null_binding(struct nf_conn *ct,
-                  struct nf_nat_info *info,
-                  unsigned int hooknum);
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
 
 extern unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
-                            struct nf_nat_info *info,
-                            unsigned int hooknum);
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum);
 #endif /* _NF_NAT_RULE_H */
index 98755ebaf163cfe788b4117167cfeaf1a861f269..496f89d45c8b89eabf7b57bde71016e85552a677 100644 (file)
@@ -119,9 +119,16 @@ static inline void udp_lib_close(struct sock *sk, long timeout)
 }
 
 
+struct udp_get_port_ops {
+       int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2);
+       int (*saddr_any)(const struct sock *sk);
+       unsigned int (*hash_port_and_rcv_saddr)(__u16 port,
+                                               const struct sock *sk);
+};
+
 /* net/ipv4/udp.c */
 extern int     udp_get_port(struct sock *sk, unsigned short snum,
-                            int (*saddr_cmp)(const struct sock *, const struct sock *));
+                            const struct udp_get_port_ops *ops);
 extern void    udp_err(struct sk_buff *, u32);
 
 extern int     udp_sendmsg(struct kiocb *iocb, struct sock *sk,
index 635b0eafca95d256e789edb0323cbb8aef759f4f..50b4b424d1caab47e79673eb3fa6972c45651e91 100644 (file)
@@ -120,5 +120,5 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb)
 
 extern void    udplite4_register(void);
 extern int     udplite_get_port(struct sock *sk, unsigned short snum,
-                       int (*scmp)(const struct sock *, const struct sock *));
+                                const struct udp_get_port_ops *ops);
 #endif /* _UDPLITE_H */
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
new file mode 100644 (file)
index 0000000..b3a36f7
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef IB_UMEM_H
+#define IB_UMEM_H
+
+#include <linux/list.h>
+#include <linux/scatterlist.h>
+
+struct ib_ucontext;
+
+struct ib_umem {
+       struct ib_ucontext     *context;
+       size_t                  length;
+       int                     offset;
+       int                     page_size;
+       int                     writable;
+       struct list_head        chunk_list;
+       struct work_struct      work;
+       struct mm_struct       *mm;
+       unsigned long           diff;
+};
+
+struct ib_umem_chunk {
+       struct list_head        list;
+       int                     nents;
+       int                     nmap;
+       struct scatterlist      page_list[0];
+};
+
+#ifdef CONFIG_INFINIBAND_USER_MEM
+
+struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
+                           size_t size, int access);
+void ib_umem_release(struct ib_umem *umem);
+int ib_umem_page_count(struct ib_umem *umem);
+
+#else /* CONFIG_INFINIBAND_USER_MEM */
+
+#include <linux/err.h>
+
+static inline struct ib_umem *ib_umem_get(struct ib_ucontext *context,
+                                         unsigned long addr, size_t size,
+                                         int access) {
+       return ERR_PTR(-EINVAL);
+}
+static inline void ib_umem_release(struct ib_umem *umem) { }
+static inline int ib_umem_page_count(struct ib_umem *umem) { return 0; }
+
+#endif /* CONFIG_INFINIBAND_USER_MEM */
+
+#endif /* IB_UMEM_H */
index 5342ac64ed1a786147a34546970234f57c2e1868..47cefca59c899819cf181582cf9df4fde4bbc872 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
+ * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -710,6 +710,7 @@ struct ib_ucontext {
        struct list_head        qp_list;
        struct list_head        srq_list;
        struct list_head        ah_list;
+       int                     closing;
 };
 
 struct ib_uobject {
@@ -723,23 +724,6 @@ struct ib_uobject {
        int                     live;
 };
 
-struct ib_umem {
-       unsigned long           user_base;
-       unsigned long           virt_base;
-       size_t                  length;
-       int                     offset;
-       int                     page_size;
-       int                     writable;
-       struct list_head        chunk_list;
-};
-
-struct ib_umem_chunk {
-       struct list_head        list;
-       int                     nents;
-       int                     nmap;
-       struct scatterlist      page_list[0];
-};
-
 struct ib_udata {
        void __user *inbuf;
        void __user *outbuf;
@@ -752,11 +736,6 @@ struct ib_udata {
         ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] -        \
          (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
 
-struct ib_umem_object {
-       struct ib_uobject       uobject;
-       struct ib_umem          umem;
-};
-
 struct ib_pd {
        struct ib_device       *device;
        struct ib_uobject      *uobject;
@@ -1003,7 +982,8 @@ struct ib_device {
                                                  int mr_access_flags,
                                                  u64 *iova_start);
        struct ib_mr *             (*reg_user_mr)(struct ib_pd *pd,
-                                                 struct ib_umem *region,
+                                                 u64 start, u64 length,
+                                                 u64 virt_addr,
                                                  int mr_access_flags,
                                                  struct ib_udata *udata);
        int                        (*query_mr)(struct ib_mr *mr,
index ad0182ef7809bba62450e4788dfb658fd601ce8d..2e6bdc4e7a0ae1deb116b7d9e96e8e29bbf05b99 100644 (file)
@@ -314,8 +314,7 @@ struct scsi_core {
        struct list_head  task_queue;
        int               task_queue_size;
 
-       struct semaphore  queue_thread_sema;
-       int               queue_thread_kill;
+       struct task_struct *queue_thread;
 };
 
 struct sas_ha_event {
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
new file mode 100644 (file)
index 0000000..4eea637
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  Header file for AT91/AT32 LCD Controller
+ *
+ *  Data structure and register user interface
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * 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
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+ /* LCD Controller info data structure */
+struct atmel_lcdfb_info {
+       spinlock_t              lock;
+       struct fb_info          *info;
+       void __iomem            *mmio;
+       unsigned long           irq_base;
+
+       unsigned int            guard_time;
+       struct platform_device  *pdev;
+       struct clk              *bus_clk;
+       struct clk              *lcdc_clk;
+       unsigned int            default_bpp;
+       unsigned int            default_lcdcon2;
+       unsigned int            default_dmacon;
+       void (*atmel_lcdfb_power_control)(int on);
+       struct fb_monspecs      *default_monspecs;
+       u32                     pseudo_palette[16];
+};
+
+#define ATMEL_LCDC_DMABADDR1   0x00
+#define ATMEL_LCDC_DMABADDR2   0x04
+#define ATMEL_LCDC_DMAFRMPT1   0x08
+#define ATMEL_LCDC_DMAFRMPT2   0x0c
+#define ATMEL_LCDC_DMAFRMADD1  0x10
+#define ATMEL_LCDC_DMAFRMADD2  0x14
+
+#define ATMEL_LCDC_DMAFRMCFG   0x18
+#define        ATMEL_LCDC_FRSIZE       (0x7fffff <<  0)
+#define        ATMEL_LCDC_BLENGTH_OFFSET       24
+#define        ATMEL_LCDC_BLENGTH      (0x7f     << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON      0x1c
+#define        ATMEL_LCDC_DMAEN        (0x1 << 0)
+#define        ATMEL_LCDC_DMARST       (0x1 << 1)
+#define        ATMEL_LCDC_DMABUSY      (0x1 << 2)
+#define                ATMEL_LCDC_DMAUPDT      (0x1 << 3)
+#define                ATMEL_LCDC_DMA2DEN      (0x1 << 4)
+
+#define ATMEL_LCDC_DMA2DCFG    0x20
+#define                ATMEL_LCDC_ADDRINC_OFFSET       0
+#define                ATMEL_LCDC_ADDRINC              (0xffff)
+#define                ATMEL_LCDC_PIXELOFF_OFFSET      24
+#define                ATMEL_LCDC_PIXELOFF             (0x1f << 24)
+
+#define ATMEL_LCDC_LCDCON1     0x0800
+#define        ATMEL_LCDC_BYPASS       (1     <<  0)
+#define        ATMEL_LCDC_CLKVAL_OFFSET        12
+#define        ATMEL_LCDC_CLKVAL       (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define        ATMEL_LCDC_LINCNT       (0x7ff << 21)
+
+#define ATMEL_LCDC_LCDCON2     0x0804
+#define        ATMEL_LCDC_DISTYPE      (3 << 0)
+#define                ATMEL_LCDC_DISTYPE_STNMONO      (0 << 0)
+#define                ATMEL_LCDC_DISTYPE_STNCOLOR     (1 << 0)
+#define                ATMEL_LCDC_DISTYPE_TFT          (2 << 0)
+#define        ATMEL_LCDC_SCANMOD      (1 << 2)
+#define                ATMEL_LCDC_SCANMOD_SINGLE       (0 << 2)
+#define                ATMEL_LCDC_SCANMOD_DUAL         (1 << 2)
+#define        ATMEL_LCDC_IFWIDTH      (3 << 3)
+#define                ATMEL_LCDC_IFWIDTH_4            (0 << 3)
+#define                ATMEL_LCDC_IFWIDTH_8            (1 << 3)
+#define                ATMEL_LCDC_IFWIDTH_16           (2 << 3)
+#define        ATMEL_LCDC_PIXELSIZE    (7 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_1          (0 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_2          (1 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_4          (2 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_8          (3 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_16         (4 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_24         (5 << 5)
+#define                ATMEL_LCDC_PIXELSIZE_32         (6 << 5)
+#define        ATMEL_LCDC_INVVD        (1 << 8)
+#define                ATMEL_LCDC_INVVD_NORMAL         (0 << 8)
+#define                ATMEL_LCDC_INVVD_INVERTED       (1 << 8)
+#define        ATMEL_LCDC_INVFRAME     (1 << 9 )
+#define                ATMEL_LCDC_INVFRAME_NORMAL      (0 << 9)
+#define                ATMEL_LCDC_INVFRAME_INVERTED    (1 << 9)
+#define        ATMEL_LCDC_INVLINE      (1 << 10)
+#define                ATMEL_LCDC_INVLINE_NORMAL       (0 << 10)
+#define                ATMEL_LCDC_INVLINE_INVERTED     (1 << 10)
+#define        ATMEL_LCDC_INVCLK       (1 << 11)
+#define                ATMEL_LCDC_INVCLK_NORMAL        (0 << 11)
+#define                ATMEL_LCDC_INVCLK_INVERTED      (1 << 11)
+#define        ATMEL_LCDC_INVDVAL      (1 << 12)
+#define                ATMEL_LCDC_INVDVAL_NORMAL       (0 << 12)
+#define                ATMEL_LCDC_INVDVAL_INVERTED     (1 << 12)
+#define        ATMEL_LCDC_CLKMOD       (1 << 15)
+#define                ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15)
+#define                ATMEL_LCDC_CLKMOD_ALWAYSACTIVE  (1 << 15)
+#define        ATMEL_LCDC_MEMOR        (1 << 31)
+#define                ATMEL_LCDC_MEMOR_BIG            (0 << 31)
+#define                ATMEL_LCDC_MEMOR_LITTLE         (1 << 31)
+
+#define ATMEL_LCDC_TIM1                0x0808
+#define        ATMEL_LCDC_VFP          (0xff <<  0)
+#define        ATMEL_LCDC_VBP_OFFSET           8
+#define        ATMEL_LCDC_VBP          (0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define        ATMEL_LCDC_VPW_OFFSET           16
+#define        ATMEL_LCDC_VPW          (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define        ATMEL_LCDC_VHDLY_OFFSET         24
+#define        ATMEL_LCDC_VHDLY        (0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2                0x080c
+#define        ATMEL_LCDC_HBP          (0xff  <<  0)
+#define        ATMEL_LCDC_HPW_OFFSET           8
+#define        ATMEL_LCDC_HPW          (0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define        ATMEL_LCDC_HFP_OFFSET           21
+#define        ATMEL_LCDC_HFP          (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG   0x0810
+#define        ATMEL_LCDC_LINEVAL      (0x7ff <<  0)
+#define        ATMEL_LCDC_HOZVAL_OFFSET        21
+#define        ATMEL_LCDC_HOZVAL       (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO                0x0814
+#define        ATMEL_LCDC_FIFOTH       (0xffff)
+
+#define ATMEL_LCDC_MVAL                0x0818
+
+#define ATMEL_LCDC_DP1_2       0x081c
+#define ATMEL_LCDC_DP4_7       0x0820
+#define ATMEL_LCDC_DP3_5       0x0824
+#define ATMEL_LCDC_DP2_3       0x0828
+#define ATMEL_LCDC_DP5_7       0x082c
+#define ATMEL_LCDC_DP3_4       0x0830
+#define ATMEL_LCDC_DP4_5       0x0834
+#define ATMEL_LCDC_DP6_7       0x0838
+#define        ATMEL_LCDC_DP1_2_VAL    (0xff)
+#define        ATMEL_LCDC_DP4_7_VAL    (0xfffffff)
+#define        ATMEL_LCDC_DP3_5_VAL    (0xfffff)
+#define        ATMEL_LCDC_DP2_3_VAL    (0xfff)
+#define        ATMEL_LCDC_DP5_7_VAL    (0xfffffff)
+#define        ATMEL_LCDC_DP3_4_VAL    (0xffff)
+#define        ATMEL_LCDC_DP4_5_VAL    (0xfffff)
+#define        ATMEL_LCDC_DP6_7_VAL    (0xfffffff)
+
+#define ATMEL_LCDC_PWRCON      0x083c
+#define        ATMEL_LCDC_PWR          (1    <<  0)
+#define        ATMEL_LCDC_GUARDT_OFFSET        1
+#define        ATMEL_LCDC_GUARDT       (0x7f <<  ATMEL_LCDC_GUARDT_OFFSET)
+#define        ATMEL_LCDC_BUSY         (1    << 31)
+
+#define ATMEL_LCDC_CONTRAST_CTR        0x0840
+#define        ATMEL_LCDC_PS           (3 << 0)
+#define                ATMEL_LCDC_PS_DIV1              (0 << 0)
+#define                ATMEL_LCDC_PS_DIV2              (1 << 0)
+#define                ATMEL_LCDC_PS_DIV4              (2 << 0)
+#define                ATMEL_LCDC_PS_DIV8              (3 << 0)
+#define        ATMEL_LCDC_POL          (1 << 2)
+#define                ATMEL_LCDC_POL_NEGATIVE         (0 << 2)
+#define                ATMEL_LCDC_POL_POSITIVE         (1 << 2)
+#define        ATMEL_LCDC_ENA          (1 << 3)
+#define                ATMEL_LCDC_ENA_PWMDISABLE       (0 << 3)
+#define                ATMEL_LCDC_ENA_PWMENABLE        (1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL        0x0844
+#define        ATMEL_LCDC_CVAL (0xff)
+
+#define ATMEL_LCDC_IER         0x0848
+#define ATMEL_LCDC_IDR         0x084c
+#define ATMEL_LCDC_IMR         0x0850
+#define ATMEL_LCDC_ISR         0x0854
+#define ATMEL_LCDC_ICR         0x0858
+#define        ATMEL_LCDC_LNI          (1 << 0)
+#define        ATMEL_LCDC_LSTLNI       (1 << 1)
+#define        ATMEL_LCDC_EOFI         (1 << 2)
+#define        ATMEL_LCDC_UFLWI        (1 << 4)
+#define        ATMEL_LCDC_OWRI         (1 << 5)
+#define        ATMEL_LCDC_MERI         (1 << 6)
+
+#define ATMEL_LCDC_LUT(n)      (0x0c00 + ((n)*4))
+
+#endif /* __ATMEL_LCDC_H__ */
index 94c7d2da90eae37d8601b8f6b07e17382ab8b309..d52e45a1e9b898bde2a98c21c06173d87d1282aa 100644 (file)
@@ -7,9 +7,6 @@
  *  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.
- *
- *  $Header: /cvsroot/linux/drivers/video/pm3fb.h,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
  */
 
 #ifndef PM3FB_H
 /* ***** pm3fb useful define and macro ***** */
 /* ***************************************** */
 
-/* permedia3 -specific definitions */
-#define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
-
-/* in case it's not in linux/pci.h */
-#ifndef PCI_DEVICE_ID_3DLABS_PERMEDIA3
-#define PCI_DEVICE_ID_3DLABS_PERMEDIA3 0x000a
-#endif
-
-/* max number of simultaneous board */
-#define PM3_MAX_BOARD 4
-
 /* max size of options */
 #define PM3_OPTIONS_SIZE 256
 
 /* max size of font name */
 #define PM3_FONTNAME_SIZE 40
 
-/* do we want accelerated console  */
-#define PM3FB_USE_ACCEL 1
-
-/* for driver debugging ONLY */
-/* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */
-/* define PM3FB_MASTER_DEBUG 1 */
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3)
-#define PM3FB_TRACE
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) */
-
-#ifdef PM3FB_MASTER_DEBUG
-#define DPRINTK(l,a,b...) do { if ((l) <= PM3FB_MASTER_DEBUG) printk("pm3fb: %s: " a, __FUNCTION__ , ## b); } while (0)
-#define DASSERT(t,a,b...) do { if (!(t)) printk("pm3fb: _assert failed: %s: " a, __FUNCTION__ , ## b); } while (0)
-#ifdef PM3FB_TRACE
-#define DTRACE printk("pm3fb: _enter %s\n", __FUNCTION__)
-#else /* PM3FB_TRACE */
-#define DTRACE
-#endif /* PM3FB_TRACE */
-#else /* PM3FB_MASTER_DEBUG */
-#define DPRINTK(l,a,b...)
-#define DASSERT(t,a,b...)
-#define DTRACE
-#endif /* PM3FB_MASTER_DEBUG */
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-#define PM3_SHOW_CUR_MODE pm3fb_show_cur_mode(l_fb_info)
-#else
-#define PM3_SHOW_CUR_MODE /* pm3fb_show_cur_mode() */
-#endif
-
-/* ******************************************** */
-/* ***** A bunch of register-access macro ***** */
-/* ******************************************** */
-
-#define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
-#define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
-
-
-#define depth2bpp(d) ((d + 7L) & ~7L)
-#define depth2ByPP(d) (depth2bpp(d) / 8)
-
-#define depth_supported(d) ((d == 8) || (d == 12) || (d == 15) || (d == 16) || (d==32))
-
-
-#define PM3_WAIT(n) \
-do{ \
-       while(PM3_READ_REG(PM3InFIFOSpace)<(n)); \
-} while(0)
-
-#define PM3_DELAY(x) do { \
-        int delay = x; \
-        unsigned char tmp; \
-        while(delay--){tmp = PM3_READ_REG(PM3InFIFOSpace);}; \
-} while(0)
-
-#define PM3_SLOW_WRITE_REG(r,v)        \
-do{                             \
-    DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in slow write\n"); \
-       mb();                   \
-       PM3_WAIT(1);            \
-       mb();                   \
-    PM3_WRITE_REG(r,v);     \
-} while(0)
-
-#define PM3_SET_INDEX(index) \
-do{ \
-       PM3_SLOW_WRITE_REG(PM3RD_IndexHigh,(((index)>>8)&0xff)); \
-       PM3_SLOW_WRITE_REG(PM3RD_IndexLow,((index)&0xff)); \
-} while(0)
-
-#define PM3_WRITE_DAC_REG(r, v) \
-do { \
-     DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in write dac reg\n"); \
-     PM3_SET_INDEX(r); \
-     mb(); \
-     PM3_WRITE_REG(PM3RD_IndexedData, v); \
-} while (0)
-
-/* next one is really a function, added as a macro to be consistent */
-#define PM3_READ_DAC_REG(r) pm3fb_read_dac_reg(l_fb_info, r)
-
-
-#define PM3_COLOR(c) \
-do { \
-  if (l_fb_info->current_par->depth == 8) \
-    { \
-      c = (c & 0xFF); \
-      c = c | (c << 8); \
-    } \
-  if ((l_fb_info->current_par->depth == 8) || (depth2bpp(l_fb_info->current_par->depth) == 16)) \
-    { \
-      c = (c & 0xFFFF); \
-      c = c | (c << 16); \
-    } \
-} while (0)
-
 #endif /* PM3FB_H */
index d0edf42f4dba1e18ccec34ad036f80e0f956ec11..4e009fde4b695fb71cc6c3935006b60a996d2888 100644 (file)
@@ -143,9 +143,7 @@ config POSIX_MQUEUE
          queues every message has a priority which decides about succession
          of receiving it by a process. If you want to compile and run
          programs written e.g. for Solaris with use of its POSIX message
-         queues (functions mq_*) say Y here. To use this feature you will
-         also need mqueue library, available from
-         <http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
+         queues (functions mq_*) say Y here.
 
          POSIX message queues are visible as a filesystem called 'mqueue'
          and can be mounted somewhere if you want to do filesystem
@@ -308,7 +306,7 @@ config SYSFS_DEPRECATED
          releases.
 
          If enabled, this option will also move any device structures
-         that belong to a class, back into the /sys/class heirachy, in
+         that belong to a class, back into the /sys/class hierarchy, in
          order to support older versions of udev.
 
          If you are using a distro that was released in 2006 or later,
@@ -477,13 +475,53 @@ config FUTEX
          support for "fast userspace mutexes".  The resulting kernel may not
          run glibc-based applications correctly.
 
+config ANON_INODES
+       bool "Enable anonymous inode source" if EMBEDDED
+       default y
+       help
+         Anonymous inode source for pseudo-files like epoll, signalfd,
+         timerfd and eventfd.
+
+         If unsure, say Y.
+
 config EPOLL
        bool "Enable eventpoll support" if EMBEDDED
        default y
+       depends on ANON_INODES
        help
          Disabling this option will cause the kernel to be built without
          support for epoll family of system calls.
 
+config SIGNALFD
+       bool "Enable signalfd() system call" if EMBEDDED
+       depends on ANON_INODES
+       default y
+       help
+         Enable the signalfd() system call that allows to receive signals
+         on a file descriptor.
+
+         If unsure, say Y.
+
+config TIMERFD
+       bool "Enable timerfd() system call" if EMBEDDED
+       depends on ANON_INODES
+       default y
+       help
+         Enable the timerfd() system call that allows to receive timer
+         events on a file descriptor.
+
+         If unsure, say Y.
+
+config EVENTFD
+       bool "Enable eventfd() system call" if EMBEDDED
+       depends on ANON_INODES
+       default y
+       help
+         Enable the eventfd() system call that allows to receive both
+         kernel notification (ie. KAIO) or userspace notifications.
+
+         If unsure, say Y.
+
 config SHMEM
        bool "Use full shmem filesystem" if EMBEDDED
        default y
@@ -504,6 +542,16 @@ config VM_EVENT_COUNTERS
          on EMBEDDED systems.  /proc/vmstat will only show page counts
          if VM event counters are disabled.
 
+config SLUB_DEBUG
+       default y
+       bool "Enable SLUB debugging support" if EMBEDDED
+       depends on SLUB
+       help
+         SLUB has extensive debug support features. Disabling these can
+         result in significant savings in code size. This also disables
+         SLUB sysfs support. /sys/slab will not exist and there will be
+         no support for cache validation etc.
+
 choice
        prompt "Choose SLAB allocator"
        default SLAB
@@ -514,9 +562,9 @@ config SLAB
        bool "SLAB"
        help
          The regular slab allocator that is established and known to work
-         well in all environments. It organizes chache hot objects in
+         well in all environments. It organizes cache hot objects in
          per cpu and per node queues. SLAB is the default choice for
-         slab allocator.
+         slab allocator.
 
 config SLUB
        depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
@@ -526,21 +574,20 @@ config SLUB
           instead of managing queues of cached objects (SLAB approach).
           Per cpu caching is realized using slabs of objects instead
           of queues of objects. SLUB can use memory efficiently
-          way and has enhanced diagnostics.
+          and has enhanced diagnostics.
 
 config SLOB
 #
-#      SLOB cannot support SMP because SLAB_DESTROY_BY_RCU does not work
-#      properly.
+#      SLOB does not support SMP because SLAB_DESTROY_BY_RCU is unsupported
 #
        depends on EMBEDDED && !SMP && !SPARSEMEM
        bool "SLOB (Simple Allocator)"
        help
           SLOB replaces the SLAB allocator with a drastically simpler
           allocator.  SLOB is more space efficient that SLAB but does not
-          scale well (single lock for all operations) and is more susceptible
-          to fragmentation. SLOB it is a great choice to reduce
-          memory usage and code size for embedded systems.
+          scale well (single lock for all operations) and is also highly
+          susceptible to fragmentation. SLUB can accomplish a higher object
+          density. It is usually better to use SLUB instead of SLOB.
 
 endchoice
 
index 3f57ed4599d6d87282f0afaead6e8ae3ad8cbf79..46fe407fb03eb6be6236378be2daa79a61cd5aa1 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/root_dev.h>
 #include <linux/security.h>
 #include <linux/delay.h>
+#include <linux/genhd.h>
 #include <linux/mount.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -308,17 +309,21 @@ retry:
                /*
                 * Allow the user to distinguish between failed sys_open
                 * and bad superblock on root device.
+                * and give them a list of the available devices
                 */
 #ifdef CONFIG_BLOCK
                __bdevname(ROOT_DEV, b);
 #endif
                printk("VFS: Cannot open root device \"%s\" or %s\n",
                                root_device_name, b);
-               printk("Please append a correct \"root=\" boot option\n");
+               printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
+               printk_all_partitions();
                panic("VFS: Unable to mount root fs on %s", b);
        }
 
+       printk("List of all partitions:\n");
+       printk_all_partitions();
        printk("No filesystem could mount root, tried: ");
        for (p = fs_names; *p; p += strlen(p)+1)
                printk(" %s", p);
index c1537e0ddcebdc549d4b5d426640e81e878cff79..1940fa75e82e1c88c36fba13f0ed5fd00624892e 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/lockdep.h>
 #include <linux/pid_namespace.h>
 #include <linux/device.h>
+#include <linux/kthread.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -425,8 +426,12 @@ static void __init setup_command_line(char *command_line)
 static void noinline rest_init(void)
        __releases(kernel_lock)
 {
+       int pid;
+
        kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
        numa_default_policy();
+       pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
+       kthreadd_task = find_task_by_pid(pid);
        unlock_kernel();
 
        /*
@@ -796,6 +801,7 @@ static int __init kernel_init(void * unused)
         */
        init_pid_ns.child_reaper = current;
 
+       __set_special_pids(1, 1);
        cad_pid = task_pid(current);
 
        smp_prepare_cpus(max_cpus);
index 0b46a5dff4c047c72f9d062484124bd3261cf1a3..c64ce9c14207644bfc07c5f2c729f5fe9b66c5b6 100644 (file)
@@ -23,7 +23,7 @@ config PREEMPT_VOLUNTARY
          "explicit preemption points" to the kernel code. These new
          preemption points have been selected to reduce the maximum
          latency of rescheduling, providing faster application reactions,
-         at the cost of slighly lower throughput.
+         at the cost of slightly lower throughput.
 
          This allows reaction to interactive events by allowing a
          low priority process to voluntarily preempt itself even if it
@@ -43,7 +43,7 @@ config PREEMPT
          even if it is in kernel mode executing a system call and would
          otherwise not be about to reach a natural preemption point.
          This allows applications to run more 'smoothly' even when the
-         system is under load, at the cost of slighly lower throughput
+         system is under load, at the cost of slightly lower throughput
          and a slight runtime overhead to kernel code.
 
          Select this if you are building a kernel for a desktop or
index cebb4c28c039b0cd9ad14592557d324b0ffac899..3bae3742c2aa567e18f7b1558f7fa72b1c9155a0 100644 (file)
@@ -475,8 +475,8 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
        return min_length;
 }
 
-static int get_compat_itimerspec(struct itimerspec *dst, 
-                                struct compat_itimerspec __user *src)
+int get_compat_itimerspec(struct itimerspec *dst,
+                         const struct compat_itimerspec __user *src)
 { 
        if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
            get_compat_timespec(&dst->it_value, &src->it_value))
@@ -484,8 +484,8 @@ static int get_compat_itimerspec(struct itimerspec *dst,
        return 0;
 } 
 
-static int put_compat_itimerspec(struct compat_itimerspec __user *dst, 
-                                struct itimerspec *src)
+int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+                         const struct itimerspec *src)
 { 
        if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
            put_compat_timespec(&src->it_value, &dst->it_value))
index 8fa1fb28f8a79b895d6438a2485466d2ac8efda1..e84d3f9c6c7ba87218df59577462fc2523c0b6f9 100644 (file)
@@ -61,18 +61,9 @@ static ssize_t
 ikconfig_read_current(struct file *file, char __user *buf,
                      size_t len, loff_t * offset)
 {
-       loff_t pos = *offset;
-       ssize_t count;
-
-       if (pos >= kernel_config_data_size)
-               return 0;
-
-       count = min(len, (size_t)(kernel_config_data_size - pos));
-       if (copy_to_user(buf, kernel_config_data + MAGIC_SIZE + pos, count))
-               return -EFAULT;
-
-       *offset += count;
-       return count;
+       return simple_read_from_buffer(buf, len, offset,
+                                      kernel_config_data + MAGIC_SIZE,
+                                      kernel_config_data_size);
 }
 
 static const struct file_operations ikconfig_file_ops = {
index 36e70845cfc3b40a4cfa98b06365df480caac6f3..208cf3497c10230552e12de042a72a1da61fe955 100644 (file)
@@ -97,7 +97,7 @@ static inline void check_for_tasks(int cpu)
                    (!cputime_eq(p->utime, cputime_zero) ||
                     !cputime_eq(p->stime, cputime_zero)))
                        printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
-                               (state = %ld, flags = %lx) \n",
+                               (state = %ld, flags = %x) \n",
                                 p->comm, p->pid, cpu, p->state, p->flags);
        }
        write_unlock_irq(&tasklist_lock);
@@ -120,11 +120,13 @@ static int take_cpu_down(void *unused)
 }
 
 /* Requires cpu_add_remove_lock to be held */
-static int _cpu_down(unsigned int cpu)
+static int _cpu_down(unsigned int cpu, int tasks_frozen)
 {
-       int err;
+       int err, nr_calls = 0;
        struct task_struct *p;
        cpumask_t old_allowed, tmp;
+       void *hcpu = (void *)(long)cpu;
+       unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 
        if (num_online_cpus() == 1)
                return -EBUSY;
@@ -132,12 +134,16 @@ static int _cpu_down(unsigned int cpu)
        if (!cpu_online(cpu))
                return -EINVAL;
 
-       err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
-                                               (void *)(long)cpu);
+       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
+                                       hcpu, -1, &nr_calls);
        if (err == NOTIFY_BAD) {
+               __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+                                         hcpu, nr_calls, NULL);
                printk("%s: attempt to take down CPU %u failed\n",
                                __FUNCTION__, cpu);
-               return -EINVAL;
+               err = -EINVAL;
+               goto out_release;
        }
 
        /* Ensure that we are not runnable on dying cpu */
@@ -152,8 +158,8 @@ static int _cpu_down(unsigned int cpu)
 
        if (IS_ERR(p) || cpu_online(cpu)) {
                /* CPU didn't die: tell everyone.  Can't complain. */
-               if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
-                               (void *)(long)cpu) == NOTIFY_BAD)
+               if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+                                           hcpu) == NOTIFY_BAD)
                        BUG();
 
                if (IS_ERR(p)) {
@@ -170,13 +176,9 @@ static int _cpu_down(unsigned int cpu)
        /* This actually kills the CPU. */
        __cpu_die(cpu);
 
-       /* Move it here so it can run. */
-       kthread_bind(p, get_cpu());
-       put_cpu();
-
        /* CPU is completely dead: tell everyone.  Too late to complain. */
-       if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD,
-                       (void *)(long)cpu) == NOTIFY_BAD)
+       if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
+                                   hcpu) == NOTIFY_BAD)
                BUG();
 
        check_for_tasks(cpu);
@@ -185,6 +187,8 @@ out_thread:
        err = kthread_stop(p);
 out_allowed:
        set_cpus_allowed(current, old_allowed);
+out_release:
+       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
        return err;
 }
 
@@ -196,7 +200,7 @@ int cpu_down(unsigned int cpu)
        if (cpu_hotplug_disabled)
                err = -EBUSY;
        else
-               err = _cpu_down(cpu);
+               err = _cpu_down(cpu, 0);
 
        mutex_unlock(&cpu_add_remove_lock);
        return err;
@@ -204,15 +208,18 @@ int cpu_down(unsigned int cpu)
 #endif /*CONFIG_HOTPLUG_CPU*/
 
 /* Requires cpu_add_remove_lock to be held */
-static int __cpuinit _cpu_up(unsigned int cpu)
+static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
 {
-       int ret;
+       int ret, nr_calls = 0;
        void *hcpu = (void *)(long)cpu;
+       unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 
        if (cpu_online(cpu) || !cpu_present(cpu))
                return -EINVAL;
 
-       ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+       ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
+                                                       -1, &nr_calls);
        if (ret == NOTIFY_BAD) {
                printk("%s: attempt to bring up CPU %u failed\n",
                                __FUNCTION__, cpu);
@@ -229,12 +236,13 @@ static int __cpuinit _cpu_up(unsigned int cpu)
        BUG_ON(!cpu_online(cpu));
 
        /* Now call notifier in preparation. */
-       raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+       raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
 
 out_notify:
        if (ret != 0)
-               raw_notifier_call_chain(&cpu_chain,
-                               CPU_UP_CANCELED, hcpu);
+               __raw_notifier_call_chain(&cpu_chain,
+                               CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
+       raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
 
        return ret;
 }
@@ -247,19 +255,13 @@ int __cpuinit cpu_up(unsigned int cpu)
        if (cpu_hotplug_disabled)
                err = -EBUSY;
        else
-               err = _cpu_up(cpu);
+               err = _cpu_up(cpu, 0);
 
        mutex_unlock(&cpu_add_remove_lock);
        return err;
 }
 
 #ifdef CONFIG_SUSPEND_SMP
-/* Needed to prevent the microcode driver from requesting firmware in its CPU
- * hotplug notifier during the suspend/resume.
- */
-int suspend_cpu_hotplug;
-EXPORT_SYMBOL(suspend_cpu_hotplug);
-
 static cpumask_t frozen_cpus;
 
 int disable_nonboot_cpus(void)
@@ -267,7 +269,6 @@ int disable_nonboot_cpus(void)
        int cpu, first_cpu, error = 0;
 
        mutex_lock(&cpu_add_remove_lock);
-       suspend_cpu_hotplug = 1;
        first_cpu = first_cpu(cpu_online_map);
        /* We take down all of the non-boot CPUs in one shot to avoid races
         * with the userspace trying to use the CPU hotplug at the same time
@@ -277,7 +278,7 @@ int disable_nonboot_cpus(void)
        for_each_online_cpu(cpu) {
                if (cpu == first_cpu)
                        continue;
-               error = _cpu_down(cpu);
+               error = _cpu_down(cpu, 1);
                if (!error) {
                        cpu_set(cpu, frozen_cpus);
                        printk("CPU%d is down\n", cpu);
@@ -294,7 +295,6 @@ int disable_nonboot_cpus(void)
        } else {
                printk(KERN_ERR "Non-boot CPUs are not disabled\n");
        }
-       suspend_cpu_hotplug = 0;
        mutex_unlock(&cpu_add_remove_lock);
        return error;
 }
@@ -309,10 +309,9 @@ void enable_nonboot_cpus(void)
        if (cpus_empty(frozen_cpus))
                goto out;
 
-       suspend_cpu_hotplug = 1;
        printk("Enabling non-boot CPUs ...\n");
        for_each_cpu_mask(cpu, frozen_cpus) {
-               error = _cpu_up(cpu);
+               error = _cpu_up(cpu, 1);
                if (!error) {
                        printk("CPU%d is up\n", cpu);
                        continue;
@@ -320,7 +319,6 @@ void enable_nonboot_cpus(void)
                printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
        }
        cpus_clear(frozen_cpus);
-       suspend_cpu_hotplug = 0;
 out:
        mutex_unlock(&cpu_add_remove_lock);
 }
index 88b416dfbc7231d95a97ea36ad36da0798bbbf8e..f57854b0892275d901e9e1b7b8f2e4784adcc37a 100644 (file)
@@ -1772,12 +1772,7 @@ static ssize_t cpuset_tasks_read(struct file *file, char __user *buf,
 {
        struct ctr_struct *ctr = file->private_data;
 
-       if (*ppos + nbytes > ctr->bufsz)
-               nbytes = ctr->bufsz - *ppos;
-       if (copy_to_user(buf, ctr->buf + *ppos, nbytes))
-               return -EFAULT;
-       *ppos += nbytes;
-       return nbytes;
+       return simple_read_from_buffer(buf, nbytes, ppos, ctr->buf, ctr->bufsz);
 }
 
 static int cpuset_tasks_release(struct inode *unused_inode, struct file *file)
index f5a7abb621f3738ce4199ad1405143405d1dbfd5..c6d14b8008ddf3007831723fc1113cd63ad3cb46 100644 (file)
 #include <linux/pid_namespace.h>
 #include <linux/ptrace.h>
 #include <linux/profile.h>
+#include <linux/signalfd.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/kthread.h>
 #include <linux/mempolicy.h>
 #include <linux/taskstats_kern.h>
 #include <linux/delayacct.h>
@@ -41,6 +43,7 @@
 #include <linux/audit.h> /* for audit_free() */
 #include <linux/resource.h>
 #include <linux/blkdev.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -81,6 +84,14 @@ static void __exit_signal(struct task_struct *tsk)
        sighand = rcu_dereference(tsk->sighand);
        spin_lock(&sighand->siglock);
 
+       /*
+        * Notify that this sighand has been detached. This must
+        * be called with the tsk->sighand lock held. Also, this
+        * access tsk->sighand internally, so it must be called
+        * before tsk->sighand is reset.
+        */
+       signalfd_detach_locked(tsk);
+
        posix_cpu_timers_exit(tsk);
        if (atomic_dec_and_test(&sig->count))
                posix_cpu_timers_exit_group(tsk);
@@ -112,6 +123,8 @@ static void __exit_signal(struct task_struct *tsk)
                sig->nvcsw += tsk->nvcsw;
                sig->nivcsw += tsk->nivcsw;
                sig->sched_time += tsk->sched_time;
+               sig->inblock += task_io_get_inblock(tsk);
+               sig->oublock += task_io_get_oublock(tsk);
                sig = NULL; /* Marker for below. */
        }
 
@@ -254,26 +267,25 @@ static int has_stopped_jobs(struct pid *pgrp)
 }
 
 /**
- * reparent_to_init - Reparent the calling kernel thread to the init task of the pid space that the thread belongs to.
+ * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd
  *
  * If a kernel thread is launched as a result of a system call, or if
- * it ever exits, it should generally reparent itself to init so that
- * it is correctly cleaned up on exit.
+ * it ever exits, it should generally reparent itself to kthreadd so it
+ * isn't in the way of other processes and is correctly cleaned up on exit.
  *
  * The various task state such as scheduling policy and priority may have
  * been inherited from a user process, so we reset them to sane values here.
  *
- * NOTE that reparent_to_init() gives the caller full capabilities.
+ * NOTE that reparent_to_kthreadd() gives the caller full capabilities.
  */
-static void reparent_to_init(void)
+static void reparent_to_kthreadd(void)
 {
        write_lock_irq(&tasklist_lock);
 
        ptrace_unlink(current);
        /* Reparent to init */
        remove_parent(current);
-       current->parent = child_reaper(current);
-       current->real_parent = child_reaper(current);
+       current->real_parent = current->parent = kthreadd_task;
        add_parent(current);
 
        /* Set the exit signal to SIGCHLD so we signal init on exit */
@@ -299,12 +311,12 @@ void __set_special_pids(pid_t session, pid_t pgrp)
        if (process_session(curr) != session) {
                detach_pid(curr, PIDTYPE_SID);
                set_signal_session(curr->signal, session);
-               attach_pid(curr, PIDTYPE_SID, session);
+               attach_pid(curr, PIDTYPE_SID, find_pid(session));
        }
        if (process_group(curr) != pgrp) {
                detach_pid(curr, PIDTYPE_PGID);
                curr->signal->pgrp = pgrp;
-               attach_pid(curr, PIDTYPE_PGID, pgrp);
+               attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp));
        }
 }
 
@@ -347,7 +359,7 @@ int disallow_signal(int sig)
                return -EINVAL;
 
        spin_lock_irq(&current->sighand->siglock);
-       sigaddset(&current->blocked, sig);
+       current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
        return 0;
@@ -400,7 +412,7 @@ void daemonize(const char *name, ...)
        current->files = init_task.files;
        atomic_inc(&current->files->count);
 
-       reparent_to_init();
+       reparent_to_kthreadd();
 }
 
 EXPORT_SYMBOL(daemonize);
@@ -1193,6 +1205,12 @@ static int wait_task_zombie(struct task_struct *p, int noreap,
                        p->nvcsw + sig->nvcsw + sig->cnvcsw;
                psig->cnivcsw +=
                        p->nivcsw + sig->nivcsw + sig->cnivcsw;
+               psig->cinblock +=
+                       task_io_get_inblock(p) +
+                       sig->inblock + sig->cinblock;
+               psig->coublock +=
+                       task_io_get_oublock(p) +
+                       sig->oublock + sig->coublock;
                spin_unlock_irq(&p->parent->sighand->siglock);
        }
 
index a8dd75d4992bbaffb63310987291127c8bd96a6d..49530e40ea8b7e6a7d6c1725f42312bd5161ad2a 100644 (file)
@@ -105,7 +105,7 @@ static struct kmem_cache *mm_cachep;
 
 void free_task(struct task_struct *tsk)
 {
-       free_thread_info(tsk->thread_info);
+       free_thread_info(tsk->stack);
        rt_mutex_debug_task_free(tsk);
        free_task_struct(tsk);
 }
@@ -175,7 +175,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        }
 
        *tsk = *orig;
-       tsk->thread_info = ti;
+       tsk->stack = ti;
        setup_thread_stack(tsk, orig);
 
 #ifdef CONFIG_CC_STACKPROTECTOR
@@ -875,6 +875,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
        sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
        sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
        sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
+       sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
        sig->sched_time = 0;
        INIT_LIST_HEAD(&sig->cpu_timers[0]);
        INIT_LIST_HEAD(&sig->cpu_timers[1]);
@@ -955,7 +956,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                        unsigned long stack_size,
                                        int __user *parent_tidptr,
                                        int __user *child_tidptr,
-                                       int pid)
+                                       struct pid *pid)
 {
        int retval;
        struct task_struct *p = NULL;
@@ -1022,7 +1023,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        p->did_exec = 0;
        delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
        copy_flags(clone_flags, p);
-       p->pid = pid;
+       p->pid = pid_nr(pid);
        retval = -EFAULT;
        if (clone_flags & CLONE_PARENT_SETTID)
                if (put_user(p->pid, parent_tidptr))
@@ -1251,13 +1252,13 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                        p->signal->tty = current->signal->tty;
                        p->signal->pgrp = process_group(current);
                        set_signal_session(p->signal, process_session(current));
-                       attach_pid(p, PIDTYPE_PGID, process_group(p));
-                       attach_pid(p, PIDTYPE_SID, process_session(p));
+                       attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
+                       attach_pid(p, PIDTYPE_SID, task_session(current));
 
                        list_add_tail_rcu(&p->tasks, &init_task.tasks);
                        __get_cpu_var(process_counts)++;
                }
-               attach_pid(p, PIDTYPE_PID, p->pid);
+               attach_pid(p, PIDTYPE_PID, pid);
                nr_threads++;
        }
 
@@ -1321,7 +1322,8 @@ struct task_struct * __cpuinit fork_idle(int cpu)
        struct task_struct *task;
        struct pt_regs regs;
 
-       task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL, 0);
+       task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL,
+                               &init_struct_pid);
        if (!IS_ERR(task))
                init_idle(task, cpu);
 
@@ -1371,7 +1373,7 @@ long do_fork(unsigned long clone_flags,
                        clone_flags |= CLONE_PTRACE;
        }
 
-       p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
+       p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
        /*
         * Do this prior waking up the new thread - the thread pointer
         * might get invalid after that point, if the thread exits quickly.
@@ -1420,12 +1422,15 @@ long do_fork(unsigned long clone_flags,
 #define ARCH_MIN_MMSTRUCT_ALIGN 0
 #endif
 
-static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags)
+static void sighand_ctor(void *data, struct kmem_cache *cachep,
+                       unsigned long flags)
 {
        struct sighand_struct *sighand = data;
 
-       if (flags & SLAB_CTOR_CONSTRUCTOR)
+       if (flags & SLAB_CTOR_CONSTRUCTOR) {
                spin_lock_init(&sighand->siglock);
+               INIT_LIST_HEAD(&sighand->signalfd_list);
+       }
 }
 
 void __init proc_caches_init(void)
@@ -1451,7 +1456,6 @@ void __init proc_caches_init(void)
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
 }
 
-
 /*
  * Check constraints on flags passed to the unshare system call and
  * force unsharing of additional process context as appropriate.
index 600bc9d801f2834c5e56203ccb614527c6b0d421..b7ce15c67e324b468d13599d47df7423adcd69d4 100644 (file)
@@ -16,6 +16,9 @@
  *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  *  Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
  *
+ *  PRIVATE futexes by Eric Dumazet
+ *  Copyright (C) 2007 Eric Dumazet <dada1@cosmosbay.com>
+ *
  *  Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
  *  enough at me, Linus for the original (flawed) idea, Matthew
  *  Kirkwood for proof-of-concept implementation.
 
 #include "rtmutex_common.h"
 
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
 #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
 
 /*
@@ -81,12 +90,12 @@ struct futex_pi_state {
  * we can wake only the relevant ones (hashed queues may be shared).
  *
  * A futex_q has a woken state, just like tasks have TASK_RUNNING.
- * It is considered woken when list_empty(&q->list) || q->lock_ptr == 0.
+ * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
  * The order of wakup is always to make the first condition true, then
  * wake up q->waiters, then make the second condition true.
  */
 struct futex_q {
-       struct list_head list;
+       struct plist_node list;
        wait_queue_head_t waiters;
 
        /* Which hash list lock to use: */
@@ -102,14 +111,20 @@ struct futex_q {
        /* Optional priority inheritance state: */
        struct futex_pi_state *pi_state;
        struct task_struct *task;
+
+       /*
+        * This waiter is used in case of requeue from a
+        * normal futex to a PI-futex
+        */
+       struct rt_mutex_waiter waiter;
 };
 
 /*
  * Split the global futex_lock into every hash list lock.
  */
 struct futex_hash_bucket {
-       spinlock_t              lock;
-       struct list_head       chain;
+       spinlock_t lock;
+       struct plist_head chain;
 };
 
 static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
@@ -138,19 +153,26 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
                && key1->both.offset == key2->both.offset);
 }
 
-/*
- * Get parameters which are the keys for a futex.
+/**
+ * get_futex_key - Get parameters which are the keys for a futex.
+ * @uaddr: virtual address of the futex
+ * @shared: NULL for a PROCESS_PRIVATE futex,
+ *     &current->mm->mmap_sem for a PROCESS_SHARED futex
+ * @key: address where result is stored.
+ *
+ * Returns a negative error code or 0
+ * The key words are stored in *key on success.
  *
  * For shared mappings, it's (page->index, vma->vm_file->f_path.dentry->d_inode,
  * offset_within_page).  For private mappings, it's (uaddr, current->mm).
  * We can usually work out the index without swapping in the page.
  *
- * Returns: 0, or negative error code.
- * The key words are stored in *key on success.
- *
- * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
+ * fshared is NULL for PROCESS_PRIVATE futexes
+ * For other futexes, it points to &current->mm->mmap_sem and
+ * caller must have taken the reader lock. but NOT any spinlocks.
  */
-int get_futex_key(u32 __user *uaddr, union futex_key *key)
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *fshared,
+                 union futex_key *key)
 {
        unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
@@ -162,10 +184,24 @@ int get_futex_key(u32 __user *uaddr, union futex_key *key)
         * The futex address must be "naturally" aligned.
         */
        key->both.offset = address % PAGE_SIZE;
-       if (unlikely((key->both.offset % sizeof(u32)) != 0))
+       if (unlikely((address % sizeof(u32)) != 0))
                return -EINVAL;
        address -= key->both.offset;
 
+       /*
+        * PROCESS_PRIVATE futexes are fast.
+        * As the mm cannot disappear under us and the 'key' only needs
+        * virtual address, we dont even have to find the underlying vma.
+        * Note : We do have to check 'uaddr' is a valid user address,
+        *        but access_ok() should be faster than find_vma()
+        */
+       if (!fshared) {
+               if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
+                       return -EFAULT;
+               key->private.mm = mm;
+               key->private.address = address;
+               return 0;
+       }
        /*
         * The futex is hashed differently depending on whether
         * it's in a shared or private mapping.  So check vma first.
@@ -180,6 +216,9 @@ int get_futex_key(u32 __user *uaddr, union futex_key *key)
        if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
                return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
 
+       /* Save the user address in the ley */
+       key->uaddr = uaddr;
+
        /*
         * Private mappings are handled in a simple way.
         *
@@ -190,6 +229,7 @@ int get_futex_key(u32 __user *uaddr, union futex_key *key)
         * mappings of _writable_ handles.
         */
        if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
+               key->both.offset |= FUT_OFF_MMSHARED; /* reference taken on mm */
                key->private.mm = mm;
                key->private.address = address;
                return 0;
@@ -199,7 +239,7 @@ int get_futex_key(u32 __user *uaddr, union futex_key *key)
         * Linear file mappings are also simple.
         */
        key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
-       key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
+       key->both.offset |= FUT_OFF_INODE; /* inode-based key. */
        if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
                key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
                                     + vma->vm_pgoff);
@@ -227,16 +267,18 @@ EXPORT_SYMBOL_GPL(get_futex_key);
  * Take a reference to the resource addressed by a key.
  * Can be called while holding spinlocks.
  *
- * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
- * function, if it is called at all.  mmap_sem keeps key->shared.inode valid.
  */
 inline void get_futex_key_refs(union futex_key *key)
 {
-       if (key->both.ptr != 0) {
-               if (key->both.offset & 1)
+       if (key->both.ptr == 0)
+               return;
+       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+               case FUT_OFF_INODE:
                        atomic_inc(&key->shared.inode->i_count);
-               else
+                       break;
+               case FUT_OFF_MMSHARED:
                        atomic_inc(&key->private.mm->mm_count);
+                       break;
        }
 }
 EXPORT_SYMBOL_GPL(get_futex_key_refs);
@@ -247,11 +289,15 @@ EXPORT_SYMBOL_GPL(get_futex_key_refs);
  */
 void drop_futex_key_refs(union futex_key *key)
 {
-       if (key->both.ptr != 0) {
-               if (key->both.offset & 1)
+       if (key->both.ptr == 0)
+               return;
+       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+               case FUT_OFF_INODE:
                        iput(key->shared.inode);
-               else
+                       break;
+               case FUT_OFF_MMSHARED:
                        mmdrop(key->private.mm);
+                       break;
        }
 }
 EXPORT_SYMBOL_GPL(drop_futex_key_refs);
@@ -268,28 +314,38 @@ static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
 }
 
 /*
- * Fault handling. Called with current->mm->mmap_sem held.
+ * Fault handling.
+ * if fshared is non NULL, current->mm->mmap_sem is already held
  */
-static int futex_handle_fault(unsigned long address, int attempt)
+static int futex_handle_fault(unsigned long address,
+                             struct rw_semaphore *fshared, int attempt)
 {
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
+       int ret = -EFAULT;
 
-       if (attempt > 2 || !(vma = find_vma(mm, address)) ||
-           vma->vm_start > address || !(vma->vm_flags & VM_WRITE))
-               return -EFAULT;
+       if (attempt > 2)
+               return ret;
 
-       switch (handle_mm_fault(mm, vma, address, 1)) {
-       case VM_FAULT_MINOR:
-               current->min_flt++;
-               break;
-       case VM_FAULT_MAJOR:
-               current->maj_flt++;
-               break;
-       default:
-               return -EFAULT;
+       if (!fshared)
+               down_read(&mm->mmap_sem);
+       vma = find_vma(mm, address);
+       if (vma && address >= vma->vm_start &&
+           (vma->vm_flags & VM_WRITE)) {
+               switch (handle_mm_fault(mm, vma, address, 1)) {
+               case VM_FAULT_MINOR:
+                       ret = 0;
+                       current->min_flt++;
+                       break;
+               case VM_FAULT_MAJOR:
+                       ret = 0;
+                       current->maj_flt++;
+                       break;
+               }
        }
-       return 0;
+       if (!fshared)
+               up_read(&mm->mmap_sem);
+       return ret;
 }
 
 /*
@@ -439,18 +495,19 @@ void exit_pi_state_list(struct task_struct *curr)
 }
 
 static int
-lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
+               union futex_key *key, struct futex_pi_state **ps)
 {
        struct futex_pi_state *pi_state = NULL;
        struct futex_q *this, *next;
-       struct list_head *head;
+       struct plist_head *head;
        struct task_struct *p;
        pid_t pid;
 
        head = &hb->chain;
 
-       list_for_each_entry_safe(this, next, head, list) {
-               if (match_futex(&this->key, &me->key)) {
+       plist_for_each_entry_safe(this, next, head, list) {
+               if (match_futex(&this->key, key)) {
                        /*
                         * Another waiter already exists - bump up
                         * the refcount and return its pi_state:
@@ -465,7 +522,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
                        WARN_ON(!atomic_read(&pi_state->refcount));
 
                        atomic_inc(&pi_state->refcount);
-                       me->pi_state = pi_state;
+                       *ps = pi_state;
 
                        return 0;
                }
@@ -492,7 +549,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
        rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
 
        /* Store the key for possible exit cleanups: */
-       pi_state->key = me->key;
+       pi_state->key = *key;
 
        spin_lock_irq(&p->pi_lock);
        WARN_ON(!list_empty(&pi_state->list));
@@ -502,7 +559,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
 
        put_task_struct(p);
 
-       me->pi_state = pi_state;
+       *ps = pi_state;
 
        return 0;
 }
@@ -513,12 +570,12 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
  */
 static void wake_futex(struct futex_q *q)
 {
-       list_del_init(&q->list);
+       plist_del(&q->list, &q->list.plist);
        if (q->filp)
                send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
        /*
         * The lock in wake_up_all() is a crucial memory barrier after the
-        * list_del_init() and also before assigning to q->lock_ptr.
+        * plist_del() and also before assigning to q->lock_ptr.
         */
        wake_up_all(&q->waiters);
        /*
@@ -562,6 +619,8 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
         */
        if (!(uval & FUTEX_OWNER_DIED)) {
                newval = FUTEX_WAITERS | new_owner->pid;
+               /* Keep the FUTEX_WAITER_REQUEUED flag if it was set */
+               newval |= (uval & FUTEX_WAITER_REQUEUED);
 
                pagefault_disable();
                curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -629,17 +688,19 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(u32 __user *uaddr, int nr_wake)
+static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+                     int nr_wake)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
-       struct list_head *head;
+       struct plist_head *head;
        union futex_key key;
        int ret;
 
-       down_read(&current->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr, &key);
+       ret = get_futex_key(uaddr, fshared, &key);
        if (unlikely(ret != 0))
                goto out;
 
@@ -647,7 +708,7 @@ static int futex_wake(u32 __user *uaddr, int nr_wake)
        spin_lock(&hb->lock);
        head = &hb->chain;
 
-       list_for_each_entry_safe(this, next, head, list) {
+       plist_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key)) {
                        if (this->pi_state) {
                                ret = -EINVAL;
@@ -661,7 +722,261 @@ static int futex_wake(u32 __user *uaddr, int nr_wake)
 
        spin_unlock(&hb->lock);
 out:
-       up_read(&current->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
+       return ret;
+}
+
+/*
+ * Called from futex_requeue_pi.
+ * Set FUTEX_WAITERS and FUTEX_WAITER_REQUEUED flags on the
+ * PI-futex value; search its associated pi_state if an owner exist
+ * or create a new one without owner.
+ */
+static inline int
+lookup_pi_state_for_requeue(u32 __user *uaddr, struct futex_hash_bucket *hb,
+                           union futex_key *key,
+                           struct futex_pi_state **pi_state)
+{
+       u32 curval, uval, newval;
+
+retry:
+       /*
+        * We can't handle a fault cleanly because we can't
+        * release the locks here. Simply return the fault.
+        */
+       if (get_futex_value_locked(&curval, uaddr))
+               return -EFAULT;
+
+       /* set the flags FUTEX_WAITERS and FUTEX_WAITER_REQUEUED */
+       if ((curval & (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED))
+           != (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED)) {
+               /*
+                * No waiters yet, we prepare the futex to have some waiters.
+                */
+
+               uval = curval;
+               newval = uval | FUTEX_WAITERS | FUTEX_WAITER_REQUEUED;
+
+               pagefault_disable();
+               curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+               pagefault_enable();
+
+               if (unlikely(curval == -EFAULT))
+                       return -EFAULT;
+               if (unlikely(curval != uval))
+                       goto retry;
+       }
+
+       if (!(curval & FUTEX_TID_MASK)
+           || lookup_pi_state(curval, hb, key, pi_state)) {
+               /* the futex has no owner (yet) or the lookup failed:
+                  allocate one pi_state without owner */
+
+               *pi_state = alloc_pi_state();
+
+               /* Already stores the key: */
+               (*pi_state)->key = *key;
+
+               /* init the mutex without owner */
+               __rt_mutex_init(&(*pi_state)->pi_mutex, NULL);
+       }
+
+       return 0;
+}
+
+/*
+ * Keep the first nr_wake waiter from futex1, wake up one,
+ * and requeue the next nr_requeue waiters following hashed on
+ * one physical page to another physical page (PI-futex uaddr2)
+ */
+static int futex_requeue_pi(u32 __user *uaddr1,
+                           struct rw_semaphore *fshared,
+                           u32 __user *uaddr2,
+                           int nr_wake, int nr_requeue, u32 *cmpval)
+{
+       union futex_key key1, key2;
+       struct futex_hash_bucket *hb1, *hb2;
+       struct plist_head *head1;
+       struct futex_q *this, *next;
+       struct futex_pi_state *pi_state2 = NULL;
+       struct rt_mutex_waiter *waiter, *top_waiter = NULL;
+       struct rt_mutex *lock2 = NULL;
+       int ret, drop_count = 0;
+
+       if (refill_pi_state_cache())
+               return -ENOMEM;
+
+retry:
+       /*
+        * First take all the futex related locks:
+        */
+       if (fshared)
+               down_read(fshared);
+
+       ret = get_futex_key(uaddr1, fshared, &key1);
+       if (unlikely(ret != 0))
+               goto out;
+       ret = get_futex_key(uaddr2, fshared, &key2);
+       if (unlikely(ret != 0))
+               goto out;
+
+       hb1 = hash_futex(&key1);
+       hb2 = hash_futex(&key2);
+
+       double_lock_hb(hb1, hb2);
+
+       if (likely(cmpval != NULL)) {
+               u32 curval;
+
+               ret = get_futex_value_locked(&curval, uaddr1);
+
+               if (unlikely(ret)) {
+                       spin_unlock(&hb1->lock);
+                       if (hb1 != hb2)
+                               spin_unlock(&hb2->lock);
+
+                       /*
+                        * If we would have faulted, release mmap_sem, fault
+                        * it in and start all over again.
+                        */
+                       if (fshared)
+                               up_read(fshared);
+
+                       ret = get_user(curval, uaddr1);
+
+                       if (!ret)
+                               goto retry;
+
+                       return ret;
+               }
+               if (curval != *cmpval) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
+       }
+
+       head1 = &hb1->chain;
+       plist_for_each_entry_safe(this, next, head1, list) {
+               if (!match_futex (&this->key, &key1))
+                       continue;
+               if (++ret <= nr_wake) {
+                       wake_futex(this);
+               } else {
+                       /*
+                        * FIRST: get and set the pi_state
+                        */
+                       if (!pi_state2) {
+                               int s;
+                               /* do this only the first time we requeue someone */
+                               s = lookup_pi_state_for_requeue(uaddr2, hb2,
+                                                               &key2, &pi_state2);
+                               if (s) {
+                                       ret = s;
+                                       goto out_unlock;
+                               }
+
+                               lock2 = &pi_state2->pi_mutex;
+                               spin_lock(&lock2->wait_lock);
+
+                               /* Save the top waiter of the wait_list */
+                               if (rt_mutex_has_waiters(lock2))
+                                       top_waiter = rt_mutex_top_waiter(lock2);
+                       } else
+                               atomic_inc(&pi_state2->refcount);
+
+
+                       this->pi_state = pi_state2;
+
+                       /*
+                        * SECOND: requeue futex_q to the correct hashbucket
+                        */
+
+                       /*
+                        * If key1 and key2 hash to the same bucket, no need to
+                        * requeue.
+                        */
+                       if (likely(head1 != &hb2->chain)) {
+                               plist_del(&this->list, &hb1->chain);
+                               plist_add(&this->list, &hb2->chain);
+                               this->lock_ptr = &hb2->lock;
+#ifdef CONFIG_DEBUG_PI_LIST
+                               this->list.plist.lock = &hb2->lock;
+#endif
+                       }
+                       this->key = key2;
+                       get_futex_key_refs(&key2);
+                       drop_count++;
+
+
+                       /*
+                        * THIRD: queue it to lock2
+                        */
+                       spin_lock_irq(&this->task->pi_lock);
+                       waiter = &this->waiter;
+                       waiter->task = this->task;
+                       waiter->lock = lock2;
+                       plist_node_init(&waiter->list_entry, this->task->prio);
+                       plist_node_init(&waiter->pi_list_entry, this->task->prio);
+                       plist_add(&waiter->list_entry, &lock2->wait_list);
+                       this->task->pi_blocked_on = waiter;
+                       spin_unlock_irq(&this->task->pi_lock);
+
+                       if (ret - nr_wake >= nr_requeue)
+                               break;
+               }
+       }
+
+       /* If we've requeued some tasks and the top_waiter of the rt_mutex
+          has changed, we must adjust the priority of the owner, if any */
+       if (drop_count) {
+               struct task_struct *owner = rt_mutex_owner(lock2);
+               if (owner &&
+                   (top_waiter != (waiter = rt_mutex_top_waiter(lock2)))) {
+                       int chain_walk = 0;
+
+                       spin_lock_irq(&owner->pi_lock);
+                       if (top_waiter)
+                               plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
+                       else
+                               /*
+                                * There was no waiters before the requeue,
+                                * the flag must be updated
+                                */
+                               mark_rt_mutex_waiters(lock2);
+
+                       plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+                       __rt_mutex_adjust_prio(owner);
+                       if (owner->pi_blocked_on) {
+                               chain_walk = 1;
+                               get_task_struct(owner);
+                       }
+
+                       spin_unlock_irq(&owner->pi_lock);
+                       spin_unlock(&lock2->wait_lock);
+
+                       if (chain_walk)
+                               rt_mutex_adjust_prio_chain(owner, 0, lock2, NULL,
+                                                          current);
+               } else {
+                       /* No owner or the top_waiter does not change */
+                       mark_rt_mutex_waiters(lock2);
+                       spin_unlock(&lock2->wait_lock);
+               }
+       }
+
+out_unlock:
+       spin_unlock(&hb1->lock);
+       if (hb1 != hb2)
+               spin_unlock(&hb2->lock);
+
+       /* drop_futex_key_refs() must be called outside the spinlocks. */
+       while (--drop_count >= 0)
+               drop_futex_key_refs(&key1);
+
+out:
+       if (fshared)
+               up_read(fshared);
        return ret;
 }
 
@@ -670,22 +985,24 @@ out:
  * to this virtual address:
  */
 static int
-futex_wake_op(u32 __user *uaddr1, u32 __user *uaddr2,
+futex_wake_op(u32 __user *uaddr1, struct rw_semaphore *fshared,
+             u32 __user *uaddr2,
              int nr_wake, int nr_wake2, int op)
 {
        union futex_key key1, key2;
        struct futex_hash_bucket *hb1, *hb2;
-       struct list_head *head;
+       struct plist_head *head;
        struct futex_q *this, *next;
        int ret, op_ret, attempt = 0;
 
 retryfull:
-       down_read(&current->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr1, &key1);
+       ret = get_futex_key(uaddr1, fshared, &key1);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, &key2);
+       ret = get_futex_key(uaddr2, fshared, &key2);
        if (unlikely(ret != 0))
                goto out;
 
@@ -725,11 +1042,10 @@ retry:
                 * still holding the mmap_sem.
                 */
                if (attempt++) {
-                       if (futex_handle_fault((unsigned long)uaddr2,
-                                               attempt)) {
-                               ret = -EFAULT;
+                       ret = futex_handle_fault((unsigned long)uaddr2,
+                                               fshared, attempt);
+                       if (ret)
                                goto out;
-                       }
                        goto retry;
                }
 
@@ -737,7 +1053,8 @@ retry:
                 * If we would have faulted, release mmap_sem,
                 * fault it in and start all over again.
                 */
-               up_read(&current->mm->mmap_sem);
+               if (fshared)
+                       up_read(fshared);
 
                ret = get_user(dummy, uaddr2);
                if (ret)
@@ -748,7 +1065,7 @@ retry:
 
        head = &hb1->chain;
 
-       list_for_each_entry_safe(this, next, head, list) {
+       plist_for_each_entry_safe(this, next, head, list) {
                if (match_futex (&this->key, &key1)) {
                        wake_futex(this);
                        if (++ret >= nr_wake)
@@ -760,7 +1077,7 @@ retry:
                head = &hb2->chain;
 
                op_ret = 0;
-               list_for_each_entry_safe(this, next, head, list) {
+               plist_for_each_entry_safe(this, next, head, list) {
                        if (match_futex (&this->key, &key2)) {
                                wake_futex(this);
                                if (++op_ret >= nr_wake2)
@@ -774,7 +1091,8 @@ retry:
        if (hb1 != hb2)
                spin_unlock(&hb2->lock);
 out:
-       up_read(&current->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
        return ret;
 }
 
@@ -782,22 +1100,24 @@ out:
  * Requeue all waiters hashed on one physical page to another
  * physical page.
  */
-static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
+static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
+                        u32 __user *uaddr2,
                         int nr_wake, int nr_requeue, u32 *cmpval)
 {
        union futex_key key1, key2;
        struct futex_hash_bucket *hb1, *hb2;
-       struct list_head *head1;
+       struct plist_head *head1;
        struct futex_q *this, *next;
        int ret, drop_count = 0;
 
  retry:
-       down_read(&current->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr1, &key1);
+       ret = get_futex_key(uaddr1, fshared, &key1);
        if (unlikely(ret != 0))
                goto out;
-       ret = get_futex_key(uaddr2, &key2);
+       ret = get_futex_key(uaddr2, fshared, &key2);
        if (unlikely(ret != 0))
                goto out;
 
@@ -820,7 +1140,8 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
                         * If we would have faulted, release mmap_sem, fault
                         * it in and start all over again.
                         */
-                       up_read(&current->mm->mmap_sem);
+                       if (fshared)
+                               up_read(fshared);
 
                        ret = get_user(curval, uaddr1);
 
@@ -836,7 +1157,7 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
        }
 
        head1 = &hb1->chain;
-       list_for_each_entry_safe(this, next, head1, list) {
+       plist_for_each_entry_safe(this, next, head1, list) {
                if (!match_futex (&this->key, &key1))
                        continue;
                if (++ret <= nr_wake) {
@@ -847,9 +1168,13 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
                         * requeue.
                         */
                        if (likely(head1 != &hb2->chain)) {
-                               list_move_tail(&this->list, &hb2->chain);
+                               plist_del(&this->list, &hb1->chain);
+                               plist_add(&this->list, &hb2->chain);
                                this->lock_ptr = &hb2->lock;
-                       }
+#ifdef CONFIG_DEBUG_PI_LIST
+                               this->list.plist.lock = &hb2->lock;
+#endif
+                       }
                        this->key = key2;
                        get_futex_key_refs(&key2);
                        drop_count++;
@@ -869,7 +1194,8 @@ out_unlock:
                drop_futex_key_refs(&key1);
 
 out:
-       up_read(&current->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
        return ret;
 }
 
@@ -894,7 +1220,23 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
 
 static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
 {
-       list_add_tail(&q->list, &hb->chain);
+       int prio;
+
+       /*
+        * The priority used to register this element is
+        * - either the real thread-priority for the real-time threads
+        * (i.e. threads with a priority lower than MAX_RT_PRIO)
+        * - or MAX_RT_PRIO for non-RT threads.
+        * Thus, all RT-threads are woken first in priority order, and
+        * the others are woken last, in FIFO order.
+        */
+       prio = min(current->normal_prio, MAX_RT_PRIO);
+
+       plist_node_init(&q->list, prio);
+#ifdef CONFIG_DEBUG_PI_LIST
+       q->list.plist.lock = &hb->lock;
+#endif
+       plist_add(&q->list, &hb->chain);
        q->task = current;
        spin_unlock(&hb->lock);
 }
@@ -949,8 +1291,8 @@ static int unqueue_me(struct futex_q *q)
                        spin_unlock(lock_ptr);
                        goto retry;
                }
-               WARN_ON(list_empty(&q->list));
-               list_del(&q->list);
+               WARN_ON(plist_node_empty(&q->list));
+               plist_del(&q->list, &q->list.plist);
 
                BUG_ON(q->pi_state);
 
@@ -964,39 +1306,104 @@ static int unqueue_me(struct futex_q *q)
 
 /*
  * PI futexes can not be requeued and must remove themself from the
- * hash bucket. The hash bucket lock is held on entry and dropped here.
+ * hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
+ * and dropped here.
  */
-static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
+static void unqueue_me_pi(struct futex_q *q)
 {
-       WARN_ON(list_empty(&q->list));
-       list_del(&q->list);
+       WARN_ON(plist_node_empty(&q->list));
+       plist_del(&q->list, &q->list.plist);
 
        BUG_ON(!q->pi_state);
        free_pi_state(q->pi_state);
        q->pi_state = NULL;
 
-       spin_unlock(&hb->lock);
+       spin_unlock(q->lock_ptr);
 
        drop_futex_key_refs(&q->key);
 }
 
+/*
+ * Fixup the pi_state owner with current.
+ *
+ * The cur->mm semaphore must be  held, it is released at return of this
+ * function.
+ */
+static int fixup_pi_state_owner(u32 __user *uaddr, struct rw_semaphore *fshared,
+                               struct futex_q *q,
+                               struct futex_hash_bucket *hb,
+                               struct task_struct *curr)
+{
+       u32 newtid = curr->pid | FUTEX_WAITERS;
+       struct futex_pi_state *pi_state = q->pi_state;
+       u32 uval, curval, newval;
+       int ret;
+
+       /* Owner died? */
+       if (pi_state->owner != NULL) {
+               spin_lock_irq(&pi_state->owner->pi_lock);
+               WARN_ON(list_empty(&pi_state->list));
+               list_del_init(&pi_state->list);
+               spin_unlock_irq(&pi_state->owner->pi_lock);
+       } else
+               newtid |= FUTEX_OWNER_DIED;
+
+       pi_state->owner = curr;
+
+       spin_lock_irq(&curr->pi_lock);
+       WARN_ON(!list_empty(&pi_state->list));
+       list_add(&pi_state->list, &curr->pi_state_list);
+       spin_unlock_irq(&curr->pi_lock);
+
+       /* Unqueue and drop the lock */
+       unqueue_me_pi(q);
+       if (fshared)
+               up_read(fshared);
+       /*
+        * We own it, so we have to replace the pending owner
+        * TID. This must be atomic as we have preserve the
+        * owner died bit here.
+        */
+       ret = get_user(uval, uaddr);
+       while (!ret) {
+               newval = (uval & FUTEX_OWNER_DIED) | newtid;
+               newval |= (uval & FUTEX_WAITER_REQUEUED);
+               curval = futex_atomic_cmpxchg_inatomic(uaddr,
+                                                      uval, newval);
+               if (curval == -EFAULT)
+                       ret = -EFAULT;
+               if (curval == uval)
+                       break;
+               uval = curval;
+       }
+       return ret;
+}
+
+/*
+ * In case we must use restart_block to restart a futex_wait,
+ * we encode in the 'arg3' shared capability
+ */
+#define ARG3_SHARED  1
+
 static long futex_wait_restart(struct restart_block *restart);
-static int futex_wait_abstime(u32 __user *uaddr, u32 val,
-                       int timed, unsigned long abs_time)
+static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+                     u32 val, ktime_t *abs_time)
 {
        struct task_struct *curr = current;
        DECLARE_WAITQUEUE(wait, curr);
        struct futex_hash_bucket *hb;
        struct futex_q q;
-       unsigned long time_left = 0;
        u32 uval;
        int ret;
+       struct hrtimer_sleeper t, *to = NULL;
+       int rem = 0;
 
        q.pi_state = NULL;
  retry:
-       down_read(&curr->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr, &q.key);
+       ret = get_futex_key(uaddr, fshared, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
 
@@ -1019,8 +1426,8 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
         * a wakeup when *uaddr != val on entry to the syscall.  This is
         * rare, but normal.
         *
-        * We hold the mmap semaphore, so the mapping cannot have changed
-        * since we looked it up in get_futex_key.
+        * for shared futexes, we hold the mmap semaphore, so the mapping
+        * cannot have changed since we looked it up in get_futex_key.
         */
        ret = get_futex_value_locked(&uval, uaddr);
 
@@ -1031,7 +1438,8 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
                 * If we would have faulted, release mmap_sem, fault it in and
                 * start all over again.
                 */
-               up_read(&curr->mm->mmap_sem);
+               if (fshared)
+                       up_read(fshared);
 
                ret = get_user(uval, uaddr);
 
@@ -1043,6 +1451,14 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
        if (uval != val)
                goto out_unlock_release_sem;
 
+       /*
+        * This rt_mutex_waiter structure is prepared here and will
+        * be used only if this task is requeued from a normal futex to
+        * a PI-futex with futex_requeue_pi.
+        */
+       debug_rt_mutex_init_waiter(&q.waiter);
+       q.waiter.task = NULL;
+
        /* Only actually queue if *uaddr contained val.  */
        __queue_me(&q, hb);
 
@@ -1050,7 +1466,8 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
         * Now the futex is queued and we have checked the data, we
         * don't want to hold mmap_sem while we sleep.
         */
-       up_read(&curr->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
 
        /*
         * There might have been scheduling since the queue_me(), as we
@@ -1065,23 +1482,33 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
        __set_current_state(TASK_INTERRUPTIBLE);
        add_wait_queue(&q.waiters, &wait);
        /*
-        * !list_empty() is safe here without any lock.
+        * !plist_node_empty() is safe here without any lock.
         * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
         */
-       time_left = 0;
-       if (likely(!list_empty(&q.list))) {
-               unsigned long rel_time;
-
-               if (timed) {
-                       unsigned long now = jiffies;
-                       if (time_after(now, abs_time))
-                               rel_time = 0;
-                       else
-                               rel_time = abs_time - now;
-               } else
-                       rel_time = MAX_SCHEDULE_TIMEOUT;
+       if (likely(!plist_node_empty(&q.list))) {
+               if (!abs_time)
+                       schedule();
+               else {
+                       to = &t;
+                       hrtimer_init(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+                       hrtimer_init_sleeper(&t, current);
+                       t.timer.expires = *abs_time;
 
-               time_left = schedule_timeout(rel_time);
+                       hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+
+                       /*
+                        * the timer could have already expired, in which
+                        * case current would be flagged for rescheduling.
+                        * Don't bother calling schedule.
+                        */
+                       if (likely(t.task))
+                               schedule();
+
+                       hrtimer_cancel(&t.timer);
+
+                       /* Flag if a timeout occured */
+                       rem = (t.task == NULL);
+               }
        }
        __set_current_state(TASK_RUNNING);
 
@@ -1090,17 +1517,80 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
         * we are the only user of it.
         */
 
+       if (q.pi_state) {
+               /*
+                * We were woken but have been requeued on a PI-futex.
+                * We have to complete the lock acquisition by taking
+                * the rtmutex.
+                */
+
+               struct rt_mutex *lock = &q.pi_state->pi_mutex;
+
+               spin_lock(&lock->wait_lock);
+               if (unlikely(q.waiter.task)) {
+                       remove_waiter(lock, &q.waiter);
+               }
+               spin_unlock(&lock->wait_lock);
+
+               if (rem)
+                       ret = -ETIMEDOUT;
+               else
+                       ret = rt_mutex_timed_lock(lock, to, 1);
+
+               if (fshared)
+                       down_read(fshared);
+               spin_lock(q.lock_ptr);
+
+               /*
+                * Got the lock. We might not be the anticipated owner if we
+                * did a lock-steal - fix up the PI-state in that case.
+                */
+               if (!ret && q.pi_state->owner != curr) {
+                       /*
+                        * We MUST play with the futex we were requeued on,
+                        * NOT the current futex.
+                        * We can retrieve it from the key of the pi_state
+                        */
+                       uaddr = q.pi_state->key.uaddr;
+
+                       /* mmap_sem and hash_bucket lock are unlocked at
+                          return of this function */
+                       ret = fixup_pi_state_owner(uaddr, fshared,
+                                                  &q, hb, curr);
+               } else {
+                       /*
+                        * Catch the rare case, where the lock was released
+                        * when we were on the way back before we locked
+                        * the hash bucket.
+                        */
+                       if (ret && q.pi_state->owner == curr) {
+                               if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+                                       ret = 0;
+                       }
+                       /* Unqueue and drop the lock */
+                       unqueue_me_pi(&q);
+                       if (fshared)
+                               up_read(fshared);
+               }
+
+               debug_rt_mutex_free_waiter(&q.waiter);
+
+               return ret;
+       }
+
+       debug_rt_mutex_free_waiter(&q.waiter);
+
        /* If we were woken (and unqueued), we succeeded, whatever. */
        if (!unqueue_me(&q))
                return 0;
-       if (time_left == 0)
+       if (rem)
                return -ETIMEDOUT;
 
        /*
         * We expect signal_pending(current), but another thread may
         * have handled it for us already.
         */
-       if (time_left == MAX_SCHEDULE_TIMEOUT)
+       if (!abs_time)
                return -ERESTARTSYS;
        else {
                struct restart_block *restart;
@@ -1108,8 +1598,10 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
                restart->fn = futex_wait_restart;
                restart->arg0 = (unsigned long)uaddr;
                restart->arg1 = (unsigned long)val;
-               restart->arg2 = (unsigned long)timed;
-               restart->arg3 = abs_time;
+               restart->arg2 = (unsigned long)abs_time;
+               restart->arg3 = 0;
+               if (fshared)
+                       restart->arg3 |= ARG3_SHARED;
                return -ERESTART_RESTARTBLOCK;
        }
 
@@ -1117,65 +1609,111 @@ static int futex_wait_abstime(u32 __user *uaddr, u32 val,
        queue_unlock(&q, hb);
 
  out_release_sem:
-       up_read(&curr->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
        return ret;
 }
 
-static int futex_wait(u32 __user *uaddr, u32 val, unsigned long rel_time)
-{
-       int timed = (rel_time != MAX_SCHEDULE_TIMEOUT);
-       return futex_wait_abstime(uaddr, val, timed, jiffies+rel_time);
-}
 
 static long futex_wait_restart(struct restart_block *restart)
 {
        u32 __user *uaddr = (u32 __user *)restart->arg0;
        u32 val = (u32)restart->arg1;
-       int timed = (int)restart->arg2;
-       unsigned long abs_time = restart->arg3;
+       ktime_t *abs_time = (ktime_t *)restart->arg2;
+       struct rw_semaphore *fshared = NULL;
 
        restart->fn = do_no_restart_syscall;
-       return (long)futex_wait_abstime(uaddr, val, timed, abs_time);
+       if (restart->arg3 & ARG3_SHARED)
+               fshared = &current->mm->mmap_sem;
+       return (long)futex_wait(uaddr, fshared, val, abs_time);
 }
 
 
+static void set_pi_futex_owner(struct futex_hash_bucket *hb,
+                              union futex_key *key, struct task_struct *p)
+{
+       struct plist_head *head;
+       struct futex_q *this, *next;
+       struct futex_pi_state *pi_state = NULL;
+       struct rt_mutex *lock;
+
+       /* Search a waiter that should already exists */
+
+       head = &hb->chain;
+
+       plist_for_each_entry_safe(this, next, head, list) {
+               if (match_futex (&this->key, key)) {
+                       pi_state = this->pi_state;
+                       break;
+               }
+       }
+
+       BUG_ON(!pi_state);
+
+       /* set p as pi_state's owner */
+       lock = &pi_state->pi_mutex;
+
+       spin_lock(&lock->wait_lock);
+       spin_lock_irq(&p->pi_lock);
+
+       list_add(&pi_state->list, &p->pi_state_list);
+       pi_state->owner = p;
+
+
+       /* set p as pi_mutex's owner */
+       debug_rt_mutex_proxy_lock(lock, p);
+       WARN_ON(rt_mutex_owner(lock));
+       rt_mutex_set_owner(lock, p, 0);
+       rt_mutex_deadlock_account_lock(lock, p);
+
+       plist_add(&rt_mutex_top_waiter(lock)->pi_list_entry,
+                 &p->pi_waiters);
+       __rt_mutex_adjust_prio(p);
+
+       spin_unlock_irq(&p->pi_lock);
+       spin_unlock(&lock->wait_lock);
+}
+
 /*
  * Userspace tried a 0 -> TID atomic transition of the futex value
  * and failed. The kernel side here does the whole locking operation:
  * if there are waiters then it will block, it does PI, etc. (Due to
  * races the kernel might see a 0 value of the futex too.)
  */
-static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
-                        long nsec, int trylock)
+static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
+                        int detect, ktime_t *time, int trylock)
 {
        struct hrtimer_sleeper timeout, *to = NULL;
        struct task_struct *curr = current;
        struct futex_hash_bucket *hb;
        u32 uval, newval, curval;
        struct futex_q q;
-       int ret, attempt = 0;
+       int ret, lock_held, attempt = 0;
 
        if (refill_pi_state_cache())
                return -ENOMEM;
 
-       if (sec != MAX_SCHEDULE_TIMEOUT) {
+       if (time) {
                to = &timeout;
                hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
                hrtimer_init_sleeper(to, current);
-               to->timer.expires = ktime_set(sec, nsec);
+               to->timer.expires = *time;
        }
 
        q.pi_state = NULL;
  retry:
-       down_read(&curr->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr, &q.key);
+       ret = get_futex_key(uaddr, fshared, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
 
        hb = queue_lock(&q, -1, NULL);
 
  retry_locked:
+       lock_held = 0;
+
        /*
         * To avoid races, we attempt to take the lock here again
         * (by doing a 0 -> TID atomic cmpxchg), while holding all
@@ -1194,7 +1732,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
        if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
                if (!detect && 0)
                        force_sig(SIGKILL, current);
-               ret = -EDEADLK;
+               /*
+                * Normally, this check is done in user space.
+                * In case of requeue, the owner may attempt to lock this futex,
+                * even if the ownership has already been given by the previous
+                * waker.
+                * In the usual case, this is a case of deadlock, but not in case
+                * of REQUEUE_PI.
+                */
+               if (!(curval & FUTEX_WAITER_REQUEUED))
+                       ret = -EDEADLK;
                goto out_unlock_release_sem;
        }
 
@@ -1206,7 +1753,18 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
                goto out_unlock_release_sem;
 
        uval = curval;
-       newval = uval | FUTEX_WAITERS;
+       /*
+        * In case of a requeue, check if there already is an owner
+        * If not, just take the futex.
+        */
+       if ((curval & FUTEX_WAITER_REQUEUED) && !(curval & FUTEX_TID_MASK)) {
+               /* set current as futex owner */
+               newval = curval | current->pid;
+               lock_held = 1;
+       } else
+               /* Set the WAITERS flag, so the owner will know it has someone
+                  to wake at next unlock */
+               newval = curval | FUTEX_WAITERS;
 
        pagefault_disable();
        curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -1217,11 +1775,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
        if (unlikely(curval != uval))
                goto retry_locked;
 
+       if (lock_held) {
+               set_pi_futex_owner(hb, &q.key, curr);
+               goto out_unlock_release_sem;
+       }
+
        /*
         * We dont have the lock. Look up the PI state (or create it if
         * we are the first waiter):
         */
-       ret = lookup_pi_state(uval, hb, &q);
+       ret = lookup_pi_state(uval, hb, &q.key, &q.pi_state);
 
        if (unlikely(ret)) {
                /*
@@ -1263,7 +1826,8 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
         * Now the futex is queued and we have checked the data, we
         * don't want to hold mmap_sem while we sleep.
         */
-       up_read(&curr->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
 
        WARN_ON(!q.pi_state);
        /*
@@ -1277,52 +1841,18 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
                ret = ret ? 0 : -EWOULDBLOCK;
        }
 
-       down_read(&curr->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
        spin_lock(q.lock_ptr);
 
        /*
         * Got the lock. We might not be the anticipated owner if we
         * did a lock-steal - fix up the PI-state in that case.
         */
-       if (!ret && q.pi_state->owner != curr) {
-               u32 newtid = current->pid | FUTEX_WAITERS;
-
-               /* Owner died? */
-               if (q.pi_state->owner != NULL) {
-                       spin_lock_irq(&q.pi_state->owner->pi_lock);
-                       WARN_ON(list_empty(&q.pi_state->list));
-                       list_del_init(&q.pi_state->list);
-                       spin_unlock_irq(&q.pi_state->owner->pi_lock);
-               } else
-                       newtid |= FUTEX_OWNER_DIED;
-
-               q.pi_state->owner = current;
-
-               spin_lock_irq(&current->pi_lock);
-               WARN_ON(!list_empty(&q.pi_state->list));
-               list_add(&q.pi_state->list, &current->pi_state_list);
-               spin_unlock_irq(&current->pi_lock);
-
-               /* Unqueue and drop the lock */
-               unqueue_me_pi(&q, hb);
-               up_read(&curr->mm->mmap_sem);
-               /*
-                * We own it, so we have to replace the pending owner
-                * TID. This must be atomic as we have preserve the
-                * owner died bit here.
-                */
-               ret = get_user(uval, uaddr);
-               while (!ret) {
-                       newval = (uval & FUTEX_OWNER_DIED) | newtid;
-                       curval = futex_atomic_cmpxchg_inatomic(uaddr,
-                                                              uval, newval);
-                       if (curval == -EFAULT)
-                               ret = -EFAULT;
-                       if (curval == uval)
-                               break;
-                       uval = curval;
-               }
-       } else {
+       if (!ret && q.pi_state->owner != curr)
+               /* mmap_sem is unlocked at return of this function */
+               ret = fixup_pi_state_owner(uaddr, fshared, &q, hb, curr);
+       else {
                /*
                 * Catch the rare case, where the lock was released
                 * when we were on the way back before we locked
@@ -1333,8 +1863,9 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
                                ret = 0;
                }
                /* Unqueue and drop the lock */
-               unqueue_me_pi(&q, hb);
-               up_read(&curr->mm->mmap_sem);
+               unqueue_me_pi(&q);
+               if (fshared)
+                       up_read(fshared);
        }
 
        if (!detect && ret == -EDEADLK && 0)
@@ -1346,7 +1877,8 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
        queue_unlock(&q, hb);
 
  out_release_sem:
-       up_read(&curr->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
        return ret;
 
  uaddr_faulted:
@@ -1357,15 +1889,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
         * still holding the mmap_sem.
         */
        if (attempt++) {
-               if (futex_handle_fault((unsigned long)uaddr, attempt)) {
-                       ret = -EFAULT;
+               ret = futex_handle_fault((unsigned long)uaddr, fshared,
+                                        attempt);
+               if (ret)
                        goto out_unlock_release_sem;
-               }
                goto retry_locked;
        }
 
        queue_unlock(&q, hb);
-       up_read(&curr->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
 
        ret = get_user(uval, uaddr);
        if (!ret && (uval != -EFAULT))
@@ -1379,12 +1912,12 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
  * This is the in-kernel slowpath: we look up the PI state (if any),
  * and do the rt-mutex unlock.
  */
-static int futex_unlock_pi(u32 __user *uaddr)
+static int futex_unlock_pi(u32 __user *uaddr, struct rw_semaphore *fshared)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
        u32 uval;
-       struct list_head *head;
+       struct plist_head *head;
        union futex_key key;
        int ret, attempt = 0;
 
@@ -1399,9 +1932,10 @@ retry:
        /*
         * First take all the futex related locks:
         */
-       down_read(&current->mm->mmap_sem);
+       if (fshared)
+               down_read(fshared);
 
-       ret = get_futex_key(uaddr, &key);
+       ret = get_futex_key(uaddr, fshared, &key);
        if (unlikely(ret != 0))
                goto out;
 
@@ -1435,7 +1969,7 @@ retry_locked:
         */
        head = &hb->chain;
 
-       list_for_each_entry_safe(this, next, head, list) {
+       plist_for_each_entry_safe(this, next, head, list) {
                if (!match_futex (&this->key, &key))
                        continue;
                ret = wake_futex_pi(uaddr, uval, this);
@@ -1460,7 +1994,8 @@ retry_locked:
 out_unlock:
        spin_unlock(&hb->lock);
 out:
-       up_read(&current->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
 
        return ret;
 
@@ -1472,15 +2007,16 @@ pi_faulted:
         * still holding the mmap_sem.
         */
        if (attempt++) {
-               if (futex_handle_fault((unsigned long)uaddr, attempt)) {
-                       ret = -EFAULT;
+               ret = futex_handle_fault((unsigned long)uaddr, fshared,
+                                        attempt);
+               if (ret)
                        goto out_unlock;
-               }
                goto retry_locked;
        }
 
        spin_unlock(&hb->lock);
-       up_read(&current->mm->mmap_sem);
+       if (fshared)
+               up_read(fshared);
 
        ret = get_user(uval, uaddr);
        if (!ret && (uval != -EFAULT))
@@ -1509,10 +2045,10 @@ static unsigned int futex_poll(struct file *filp,
        poll_wait(filp, &q->waiters, wait);
 
        /*
-        * list_empty() is safe here without any lock.
+        * plist_node_empty() is safe here without any lock.
         * q->lock_ptr != 0 is not safe, because of ordering against wakeup.
         */
-       if (list_empty(&q->list))
+       if (plist_node_empty(&q->list))
                ret = POLLIN | POLLRDNORM;
 
        return ret;
@@ -1532,6 +2068,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
        struct futex_q *q;
        struct file *filp;
        int ret, err;
+       struct rw_semaphore *fshared;
        static unsigned long printk_interval;
 
        if (printk_timed_ratelimit(&printk_interval, 60 * 60 * 1000)) {
@@ -1573,11 +2110,12 @@ static int futex_fd(u32 __user *uaddr, int signal)
        }
        q->pi_state = NULL;
 
-       down_read(&current->mm->mmap_sem);
-       err = get_futex_key(uaddr, &q->key);
+       fshared = &current->mm->mmap_sem;
+       down_read(fshared);
+       err = get_futex_key(uaddr, fshared, &q->key);
 
        if (unlikely(err != 0)) {
-               up_read(&current->mm->mmap_sem);
+               up_read(fshared);
                kfree(q);
                goto error;
        }
@@ -1589,7 +2127,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
        filp->private_data = q;
 
        queue_me(q, ret, filp);
-       up_read(&current->mm->mmap_sem);
+       up_read(fshared);
 
        /* Now we map fd to filp, so userspace can access it */
        fd_install(ret, filp);
@@ -1702,6 +2240,8 @@ retry:
                 * userspace.
                 */
                mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
+               /* Also keep the FUTEX_WAITER_REQUEUED flag if set */
+               mval |= (uval & FUTEX_WAITER_REQUEUED);
                nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
 
                if (nval == -EFAULT)
@@ -1716,7 +2256,7 @@ retry:
                 */
                if (!pi) {
                        if (uval & FUTEX_WAITERS)
-                               futex_wake(uaddr, 1);
+                               futex_wake(uaddr, &curr->mm->mmap_sem, 1);
                }
        }
        return 0;
@@ -1772,7 +2312,8 @@ void exit_robust_list(struct task_struct *curr)
                return;
 
        if (pending)
-               handle_futex_death((void __user *)pending + futex_offset, curr, pip);
+               handle_futex_death((void __user *)pending + futex_offset,
+                                  curr, pip);
 
        while (entry != &head->list) {
                /*
@@ -1798,39 +2339,47 @@ void exit_robust_list(struct task_struct *curr)
        }
 }
 
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
                u32 __user *uaddr2, u32 val2, u32 val3)
 {
        int ret;
+       int cmd = op & FUTEX_CMD_MASK;
+       struct rw_semaphore *fshared = NULL;
+
+       if (!(op & FUTEX_PRIVATE_FLAG))
+               fshared = &current->mm->mmap_sem;
 
-       switch (op) {
+       switch (cmd) {
        case FUTEX_WAIT:
-               ret = futex_wait(uaddr, val, timeout);
+               ret = futex_wait(uaddr, fshared, val, timeout);
                break;
        case FUTEX_WAKE:
-               ret = futex_wake(uaddr, val);
+               ret = futex_wake(uaddr, fshared, val);
                break;
        case FUTEX_FD:
                /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
                ret = futex_fd(uaddr, val);
                break;
        case FUTEX_REQUEUE:
-               ret = futex_requeue(uaddr, uaddr2, val, val2, NULL);
+               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL);
                break;
        case FUTEX_CMP_REQUEUE:
-               ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
+               ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3);
                break;
        case FUTEX_WAKE_OP:
-               ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
+               ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3);
                break;
        case FUTEX_LOCK_PI:
-               ret = futex_lock_pi(uaddr, val, timeout, val2, 0);
+               ret = futex_lock_pi(uaddr, fshared, val, timeout, 0);
                break;
        case FUTEX_UNLOCK_PI:
-               ret = futex_unlock_pi(uaddr);
+               ret = futex_unlock_pi(uaddr, fshared);
                break;
        case FUTEX_TRYLOCK_PI:
-               ret = futex_lock_pi(uaddr, 0, timeout, val2, 1);
+               ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
+               break;
+       case FUTEX_CMP_REQUEUE_PI:
+               ret = futex_requeue_pi(uaddr, fshared, uaddr2, val, val2, &val3);
                break;
        default:
                ret = -ENOSYS;
@@ -1843,29 +2392,30 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
                          struct timespec __user *utime, u32 __user *uaddr2,
                          u32 val3)
 {
-       struct timespec t;
-       unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+       struct timespec ts;
+       ktime_t t, *tp = NULL;
        u32 val2 = 0;
+       int cmd = op & FUTEX_CMD_MASK;
 
-       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
-               if (copy_from_user(&t, utime, sizeof(t)) != 0)
+       if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+               if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
                        return -EFAULT;
-               if (!timespec_valid(&t))
+               if (!timespec_valid(&ts))
                        return -EINVAL;
-               if (op == FUTEX_WAIT)
-                       timeout = timespec_to_jiffies(&t) + 1;
-               else {
-                       timeout = t.tv_sec;
-                       val2 = t.tv_nsec;
-               }
+
+               t = timespec_to_ktime(ts);
+               if (cmd == FUTEX_WAIT)
+                       t = ktime_add(ktime_get(), t);
+               tp = &t;
        }
        /*
-        * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
+        * requeue parameter in 'utime' if cmd == FUTEX_REQUEUE.
         */
-       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+       if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE
+           || cmd == FUTEX_CMP_REQUEUE_PI)
                val2 = (u32) (unsigned long) utime;
 
-       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
 
 static int futexfs_get_sb(struct file_system_type *fs_type,
@@ -1895,7 +2445,7 @@ static int __init init(void)
        }
 
        for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
-               INIT_LIST_HEAD(&futex_queues[i].chain);
+               plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock);
                spin_lock_init(&futex_queues[i].lock);
        }
        return 0;
index 50f24eea6cd02916bd53d0ea09b1b8de668f8823..338a9b489fbc34fc2ca2ceeecd19f44f2889dd21 100644 (file)
@@ -141,24 +141,24 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
                struct compat_timespec __user *utime, u32 __user *uaddr2,
                u32 val3)
 {
-       struct timespec t;
-       unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+       struct timespec ts;
+       ktime_t t, *tp = NULL;
        int val2 = 0;
 
        if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
-               if (get_compat_timespec(&t, utime))
+               if (get_compat_timespec(&ts, utime))
                        return -EFAULT;
-               if (!timespec_valid(&t))
+               if (!timespec_valid(&ts))
                        return -EINVAL;
+
+               t = timespec_to_ktime(ts);
                if (op == FUTEX_WAIT)
-                       timeout = timespec_to_jiffies(&t) + 1;
-               else {
-                       timeout = t.tv_sec;
-                       val2 = t.tv_nsec;
-               }
+                       t = ktime_add(ktime_get(), t);
+               tp = &t;
        }
-       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+       if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE
+           || op == FUTEX_CMP_REQUEUE_PI)
                val2 = (int) (unsigned long) utime;
 
-       return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+       return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
 }
index c9f4f044a8a8f032e203c2bb81fb73fa1c98c212..23c03f43e1962d6f0dfa4cb8a716080cf671a48c 100644 (file)
@@ -1411,11 +1411,13 @@ static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
        switch (action) {
 
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                init_hrtimers_cpu(cpu);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu);
                migrate_hrtimers(cpu);
                break;
index 32e1ab1477d1a975e6f19713eca1d41277da7f80..e391cbb1f56665e4f751706403d69bd3bd86c471 100644 (file)
@@ -22,7 +22,6 @@
  * handle_bad_irq - handle spurious and unhandled irqs
  * @irq:       the interrupt number
  * @desc:      description of the interrupt
- * @regs:      pointer to a register structure
  *
  * Handles spurious and unhandled IRQ's. It also prints a debugmessage.
  */
index 49cc4b9c1a8d8ad8a0a602d7ea4cf0a6fe900a0b..4d32eb077179a2babd3f49b9f31631d4c6e27bb7 100644 (file)
@@ -135,7 +135,6 @@ static int ____call_usermodehelper(void *data)
 
        /* Unblock all signals and set the session keyring. */
        new_session = key_get(sub_info->ring);
-       flush_signals(current);
        spin_lock_irq(&current->sighand->siglock);
        old_session = __install_session_keyring(current, new_session);
        flush_signal_handlers(current, 1);
@@ -186,14 +185,9 @@ static int wait_for_helper(void *data)
 {
        struct subprocess_info *sub_info = data;
        pid_t pid;
-       struct k_sigaction sa;
 
        /* Install a handler: if SIGCLD isn't handled sys_wait4 won't
         * populate the status, but will return -ECHILD. */
-       sa.sa.sa_handler = SIG_IGN;
-       sa.sa.sa_flags = 0;
-       siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-       do_sigaction(SIGCHLD, &sa, NULL);
        allow_signal(SIGCHLD);
 
        pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
index 87c50ccd1d4e93850373d23c8d96b46a93cc0688..df8a8e8f6ca4fbb55d2da6770f9040d31de9cf0b 100644 (file)
@@ -1,7 +1,7 @@
 /* Kernel thread helper functions.
  *   Copyright (C) 2004 IBM Corporation, Rusty Russell.
  *
- * Creation is done via keventd, so that we get a clean environment
+ * Creation is done via kthreadd, so that we get a clean environment
  * even if we're invoked from userspace (think modprobe, hotplug cpu,
  * etc.).
  */
 #include <linux/mutex.h>
 #include <asm/semaphore.h>
 
-/*
- * We dont want to execute off keventd since it might
- * hold a semaphore our callers hold too:
- */
-static struct workqueue_struct *helper_wq;
+static DEFINE_SPINLOCK(kthread_create_lock);
+static LIST_HEAD(kthread_create_list);
+struct task_struct *kthreadd_task;
 
 struct kthread_create_info
 {
-       /* Information passed to kthread() from keventd. */
+       /* Information passed to kthread() from kthreadd. */
        int (*threadfn)(void *data);
        void *data;
        struct completion started;
 
-       /* Result passed back to kthread_create() from keventd. */
+       /* Result passed back to kthread_create() from kthreadd. */
        struct task_struct *result;
        struct completion done;
 
-       struct work_struct work;
+       struct list_head list;
 };
 
 struct kthread_stop_info
@@ -60,42 +58,17 @@ int kthread_should_stop(void)
 }
 EXPORT_SYMBOL(kthread_should_stop);
 
-static void kthread_exit_files(void)
-{
-       struct fs_struct *fs;
-       struct task_struct *tsk = current;
-
-       exit_fs(tsk);           /* current->fs->count--; */
-       fs = init_task.fs;
-       tsk->fs = fs;
-       atomic_inc(&fs->count);
-       exit_files(tsk);
-       current->files = init_task.files;
-       atomic_inc(&tsk->files->count);
-}
-
 static int kthread(void *_create)
 {
        struct kthread_create_info *create = _create;
        int (*threadfn)(void *data);
        void *data;
-       sigset_t blocked;
        int ret = -EINTR;
 
-       kthread_exit_files();
-
-       /* Copy data: it's on keventd's stack */
+       /* Copy data: it's on kthread's stack */
        threadfn = create->threadfn;
        data = create->data;
 
-       /* Block and flush all signals (in case we're not from keventd). */
-       sigfillset(&blocked);
-       sigprocmask(SIG_BLOCK, &blocked, NULL);
-       flush_signals(current);
-
-       /* By default we can run anywhere, unlike keventd. */
-       set_cpus_allowed(current, CPU_MASK_ALL);
-
        /* OK, tell user we're spawned, wait for stop or wakeup */
        __set_current_state(TASK_INTERRUPTIBLE);
        complete(&create->started);
@@ -112,11 +85,8 @@ static int kthread(void *_create)
        return 0;
 }
 
-/* We are keventd: create a thread. */
-static void keventd_create_kthread(struct work_struct *work)
+static void create_kthread(struct kthread_create_info *create)
 {
-       struct kthread_create_info *create =
-               container_of(work, struct kthread_create_info, work);
        int pid;
 
        /* We want our own signal handler (we take no signals by default). */
@@ -162,17 +132,14 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
        create.data = data;
        init_completion(&create.started);
        init_completion(&create.done);
-       INIT_WORK(&create.work, keventd_create_kthread);
-
-       /*
-        * The workqueue needs to start up first:
-        */
-       if (!helper_wq)
-               create.work.func(&create.work);
-       else {
-               queue_work(helper_wq, &create.work);
-               wait_for_completion(&create.done);
-       }
+
+       spin_lock(&kthread_create_lock);
+       list_add_tail(&create.list, &kthread_create_list);
+       wake_up_process(kthreadd_task);
+       spin_unlock(&kthread_create_lock);
+
+       wait_for_completion(&create.done);
+
        if (!IS_ERR(create.result)) {
                va_list args;
                va_start(args, namefmt);
@@ -180,7 +147,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
                          namefmt, args);
                va_end(args);
        }
-
        return create.result;
 }
 EXPORT_SYMBOL(kthread_create);
@@ -245,12 +211,47 @@ int kthread_stop(struct task_struct *k)
 }
 EXPORT_SYMBOL(kthread_stop);
 
-static __init int helper_init(void)
+
+static __init void kthreadd_setup(void)
 {
-       helper_wq = create_singlethread_workqueue("kthread");
-       BUG_ON(!helper_wq);
+       struct task_struct *tsk = current;
 
-       return 0;
+       set_task_comm(tsk, "kthreadd");
+
+       ignore_signals(tsk);
+
+       set_user_nice(tsk, -5);
+       set_cpus_allowed(tsk, CPU_MASK_ALL);
 }
 
-core_initcall(helper_init);
+int kthreadd(void *unused)
+{
+       /* Setup a clean context for our children to inherit. */
+       kthreadd_setup();
+
+       current->flags |= PF_NOFREEZE;
+
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (list_empty(&kthread_create_list))
+                       schedule();
+               __set_current_state(TASK_RUNNING);
+
+               spin_lock(&kthread_create_lock);
+               while (!list_empty(&kthread_create_list)) {
+                       struct kthread_create_info *create;
+
+                       create = list_entry(kthread_create_list.next,
+                                           struct kthread_create_info, list);
+                       list_del_init(&create->list);
+                       spin_unlock(&kthread_create_lock);
+
+                       create_kthread(create);
+
+                       spin_lock(&kthread_create_lock);
+               }
+               spin_unlock(&kthread_create_lock);
+       }
+
+       return 0;
+}
index d36e45477fac99ddf0426564b920ce98bc5855af..9bd93de01f4a95ab6abb0729401bf424cf5fab21 100644 (file)
@@ -96,9 +96,9 @@ static inline void add_taint_module(struct module *mod, unsigned flag)
        mod->taints |= flag;
 }
 
-/* A thread that wants to hold a reference to a module only while it
- * is running can call ths to safely exit.
- * nfsd and lockd use this.
+/*
+ * A thread that wants to hold a reference to a module only while it
+ * is running can call this to safely exit.  nfsd and lockd use this.
  */
 void __module_put_and_exit(struct module *mod, long code)
 {
@@ -1199,7 +1199,7 @@ static int __unlink_module(void *_mod)
        return 0;
 }
 
-/* Free a module, remove from lists, etc (must hold module mutex). */
+/* Free a module, remove from lists, etc (must hold module_mutex). */
 static void free_module(struct module *mod)
 {
        /* Delete from various lists */
@@ -1246,7 +1246,7 @@ EXPORT_SYMBOL_GPL(__symbol_get);
 
 /*
  * Ensure that an exported symbol [global namespace] does not already exist
- * in the Kernel or in some other modules exported symbol table.
+ * in the kernel or in some other module's exported symbol table.
  */
 static int verify_export_symbols(struct module *mod)
 {
index e7cbbb82765b4f66348e927fd2911ac4d9078078..303eab18484b1c63b7a678bf2b24a928cfc847fa 100644 (file)
@@ -133,7 +133,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
 
        debug_mutex_lock_common(lock, &waiter);
        mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
-       debug_mutex_add_waiter(lock, &waiter, task->thread_info);
+       debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
        /* add waiting tasks to the end of the waitqueue (FIFO): */
        list_add_tail(&waiter.list, &lock->wait_list);
@@ -159,7 +159,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
                 */
                if (unlikely(state == TASK_INTERRUPTIBLE &&
                                                signal_pending(task))) {
-                       mutex_remove_waiter(lock, &waiter, task->thread_info);
+                       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
                        mutex_release(&lock->dep_map, 1, _RET_IP_);
                        spin_unlock_mutex(&lock->wait_lock, flags);
 
@@ -175,8 +175,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
        }
 
        /* got the lock - rejoice! */
-       mutex_remove_waiter(lock, &waiter, task->thread_info);
-       debug_mutex_set_owner(lock, task->thread_info);
+       mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+       debug_mutex_set_owner(lock, task_thread_info(task));
 
        /* set it to 0 if there are no waiters left: */
        if (likely(list_empty(&lock->wait_list)))
index d3ad724afa8305548ff5c11b830032366a0592d2..eb66bd2953ab95f614781b12da75b4613ec0f757 100644 (file)
 #include <linux/bootmem.h>
 #include <linux/hash.h>
 #include <linux/pid_namespace.h>
+#include <linux/init_task.h>
 
 #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
 static struct hlist_head *pid_hash;
 static int pidhash_shift;
 static struct kmem_cache *pid_cachep;
+struct pid init_struct_pid = INIT_STRUCT_PID;
 
 int pid_max = PID_MAX_DEFAULT;
 
@@ -247,13 +249,16 @@ struct pid * fastcall find_pid(int nr)
 }
 EXPORT_SYMBOL_GPL(find_pid);
 
-int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr)
+/*
+ * attach_pid() must be called with the tasklist_lock write-held.
+ */
+int fastcall attach_pid(struct task_struct *task, enum pid_type type,
+               struct pid *pid)
 {
        struct pid_link *link;
-       struct pid *pid;
 
        link = &task->pids[type];
-       link->pid = pid = find_pid(nr);
+       link->pid = pid;
        hlist_add_head_rcu(&link->node, &pid->tasks[type]);
 
        return 0;
index 06331374d8624627e4071ca5df6b70cdf16c190b..b5f0543ed84d38bd44ceb96cb5efe3d0330d15e8 100644 (file)
@@ -30,30 +30,69 @@ char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
 
+enum {
+       HIBERNATION_INVALID,
+       HIBERNATION_PLATFORM,
+       HIBERNATION_TEST,
+       HIBERNATION_TESTPROC,
+       HIBERNATION_SHUTDOWN,
+       HIBERNATION_REBOOT,
+       /* keep last */
+       __HIBERNATION_AFTER_LAST
+};
+#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
+#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
+
+static int hibernation_mode = HIBERNATION_SHUTDOWN;
+
+struct hibernation_ops *hibernation_ops;
+
+/**
+ * hibernation_set_ops - set the global hibernate operations
+ * @ops: the hibernation operations to use in subsequent hibernation transitions
+ */
+
+void hibernation_set_ops(struct hibernation_ops *ops)
+{
+       if (ops && !(ops->prepare && ops->enter && ops->finish)) {
+               WARN_ON(1);
+               return;
+       }
+       mutex_lock(&pm_mutex);
+       hibernation_ops = ops;
+       if (ops)
+               hibernation_mode = HIBERNATION_PLATFORM;
+       else if (hibernation_mode == HIBERNATION_PLATFORM)
+               hibernation_mode = HIBERNATION_SHUTDOWN;
+
+       mutex_unlock(&pm_mutex);
+}
+
+
 /**
  *     platform_prepare - prepare the machine for hibernation using the
  *     platform driver if so configured and return an error code if it fails
  */
 
-static inline int platform_prepare(void)
+static int platform_prepare(void)
 {
-       int error = 0;
+       return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
+               hibernation_ops->prepare() : 0;
+}
 
-       switch (pm_disk_mode) {
-       case PM_DISK_TEST:
-       case PM_DISK_TESTPROC:
-       case PM_DISK_SHUTDOWN:
-       case PM_DISK_REBOOT:
-               break;
-       default:
-               if (pm_ops && pm_ops->prepare)
-                       error = pm_ops->prepare(PM_SUSPEND_DISK);
-       }
-       return error;
+/**
+ *     platform_finish - switch the machine to the normal mode of operation
+ *     using the platform driver (must be called after platform_prepare())
+ */
+
+static void platform_finish(void)
+{
+       if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
+               hibernation_ops->finish();
 }
 
 /**
- *     power_down - Shut machine down for hibernate.
+ *     power_down - Shut the machine down for hibernation.
  *
  *     Use the platform driver, if configured so; otherwise try
  *     to power off or reboot.
@@ -61,20 +100,20 @@ static inline int platform_prepare(void)
 
 static void power_down(void)
 {
-       switch (pm_disk_mode) {
-       case PM_DISK_TEST:
-       case PM_DISK_TESTPROC:
+       switch (hibernation_mode) {
+       case HIBERNATION_TEST:
+       case HIBERNATION_TESTPROC:
                break;
-       case PM_DISK_SHUTDOWN:
+       case HIBERNATION_SHUTDOWN:
                kernel_power_off();
                break;
-       case PM_DISK_REBOOT:
+       case HIBERNATION_REBOOT:
                kernel_restart(NULL);
                break;
-       default:
-               if (pm_ops && pm_ops->enter) {
+       case HIBERNATION_PLATFORM:
+               if (hibernation_ops) {
                        kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-                       pm_ops->enter(PM_SUSPEND_DISK);
+                       hibernation_ops->enter();
                        break;
                }
        }
@@ -87,20 +126,6 @@ static void power_down(void)
        while(1);
 }
 
-static inline void platform_finish(void)
-{
-       switch (pm_disk_mode) {
-       case PM_DISK_TEST:
-       case PM_DISK_TESTPROC:
-       case PM_DISK_SHUTDOWN:
-       case PM_DISK_REBOOT:
-               break;
-       default:
-               if (pm_ops && pm_ops->finish)
-                       pm_ops->finish(PM_SUSPEND_DISK);
-       }
-}
-
 static void unprepare_processes(void)
 {
        thaw_processes();
@@ -120,13 +145,10 @@ static int prepare_processes(void)
 }
 
 /**
- *     pm_suspend_disk - The granpappy of hibernation power management.
- *
- *     If not, then call swsusp to do its thing, then figure out how
- *     to power down the system.
+ *     hibernate - The granpappy of the built-in hibernation management
  */
 
-int pm_suspend_disk(void)
+int hibernate(void)
 {
        int error;
 
@@ -143,7 +165,8 @@ int pm_suspend_disk(void)
        if (error)
                goto Finish;
 
-       if (pm_disk_mode == PM_DISK_TESTPROC) {
+       mutex_lock(&pm_mutex);
+       if (hibernation_mode == HIBERNATION_TESTPROC) {
                printk("swsusp debug: Waiting for 5 seconds.\n");
                mdelay(5000);
                goto Thaw;
@@ -168,7 +191,7 @@ int pm_suspend_disk(void)
        if (error)
                goto Enable_cpus;
 
-       if (pm_disk_mode == PM_DISK_TEST) {
+       if (hibernation_mode == HIBERNATION_TEST) {
                printk("swsusp debug: Waiting for 5 seconds.\n");
                mdelay(5000);
                goto Enable_cpus;
@@ -205,6 +228,7 @@ int pm_suspend_disk(void)
        device_resume();
        resume_console();
  Thaw:
+       mutex_unlock(&pm_mutex);
        unprepare_processes();
  Finish:
        free_basic_memory_bitmaps();
@@ -220,7 +244,7 @@ int pm_suspend_disk(void)
  *     Called as a late_initcall (so all devices are discovered and
  *     initialized), we call swsusp to see if we have a saved image or not.
  *     If so, we quiesce devices, the restore the saved image. We will
- *     return above (in pm_suspend_disk() ) if everything goes well.
+ *     return above (in hibernate() ) if everything goes well.
  *     Otherwise, we fail gracefully and return to the normally
  *     scheduled program.
  *
@@ -315,25 +339,26 @@ static int software_resume(void)
 late_initcall(software_resume);
 
 
-static const char * const pm_disk_modes[] = {
-       [PM_DISK_PLATFORM]      = "platform",
-       [PM_DISK_SHUTDOWN]      = "shutdown",
-       [PM_DISK_REBOOT]        = "reboot",
-       [PM_DISK_TEST]          = "test",
-       [PM_DISK_TESTPROC]      = "testproc",
+static const char * const hibernation_modes[] = {
+       [HIBERNATION_PLATFORM]  = "platform",
+       [HIBERNATION_SHUTDOWN]  = "shutdown",
+       [HIBERNATION_REBOOT]    = "reboot",
+       [HIBERNATION_TEST]      = "test",
+       [HIBERNATION_TESTPROC]  = "testproc",
 };
 
 /**
- *     disk - Control suspend-to-disk mode
+ *     disk - Control hibernation mode
  *
  *     Suspend-to-disk can be handled in several ways. We have a few options
  *     for putting the system to sleep - using the platform driver (e.g. ACPI
- *     or other pm_ops), powering off the system or rebooting the system
- *     (for testing) as well as the two test modes.
+ *     or other hibernation_ops), powering off the system or rebooting the
+ *     system (for testing) as well as the two test modes.
  *
  *     The system can support 'platform', and that is known a priori (and
- *     encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot'
- *     as alternatives, as well as the test modes 'test' and 'testproc'.
+ *     encoded by the presence of hibernation_ops). However, the user may
+ *     choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
+ *     test modes, 'test' or 'testproc'.
  *
  *     show() will display what the mode is currently set to.
  *     store() will accept one of
@@ -345,7 +370,7 @@ static const char * const pm_disk_modes[] = {
  *     'testproc'
  *
  *     It will only change to 'platform' if the system
- *     supports it (as determined from pm_ops->pm_disk_mode).
+ *     supports it (as determined by having hibernation_ops).
  */
 
 static ssize_t disk_show(struct kset *kset, char *buf)
@@ -353,28 +378,25 @@ static ssize_t disk_show(struct kset *kset, char *buf)
        int i;
        char *start = buf;
 
-       for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
-               if (!pm_disk_modes[i])
+       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+               if (!hibernation_modes[i])
                        continue;
                switch (i) {
-               case PM_DISK_SHUTDOWN:
-               case PM_DISK_REBOOT:
-               case PM_DISK_TEST:
-               case PM_DISK_TESTPROC:
+               case HIBERNATION_SHUTDOWN:
+               case HIBERNATION_REBOOT:
+               case HIBERNATION_TEST:
+               case HIBERNATION_TESTPROC:
                        break;
-               default:
-                       if (pm_ops && pm_ops->enter &&
-                           (i == pm_ops->pm_disk_mode))
+               case HIBERNATION_PLATFORM:
+                       if (hibernation_ops)
                                break;
                        /* not a valid mode, continue with loop */
                        continue;
                }
-               if (i == pm_disk_mode)
-                       buf += sprintf(buf, "[%s]", pm_disk_modes[i]);
+               if (i == hibernation_mode)
+                       buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
                else
-                       buf += sprintf(buf, "%s", pm_disk_modes[i]);
-               if (i+1 != PM_DISK_MAX)
-                       buf += sprintf(buf, " ");
+                       buf += sprintf(buf, "%s ", hibernation_modes[i]);
        }
        buf += sprintf(buf, "\n");
        return buf-start;
@@ -387,39 +409,38 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
        int i;
        int len;
        char *p;
-       suspend_disk_method_t mode = 0;
+       int mode = HIBERNATION_INVALID;
 
        p = memchr(buf, '\n', n);
        len = p ? p - buf : n;
 
        mutex_lock(&pm_mutex);
-       for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) {
-               if (!strncmp(buf, pm_disk_modes[i], len)) {
+       for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+               if (!strncmp(buf, hibernation_modes[i], len)) {
                        mode = i;
                        break;
                }
        }
-       if (mode) {
+       if (mode != HIBERNATION_INVALID) {
                switch (mode) {
-               case PM_DISK_SHUTDOWN:
-               case PM_DISK_REBOOT:
-               case PM_DISK_TEST:
-               case PM_DISK_TESTPROC:
-                       pm_disk_mode = mode;
+               case HIBERNATION_SHUTDOWN:
+               case HIBERNATION_REBOOT:
+               case HIBERNATION_TEST:
+               case HIBERNATION_TESTPROC:
+                       hibernation_mode = mode;
                        break;
-               default:
-                       if (pm_ops && pm_ops->enter &&
-                           (mode == pm_ops->pm_disk_mode))
-                               pm_disk_mode = mode;
+               case HIBERNATION_PLATFORM:
+                       if (hibernation_ops)
+                               hibernation_mode = mode;
                        else
                                error = -EINVAL;
                }
-       } else {
+       } else
                error = -EINVAL;
-       }
 
-       pr_debug("PM: suspend-to-disk mode set to '%s'\n",
-                pm_disk_modes[mode]);
+       if (!error)
+               pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+                        hibernation_modes[mode]);
        mutex_unlock(&pm_mutex);
        return error ? error : n;
 }
index f6dda685e7e2b06bd0eb27631dd84dbf33e8c0ef..40d56a31245e96e7e70557faaea98de382286614 100644 (file)
@@ -30,7 +30,6 @@
 DEFINE_MUTEX(pm_mutex);
 
 struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
 
 /**
  *     pm_set_ops - Set the global power method table. 
@@ -41,10 +40,6 @@ void pm_set_ops(struct pm_ops * ops)
 {
        mutex_lock(&pm_mutex);
        pm_ops = ops;
-       if (ops && ops->pm_disk_mode != PM_DISK_INVALID) {
-               pm_disk_mode = ops->pm_disk_mode;
-       } else
-               pm_disk_mode = PM_DISK_SHUTDOWN;
        mutex_unlock(&pm_mutex);
 }
 
@@ -184,24 +179,12 @@ static void suspend_finish(suspend_state_t state)
 static const char * const pm_states[PM_SUSPEND_MAX] = {
        [PM_SUSPEND_STANDBY]    = "standby",
        [PM_SUSPEND_MEM]        = "mem",
-       [PM_SUSPEND_DISK]       = "disk",
 };
 
 static inline int valid_state(suspend_state_t state)
 {
-       /* Suspend-to-disk does not really need low-level support.
-        * It can work with shutdown/reboot if needed. If it isn't
-        * configured, then it cannot be supported.
-        */
-       if (state == PM_SUSPEND_DISK)
-#ifdef CONFIG_SOFTWARE_SUSPEND
-               return 1;
-#else
-               return 0;
-#endif
-
-       /* all other states need lowlevel support and need to be
-        * valid to the lowlevel implementation, no valid callback
+       /* All states need lowlevel support and need to be valid
+        * to the lowlevel implementation, no valid callback
         * implies that none are valid. */
        if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
                return 0;
@@ -229,11 +212,6 @@ static int enter_state(suspend_state_t state)
        if (!mutex_trylock(&pm_mutex))
                return -EBUSY;
 
-       if (state == PM_SUSPEND_DISK) {
-               error = pm_suspend_disk();
-               goto Unlock;
-       }
-
        pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
        if ((error = suspend_prepare(state)))
                goto Unlock;
@@ -251,7 +229,7 @@ static int enter_state(suspend_state_t state)
 
 /**
  *     pm_suspend - Externally visible function for suspending system.
- *     @state:         Enumarted value of state to enter.
+ *     @state:         Enumerated value of state to enter.
  *
  *     Determine whether or not value is within range, get state 
  *     structure, and enter (above).
@@ -289,7 +267,13 @@ static ssize_t state_show(struct kset *kset, char *buf)
                if (pm_states[i] && valid_state(i))
                        s += sprintf(s,"%s ", pm_states[i]);
        }
-       s += sprintf(s,"\n");
+#ifdef CONFIG_SOFTWARE_SUSPEND
+       s += sprintf(s, "%s\n", "disk");
+#else
+       if (s != buf)
+               /* convert the last space to a newline */
+               *(s-1) = '\n';
+#endif
        return (s - buf);
 }
 
@@ -304,6 +288,12 @@ static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
        p = memchr(buf, '\n', n);
        len = p ? p - buf : n;
 
+       /* First, check if we are requested to hibernate */
+       if (!strncmp(buf, "disk", len)) {
+               error = hibernate();
+               return error ? error : n;
+       }
+
        for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
                if (*s && !strncmp(buf, *s, len))
                        break;
index 34b43542785a3859d8e954858346aeb8d409f367..51381487103ff405263cb48983db8102ce7f73f8 100644 (file)
@@ -25,12 +25,7 @@ struct swsusp_info {
  */
 #define SPARE_PAGES    ((1024 * 1024) >> PAGE_SHIFT)
 
-extern int pm_suspend_disk(void);
-#else
-static inline int pm_suspend_disk(void)
-{
-       return -EPERM;
-}
+extern struct hibernation_ops *hibernation_ops;
 #endif
 
 extern int pfn_is_nosave(unsigned long);
index b7039772b05ca04a3d0fd67dfde40c31e9539f20..a3b7854b8f7c8ea2de21e8940e0f2f3be4ba50ca 100644 (file)
@@ -607,7 +607,8 @@ static LIST_HEAD(nosave_regions);
  */
 
 void __init
-register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
+__register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+                        int use_kmalloc)
 {
        struct nosave_region *region;
 
@@ -623,8 +624,13 @@ register_nosave_region(unsigned long start_pfn, unsigned long end_pfn)
                        goto Report;
                }
        }
-       /* This allocation cannot fail */
-       region = alloc_bootmem_low(sizeof(struct nosave_region));
+       if (use_kmalloc) {
+               /* during init, this shouldn't fail */
+               region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
+               BUG_ON(!region);
+       } else
+               /* This allocation cannot fail */
+               region = alloc_bootmem_low(sizeof(struct nosave_region));
        region->start_pfn = start_pfn;
        region->end_pfn = end_pfn;
        list_add_tail(&region->list, &nosave_regions);
@@ -1227,7 +1233,7 @@ asmlinkage int swsusp_save(void)
        nr_copy_pages = nr_pages;
        nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
 
-       printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages);
+       printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
 
        return 0;
 }
index 040560d9c3123b50502fdfd3dd0518e822086060..24d7d78e6f42ff71e95401b82460924709346f1a 100644 (file)
@@ -130,16 +130,16 @@ static inline int platform_prepare(void)
 {
        int error = 0;
 
-       if (pm_ops && pm_ops->prepare)
-               error = pm_ops->prepare(PM_SUSPEND_DISK);
+       if (hibernation_ops)
+               error = hibernation_ops->prepare();
 
        return error;
 }
 
 static inline void platform_finish(void)
 {
-       if (pm_ops && pm_ops->finish)
-               pm_ops->finish(PM_SUSPEND_DISK);
+       if (hibernation_ops)
+               hibernation_ops->finish();
 }
 
 static inline int snapshot_suspend(int platform_suspend)
@@ -384,7 +384,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                switch (arg) {
 
                case PMOPS_PREPARE:
-                       if (pm_ops && pm_ops->enter) {
+                       if (hibernation_ops) {
                                data->platform_suspend = 1;
                                error = 0;
                        } else {
@@ -395,8 +395,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
                case PMOPS_ENTER:
                        if (data->platform_suspend) {
                                kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
-                               error = pm_ops->enter(PM_SUSPEND_DISK);
-                               error = 0;
+                               error = hibernation_ops->enter();
                        }
                        break;
 
index 9bfadb248dd877b009e49710db79957f13188c5d..cc91b9bf759dc5723037d8ac4e2ab2e765372b16 100644 (file)
@@ -340,6 +340,7 @@ static int __devinit profile_cpu_callback(struct notifier_block *info,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                node = cpu_to_node(cpu);
                per_cpu(cpu_profile_flip, cpu) = 0;
                if (!per_cpu(cpu_profile_hits, cpu)[1]) {
@@ -365,10 +366,13 @@ static int __devinit profile_cpu_callback(struct notifier_block *info,
                __free_page(page);
                return NOTIFY_BAD;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                cpu_set(cpu, prof_cpu_mask);
                break;
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                cpu_clear(cpu, prof_cpu_mask);
                if (per_cpu(cpu_profile_hits, cpu)[0]) {
                        page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
index 3554b76da84cf08ebc2808b5f2a237a362e52330..2c2dd8410dc4fd8b27d0e66dcd31daceb56ff027 100644 (file)
@@ -558,9 +558,11 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
        long cpu = (long)hcpu;
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                rcu_online_cpu(cpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                rcu_offline_cpu(cpu);
                break;
        default:
index 577f251c7e28104f621d542a199169053a589c8b..4311101b0ca75a46206a2e9a50f82bffd5683fa5 100644 (file)
@@ -310,16 +310,13 @@ static struct rchan_callbacks default_channel_callbacks = {
 
 /**
  *     wakeup_readers - wake up readers waiting on a channel
- *     @work: work struct that contains the the channel buffer
+ *     @data: contains the channel buffer
  *
- *     This is the work function used to defer reader waking.  The
- *     reason waking is deferred is that calling directly from write
- *     causes problems if you're writing from say the scheduler.
+ *     This is the timer function used to defer reader waking.
  */
-static void wakeup_readers(struct work_struct *work)
+static void wakeup_readers(unsigned long data)
 {
-       struct rchan_buf *buf =
-               container_of(work, struct rchan_buf, wake_readers.work);
+       struct rchan_buf *buf = (struct rchan_buf *)data;
        wake_up_interruptible(&buf->read_wait);
 }
 
@@ -337,11 +334,9 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
        if (init) {
                init_waitqueue_head(&buf->read_wait);
                kref_init(&buf->kref);
-               INIT_DELAYED_WORK(&buf->wake_readers, NULL);
-       } else {
-               cancel_delayed_work(&buf->wake_readers);
-               flush_scheduled_work();
-       }
+               setup_timer(&buf->timer, wakeup_readers, (unsigned long)buf);
+       } else
+               del_timer_sync(&buf->timer);
 
        buf->subbufs_produced = 0;
        buf->subbufs_consumed = 0;
@@ -447,8 +442,7 @@ end:
 static void relay_close_buf(struct rchan_buf *buf)
 {
        buf->finalized = 1;
-       cancel_delayed_work(&buf->wake_readers);
-       flush_scheduled_work();
+       del_timer_sync(&buf->timer);
        kref_put(&buf->kref, relay_remove_buf);
 }
 
@@ -490,6 +484,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
 
        switch(action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                mutex_lock(&relay_channels_mutex);
                list_for_each_entry(chan, &relay_channels, list) {
                        if (chan->buf[hotcpu])
@@ -506,6 +501,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
                mutex_unlock(&relay_channels_mutex);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                /* No need to flush the cpu : will be flushed upon
                 * final relay_flush() call. */
                break;
@@ -608,11 +604,14 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
                buf->dentry->d_inode->i_size += buf->chan->subbuf_size -
                        buf->padding[old_subbuf];
                smp_mb();
-               if (waitqueue_active(&buf->read_wait)) {
-                       PREPARE_DELAYED_WORK(&buf->wake_readers,
-                                            wakeup_readers);
-                       schedule_delayed_work(&buf->wake_readers, 1);
-               }
+               if (waitqueue_active(&buf->read_wait))
+                       /*
+                        * Calling wake_up_interruptible() from here
+                        * will deadlock if we happen to be logging
+                        * from the scheduler (trying to re-grab
+                        * rq->lock), so defer it.
+                        */
+                       __mod_timer(&buf->timer, jiffies + 1);
        }
 
        old = buf->data;
index 180978cb2f7524b180863967be0391d32f47783d..12879f6c1ec3b9a53069690f0205082ea581565c 100644 (file)
@@ -56,7 +56,7 @@
  * state.
  */
 
-static void
+void
 rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
                   unsigned long mask)
 {
@@ -80,29 +80,6 @@ static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
                clear_rt_mutex_waiters(lock);
 }
 
-/*
- * We can speed up the acquire/release, if the architecture
- * supports cmpxchg and if there's no debugging state to be set up
- */
-#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
-# define rt_mutex_cmpxchg(l,c,n)       (cmpxchg(&l->owner, c, n) == c)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-       unsigned long owner, *p = (unsigned long *) &lock->owner;
-
-       do {
-               owner = *p;
-       } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
-}
-#else
-# define rt_mutex_cmpxchg(l,c,n)       (0)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
-       lock->owner = (struct task_struct *)
-                       ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
-}
-#endif
-
 /*
  * Calculate task priority from the waiter list priority
  *
@@ -123,7 +100,7 @@ int rt_mutex_getprio(struct task_struct *task)
  *
  * This can be both boosting and unboosting. task->pi_lock must be held.
  */
-static void __rt_mutex_adjust_prio(struct task_struct *task)
+void __rt_mutex_adjust_prio(struct task_struct *task)
 {
        int prio = rt_mutex_getprio(task);
 
@@ -159,11 +136,11 @@ int max_lock_depth = 1024;
  * Decreases task's usage by one - may thus free the task.
  * Returns 0 or -EDEADLK.
  */
-static int rt_mutex_adjust_prio_chain(struct task_struct *task,
-                                     int deadlock_detect,
-                                     struct rt_mutex *orig_lock,
-                                     struct rt_mutex_waiter *orig_waiter,
-                                     struct task_struct *top_task)
+int rt_mutex_adjust_prio_chain(struct task_struct *task,
+                              int deadlock_detect,
+                              struct rt_mutex *orig_lock,
+                              struct rt_mutex_waiter *orig_waiter,
+                              struct task_struct *top_task)
 {
        struct rt_mutex *lock;
        struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
@@ -524,8 +501,8 @@ static void wakeup_next_waiter(struct rt_mutex *lock)
  *
  * Must be called with lock->wait_lock held
  */
-static void remove_waiter(struct rt_mutex *lock,
-                         struct rt_mutex_waiter *waiter)
+void remove_waiter(struct rt_mutex *lock,
+                  struct rt_mutex_waiter *waiter)
 {
        int first = (waiter == rt_mutex_top_waiter(lock));
        struct task_struct *owner = rt_mutex_owner(lock);
index 9c75856e791ee91a0e34dbdc0079a8297c9574ff..242ec7ee740b0aae5b624c89df610084667c28b1 100644 (file)
@@ -112,6 +112,29 @@ static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
        return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING;
 }
 
+/*
+ * We can speed up the acquire/release, if the architecture
+ * supports cmpxchg and if there's no debugging state to be set up
+ */
+#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+# define rt_mutex_cmpxchg(l,c,n)       (cmpxchg(&l->owner, c, n) == c)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+       do {
+               owner = *p;
+       } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
+}
+#else
+# define rt_mutex_cmpxchg(l,c,n)       (0)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+       lock->owner = (struct task_struct *)
+                       ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
+}
+#endif
+
 /*
  * PI-futex support (proxy locking functions, etc.):
  */
@@ -120,4 +143,15 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
                                       struct task_struct *proxy_owner);
 extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
                                  struct task_struct *proxy_owner);
+
+extern void rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
+                              unsigned long mask);
+extern void __rt_mutex_adjust_prio(struct task_struct *task);
+extern int rt_mutex_adjust_prio_chain(struct task_struct *task,
+                                     int deadlock_detect,
+                                     struct rt_mutex *orig_lock,
+                                     struct rt_mutex_waiter *orig_waiter,
+                                     struct task_struct *top_task);
+extern void remove_waiter(struct rt_mutex *lock,
+                         struct rt_mutex_waiter *waiter);
 #endif
index a3a04085e79407a94a0fa79b8b2da7e77be33185..799d23b4e35dacf56e118d82953102db54c0fdfb 100644 (file)
@@ -169,7 +169,7 @@ unsigned long long __attribute__((weak)) sched_clock(void)
                (MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1))
 
 #define TASK_PREEMPTS_CURR(p, rq) \
-       (((p)->prio < (rq)->curr->prio) && ((p)->array == (rq)->active))
+       ((p)->prio < (rq)->curr->prio)
 
 #define SCALE_PRIO(x, prio) \
        max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
@@ -305,6 +305,7 @@ struct rq {
 };
 
 static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_MUTEX(sched_hotcpu_mutex);
 
 static inline int cpu_of(struct rq *rq)
 {
@@ -4076,13 +4077,13 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
        struct prio_array *array;
        unsigned long flags;
        struct rq *rq;
-       int delta;
+       int oldprio;
 
        BUG_ON(prio < 0 || prio > MAX_PRIO);
 
        rq = task_rq_lock(p, &flags);
 
-       delta = prio - p->prio;
+       oldprio = p->prio;
        array = p->array;
        if (array)
                dequeue_task(p, array);
@@ -4098,11 +4099,13 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
                enqueue_task(p, array);
                /*
                 * Reschedule if we are currently running on this runqueue and
-                * our priority decreased, or if our priority became higher
-                * than the current's.
+                * our priority decreased, or if we are not currently running on
+                * this runqueue and our priority is higher than the current's
                 */
-               if (TASK_PREEMPTS_CURR(p, rq) ||
-                               (delta > 0 && task_running(rq, p)))
+               if (task_running(rq, p)) {
+                       if (p->prio > oldprio)
+                               resched_task(rq->curr);
+               } else if (TASK_PREEMPTS_CURR(p, rq))
                        resched_task(rq->curr);
        }
        task_rq_unlock(rq, &flags);
@@ -4150,12 +4153,10 @@ void set_user_nice(struct task_struct *p, long nice)
                enqueue_task(p, array);
                inc_raw_weighted_load(rq, p);
                /*
-                * Reschedule if we are currently running on this runqueue and
-                * our priority decreased, or if our priority became higher
-                * than the current's.
+                * If the task increased its priority or is running and
+                * lowered its priority, then reschedule its CPU:
                 */
-               if (TASK_PREEMPTS_CURR(p, rq) ||
-                               (delta > 0 && task_running(rq, p)))
+               if (delta < 0 || (delta > 0 && task_running(rq, p)))
                        resched_task(rq->curr);
        }
 out_unlock:
@@ -4382,11 +4383,13 @@ recheck:
                __activate_task(p, rq);
                /*
                 * Reschedule if we are currently running on this runqueue and
-                * our priority decreased, or our priority became higher
-                * than the current's.
+                * our priority decreased, or if we are not currently running on
+                * this runqueue and our priority is higher than the current's
                 */
-               if (TASK_PREEMPTS_CURR(p, rq) ||
-                               (task_running(rq, p) && p->prio > oldprio))
+               if (task_running(rq, p)) {
+                       if (p->prio > oldprio)
+                               resched_task(rq->curr);
+               } else if (TASK_PREEMPTS_CURR(p, rq))
                        resched_task(rq->curr);
        }
        __task_rq_unlock(rq);
@@ -4518,13 +4521,13 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
        struct task_struct *p;
        int retval;
 
-       lock_cpu_hotplug();
+       mutex_lock(&sched_hotcpu_mutex);
        read_lock(&tasklist_lock);
 
        p = find_process_by_pid(pid);
        if (!p) {
                read_unlock(&tasklist_lock);
-               unlock_cpu_hotplug();
+               mutex_unlock(&sched_hotcpu_mutex);
                return -ESRCH;
        }
 
@@ -4551,7 +4554,7 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
 
 out_unlock:
        put_task_struct(p);
-       unlock_cpu_hotplug();
+       mutex_unlock(&sched_hotcpu_mutex);
        return retval;
 }
 
@@ -4608,7 +4611,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
        struct task_struct *p;
        int retval;
 
-       lock_cpu_hotplug();
+       mutex_lock(&sched_hotcpu_mutex);
        read_lock(&tasklist_lock);
 
        retval = -ESRCH;
@@ -4624,7 +4627,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
 
 out_unlock:
        read_unlock(&tasklist_lock);
-       unlock_cpu_hotplug();
+       mutex_unlock(&sched_hotcpu_mutex);
        if (retval)
                return retval;
 
@@ -5386,7 +5389,12 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        struct rq *rq;
 
        switch (action) {
+       case CPU_LOCK_ACQUIRE:
+               mutex_lock(&sched_hotcpu_mutex);
+               break;
+
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
                if (IS_ERR(p))
                        return NOTIFY_BAD;
@@ -5400,12 +5408,14 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
 
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                /* Strictly unneccessary, as first user will wake it. */
                wake_up_process(cpu_rq(cpu)->migration_thread);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                if (!cpu_rq(cpu)->migration_thread)
                        break;
                /* Unbind it from offline cpu so it can run.  Fall thru. */
@@ -5416,6 +5426,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
 
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                migrate_live_tasks(cpu);
                rq = cpu_rq(cpu);
                kthread_stop(rq->migration_thread);
@@ -5431,7 +5442,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                BUG_ON(rq->nr_running != 0);
 
                /* No need to migrate the tasks: it was best-effort if
-                * they didn't do lock_cpu_hotplug().  Just wake up
+                * they didn't take sched_hotcpu_mutex.  Just wake up
                 * the requestors. */
                spin_lock_irq(&rq->lock);
                while (!list_empty(&rq->migration_queue)) {
@@ -5445,6 +5456,9 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
                spin_unlock_irq(&rq->lock);
                break;
 #endif
+       case CPU_LOCK_RELEASE:
+               mutex_unlock(&sched_hotcpu_mutex);
+               break;
        }
        return NOTIFY_OK;
 }
@@ -6820,10 +6834,10 @@ int arch_reinit_sched_domains(void)
 {
        int err;
 
-       lock_cpu_hotplug();
+       mutex_lock(&sched_hotcpu_mutex);
        detach_destroy_domains(&cpu_online_map);
        err = arch_init_sched_domains(&cpu_online_map);
-       unlock_cpu_hotplug();
+       mutex_unlock(&sched_hotcpu_mutex);
 
        return err;
 }
@@ -6902,14 +6916,20 @@ static int update_sched_domains(struct notifier_block *nfb,
 {
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
        case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
                detach_destroy_domains(&cpu_online_map);
                return NOTIFY_OK;
 
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                /*
                 * Fall through and re-initialise the domains.
                 */
@@ -6928,12 +6948,12 @@ void __init sched_init_smp(void)
 {
        cpumask_t non_isolated_cpus;
 
-       lock_cpu_hotplug();
+       mutex_lock(&sched_hotcpu_mutex);
        arch_init_sched_domains(&cpu_online_map);
        cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map);
        if (cpus_empty(non_isolated_cpus))
                cpu_set(smp_processor_id(), non_isolated_cpus);
-       unlock_cpu_hotplug();
+       mutex_unlock(&sched_hotcpu_mutex);
        /* XXX: Theoretical race here - CPU may be hotplugged now */
        hotcpu_notifier(update_sched_domains, 0);
 
index 1368e67c84822a850c5cb8459a1c00a6609469d2..34b7d6abce8fd786161a2d5517377103d1a4b85b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/syscalls.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
+#include <linux/signalfd.h>
 #include <linux/capability.h>
 #include <linux/freezer.h>
 #include <linux/pid_namespace.h>
 
 static struct kmem_cache *sigqueue_cachep;
 
-/*
- * In POSIX a signal is sent either to a specific thread (Linux task)
- * or to the process as a whole (Linux thread group).  How the signal
- * is sent determines whether it's to one thread or the whole group,
- * which determines which signal mask(s) are involved in blocking it
- * from being delivered until later.  When the signal is delivered,
- * either it's caught or ignored by a user handler or it has a default
- * effect that applies to the whole thread group (POSIX process).
- *
- * The possible effects an unblocked signal set to SIG_DFL can have are:
- *   ignore    - Nothing Happens
- *   terminate - kill the process, i.e. all threads in the group,
- *               similar to exit_group.  The group leader (only) reports
- *               WIFSIGNALED status to its parent.
- *   coredump  - write a core dump file describing all threads using
- *               the same mm and then kill all those threads
- *   stop      - stop all the threads in the group, i.e. TASK_STOPPED state
- *
- * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
- * Other signals when not blocked and set to SIG_DFL behaves as follows.
- * The job control signals also have other special effects.
- *
- *     +--------------------+------------------+
- *     |  POSIX signal      |  default action  |
- *     +--------------------+------------------+
- *     |  SIGHUP            |  terminate       |
- *     |  SIGINT            |  terminate       |
- *     |  SIGQUIT           |  coredump        |
- *     |  SIGILL            |  coredump        |
- *     |  SIGTRAP           |  coredump        |
- *     |  SIGABRT/SIGIOT    |  coredump        |
- *     |  SIGBUS            |  coredump        |
- *     |  SIGFPE            |  coredump        |
- *     |  SIGKILL           |  terminate(+)    |
- *     |  SIGUSR1           |  terminate       |
- *     |  SIGSEGV           |  coredump        |
- *     |  SIGUSR2           |  terminate       |
- *     |  SIGPIPE           |  terminate       |
- *     |  SIGALRM           |  terminate       |
- *     |  SIGTERM           |  terminate       |
- *     |  SIGCHLD           |  ignore          |
- *     |  SIGCONT           |  ignore(*)       |
- *     |  SIGSTOP           |  stop(*)(+)      |
- *     |  SIGTSTP           |  stop(*)         |
- *     |  SIGTTIN           |  stop(*)         |
- *     |  SIGTTOU           |  stop(*)         |
- *     |  SIGURG            |  ignore          |
- *     |  SIGXCPU           |  coredump        |
- *     |  SIGXFSZ           |  coredump        |
- *     |  SIGVTALRM         |  terminate       |
- *     |  SIGPROF           |  terminate       |
- *     |  SIGPOLL/SIGIO     |  terminate       |
- *     |  SIGSYS/SIGUNUSED  |  coredump        |
- *     |  SIGSTKFLT         |  terminate       |
- *     |  SIGWINCH          |  ignore          |
- *     |  SIGPWR            |  terminate       |
- *     |  SIGRTMIN-SIGRTMAX |  terminate       |
- *     +--------------------+------------------+
- *     |  non-POSIX signal  |  default action  |
- *     +--------------------+------------------+
- *     |  SIGEMT            |  coredump        |
- *     +--------------------+------------------+
- *
- * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
- * (*) Special job control effects:
- * When SIGCONT is sent, it resumes the process (all threads in the group)
- * from TASK_STOPPED state and also clears any pending/queued stop signals
- * (any of those marked with "stop(*)").  This happens regardless of blocking,
- * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
- * any pending/queued SIGCONT signals; this happens regardless of blocking,
- * catching, or ignored the stop signal, though (except for SIGSTOP) the
- * default action of stopping the process may happen later or never.
- */
-
-#ifdef SIGEMT
-#define M_SIGEMT       M(SIGEMT)
-#else
-#define M_SIGEMT       0
-#endif
-
-#if SIGRTMIN > BITS_PER_LONG
-#define M(sig) (1ULL << ((sig)-1))
-#else
-#define M(sig) (1UL << ((sig)-1))
-#endif
-#define T(sig, mask) (M(sig) & (mask))
-
-#define SIG_KERNEL_ONLY_MASK (\
-       M(SIGKILL)   |  M(SIGSTOP)                                   )
-
-#define SIG_KERNEL_STOP_MASK (\
-       M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   )
-
-#define SIG_KERNEL_COREDUMP_MASK (\
-        M(SIGQUIT)   |  M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   | \
-        M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGBUS)    |  M(SIGSYS)    | \
-        M(SIGXCPU)   |  M(SIGXFSZ)   |  M_SIGEMT                     )
-
-#define SIG_KERNEL_IGNORE_MASK (\
-        M(SIGCONT)   |  M(SIGCHLD)   |  M(SIGWINCH)  |  M(SIGURG)    )
-
-#define sig_kernel_only(sig) \
-               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_ONLY_MASK))
-#define sig_kernel_coredump(sig) \
-               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_COREDUMP_MASK))
-#define sig_kernel_ignore(sig) \
-               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_IGNORE_MASK))
-#define sig_kernel_stop(sig) \
-               (((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_STOP_MASK))
-
-#define sig_needs_tasklist(sig)        ((sig) == SIGCONT)
-
-#define sig_user_defined(t, signr) \
-       (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&  \
-        ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
-
-#define sig_fatal(t, signr) \
-       (!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
-        (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
 static int sig_ignored(struct task_struct *t, int sig)
 {
@@ -232,8 +114,7 @@ void recalc_sigpending(void)
 
 /* Given the mask, find the first available signal that should be serviced. */
 
-static int
-next_signal(struct sigpending *pending, sigset_t *mask)
+int next_signal(struct sigpending *pending, sigset_t *mask)
 {
        unsigned long i, *s, *m, x;
        int sig = 0;
@@ -328,6 +209,16 @@ void flush_signals(struct task_struct *t)
        spin_unlock_irqrestore(&t->sighand->siglock, flags);
 }
 
+void ignore_signals(struct task_struct *t)
+{
+       int i;
+
+       for (i = 0; i < _NSIG; ++i)
+               t->sighand->action[i].sa.sa_handler = SIG_IGN;
+
+       flush_signals(t);
+}
+
 /*
  * Flush all handlers for a task.
  */
@@ -738,6 +629,12 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
        struct sigqueue * q = NULL;
        int ret = 0;
 
+       /*
+        * Deliver the signal to listening signalfds. This must be called
+        * with the sighand lock held.
+        */
+       signalfd_notify(t, sig);
+
        /*
         * fast-pathed signals for kernel-internal things like SIGSTOP
         * or SIGKILL.
@@ -1032,17 +929,6 @@ void zap_other_threads(struct task_struct *p)
                if (t->exit_state)
                        continue;
 
-               /*
-                * We don't want to notify the parent, since we are
-                * killed as part of a thread group due to another
-                * thread doing an execve() or similar. So set the
-                * exit signal to -1 to allow immediate reaping of
-                * the process.  But don't detach the thread group
-                * leader.
-                */
-               if (t != p->group_leader)
-                       t->exit_signal = -1;
-
                /* SIGKILL will be handled before any pending SIGSTOP */
                sigaddset(&t->pending.signal, SIGKILL);
                signal_wake_up(t, 1);
@@ -1400,6 +1286,11 @@ int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
                ret = 1;
                goto out;
        }
+       /*
+        * Deliver the signal to listening signalfds. This must be called
+        * with the sighand lock held.
+        */
+       signalfd_notify(p, sig);
 
        list_add_tail(&q->list, &p->pending.list);
        sigaddset(&p->pending.signal, sig);
@@ -1443,6 +1334,11 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
                q->info.si_overrun++;
                goto out;
        } 
+       /*
+        * Deliver the signal to listening signalfds. This must be called
+        * with the sighand lock held.
+        */
+       signalfd_notify(p, sig);
 
        /*
         * Put this signal on the shared-pending queue.
@@ -2103,6 +1999,8 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
        /*
         * If you change siginfo_t structure, please be sure
         * this code is fixed accordingly.
+        * Please remember to update the signalfd_copyinfo() function
+        * inside fs/signalfd.c too, in case siginfo_t changes.
         * It should never copy any pad contained in the structure
         * to avoid security leaks, but must copy the generic
         * 3 ints plus the relevant union member.
index 8b75008e2bd84bc91db15681896ab1a631091378..0b9886a00e74ba33ed59cafb8b02bc9d01570575 100644 (file)
@@ -593,6 +593,7 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk("ksoftirqd for %i failed\n", hotcpu);
@@ -602,16 +603,19 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
                per_cpu(ksoftirqd, hotcpu) = p;
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                wake_up_process(per_cpu(ksoftirqd, hotcpu));
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                if (!per_cpu(ksoftirqd, hotcpu))
                        break;
                /* Unbind so it can run.  Fall thru. */
                kthread_bind(per_cpu(ksoftirqd, hotcpu),
                             any_online_cpu(cpu_online_map));
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                p = per_cpu(ksoftirqd, hotcpu);
                per_cpu(ksoftirqd, hotcpu) = NULL;
                kthread_stop(p);
index 8fa7040247ad1971125916e3fe903581ecbc56c4..0131e296ffb416435f7c54a935657c624a09d0c5 100644 (file)
@@ -146,6 +146,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                BUG_ON(per_cpu(watchdog_task, hotcpu));
                p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
                if (IS_ERR(p)) {
@@ -157,16 +158,19 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                kthread_bind(p, hotcpu);
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                wake_up_process(per_cpu(watchdog_task, hotcpu));
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                if (!per_cpu(watchdog_task, hotcpu))
                        break;
                /* Unbind so it can run.  Fall thru. */
                kthread_bind(per_cpu(watchdog_task, hotcpu),
                             any_online_cpu(cpu_online_map));
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                p = per_cpu(watchdog_task, hotcpu);
                per_cpu(watchdog_task, hotcpu) = NULL;
                kthread_stop(p);
index daabb74ee0bc2648dda71286eb0331074af5f28b..fcee2a8e6da37a79a02a09a4dfaca30887098292 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/sched.h>
 #include <linux/stop_machine.h>
 #include <linux/syscalls.h>
+#include <linux/interrupt.h>
+
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -45,6 +47,7 @@ static int stopmachine(void *cpu)
                if (stopmachine_state == STOPMACHINE_DISABLE_IRQ 
                    && !irqs_disabled) {
                        local_irq_disable();
+                       hard_irq_disable();
                        irqs_disabled = 1;
                        /* Ack: irqs disabled. */
                        smp_mb(); /* Must read state first. */
@@ -124,6 +127,7 @@ static int stop_machine(void)
 
        /* Make them disable irqs. */
        local_irq_disable();
+       hard_irq_disable();
        stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
 
        return 0;
index 926bf9d7ac45d152ccf17c4f511724f9f5cb7ced..872271ccc3843989ad493ae4dc219b38bf30b15e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/prctl.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/resource.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
 #include <linux/workqueue.h>
@@ -29,6 +30,7 @@
 #include <linux/signal.h>
 #include <linux/cn_proc.h>
 #include <linux/getcpu.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -134,19 +136,39 @@ static int notifier_chain_unregister(struct notifier_block **nl,
        return -ENOENT;
 }
 
+/**
+ * notifier_call_chain - Informs the registered notifiers about an event.
+ *     @nl:            Pointer to head of the blocking notifier chain
+ *     @val:           Value passed unmodified to notifier function
+ *     @v:             Pointer passed unmodified to notifier function
+ *     @nr_to_call:    Number of notifier functions to be called. Don't care
+ *                     value of this parameter is -1.
+ *     @nr_calls:      Records the number of notifications sent. Don't care
+ *                     value of this field is NULL.
+ *     @returns:       notifier_call_chain returns the value returned by the
+ *                     last notifier function called.
+ */
+
 static int __kprobes notifier_call_chain(struct notifier_block **nl,
-               unsigned long val, void *v)
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
        struct notifier_block *nb, *next_nb;
 
        nb = rcu_dereference(*nl);
-       while (nb) {
+
+       while (nb && nr_to_call) {
                next_nb = rcu_dereference(nb->next);
                ret = nb->notifier_call(nb, val, v);
+
+               if (nr_calls)
+                       (*nr_calls)++;
+
                if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
                        break;
                nb = next_nb;
+               nr_to_call--;
        }
        return ret;
 }
@@ -205,10 +227,12 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
 
 /**
- *     atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *     __atomic_notifier_call_chain - Call functions in an atomic notifier chain
  *     @nh: Pointer to head of the atomic notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See the comment for notifier_call_chain.
+ *     @nr_calls: See the comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an atomic context, so they must not block.
@@ -222,19 +246,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-               unsigned long val, void *v)
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret;
 
        rcu_read_lock();
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        rcu_read_unlock();
        return ret;
 }
 
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
+
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+}
 
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 /*
  *     Blocking notifier chain routines.  All access to the chain is
  *     synchronized by an rwsem.
@@ -304,10 +336,12 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
 
 /**
- *     blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ *     __blocking_notifier_call_chain - Call functions in a blocking notifier chain
  *     @nh: Pointer to head of the blocking notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -320,8 +354,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-               unsigned long val, void *v)
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+                                  unsigned long val, void *v,
+                                  int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
 
@@ -332,12 +367,19 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
         */
        if (rcu_dereference(nh->head)) {
                down_read(&nh->rwsem);
-               ret = notifier_call_chain(&nh->head, val, v);
+               ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
+                                       nr_calls);
                up_read(&nh->rwsem);
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
 
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
 /*
@@ -383,10 +425,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
 
 /**
- *     raw_notifier_call_chain - Call functions in a raw notifier chain
+ *     __raw_notifier_call_chain - Call functions in a raw notifier chain
  *     @nh: Pointer to head of the raw notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an undefined context.
@@ -400,10 +444,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
  *     of the last notifier function called.
  */
 
+int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+                             unsigned long val, void *v,
+                             int nr_to_call, int *nr_calls)
+{
+       return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+}
+
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
+
 int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v)
 {
-       return notifier_call_chain(&nh->head, val, v);
+       return __raw_notifier_call_chain(nh, val, v, -1, NULL);
 }
 
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +531,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
 
 /**
- *     srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *     __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
  *     @nh: Pointer to head of the SRCU notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -494,18 +549,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
  *     of the last notifier function called.
  */
 
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-               unsigned long val, void *v)
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+                              unsigned long val, void *v,
+                              int nr_to_call, int *nr_calls)
 {
        int ret;
        int idx;
 
        idx = srcu_read_lock(&nh->srcu);
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        srcu_read_unlock(&nh->srcu, idx);
        return ret;
 }
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
 
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
 
 /**
@@ -598,7 +660,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
        int error = -EINVAL;
        struct pid *pgrp;
 
-       if (which > 2 || which < 0)
+       if (which > PRIO_USER || which < PRIO_PROCESS)
                goto out;
 
        /* normalize: avoid signed division (rounding problems) */
@@ -662,7 +724,7 @@ asmlinkage long sys_getpriority(int which, int who)
        long niceval, retval = -ESRCH;
        struct pid *pgrp;
 
-       if (which > 2 || which < 0)
+       if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
 
        read_lock(&tasklist_lock);
@@ -881,7 +943,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 #ifdef CONFIG_SOFTWARE_SUSPEND
        case LINUX_REBOOT_CMD_SW_SUSPEND:
                {
-                       int ret = pm_suspend(PM_SUSPEND_DISK);
+                       int ret = hibernate();
                        unlock_kernel();
                        return ret;
                }
@@ -1292,7 +1354,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
 }
 
 /*
- * Samma på svenska..
+ * Samma på svenska..
  */
 asmlinkage long sys_setfsgid(gid_t gid)
 {
@@ -1426,7 +1488,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        if (process_group(p) != pgid) {
                detach_pid(p, PIDTYPE_PGID);
                p->signal->pgrp = pgid;
-               attach_pid(p, PIDTYPE_PGID, pgid);
+               attach_pid(p, PIDTYPE_PGID, find_pid(pgid));
        }
 
        err = 0;
@@ -2022,6 +2084,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_nivcsw = p->signal->cnivcsw;
                        r->ru_minflt = p->signal->cmin_flt;
                        r->ru_majflt = p->signal->cmaj_flt;
+                       r->ru_inblock = p->signal->cinblock;
+                       r->ru_oublock = p->signal->coublock;
 
                        if (who == RUSAGE_CHILDREN)
                                break;
@@ -2033,6 +2097,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_nivcsw += p->signal->nivcsw;
                        r->ru_minflt += p->signal->min_flt;
                        r->ru_majflt += p->signal->maj_flt;
+                       r->ru_inblock += p->signal->inblock;
+                       r->ru_oublock += p->signal->oublock;
                        t = p;
                        do {
                                utime = cputime_add(utime, t->utime);
@@ -2041,6 +2107,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                                r->ru_nivcsw += t->nivcsw;
                                r->ru_minflt += t->min_flt;
                                r->ru_majflt += t->maj_flt;
+                               r->ru_inblock += task_io_get_inblock(t);
+                               r->ru_oublock += task_io_get_oublock(t);
                                t = next_thread(t);
                        } while (t != p);
                        break;
index d7306d0f3dfc76dd061c7dca24e83fa210b33adf..b6d77a8a1ca960ecf13c18d5c68efa03226ef1ed 100644 (file)
@@ -141,3 +141,8 @@ cond_syscall(compat_sys_migrate_pages);
 cond_syscall(sys_bdflush);
 cond_syscall(sys_ioprio_set);
 cond_syscall(sys_ioprio_get);
+
+/* New file descriptors */
+cond_syscall(sys_signalfd);
+cond_syscall(sys_timerfd);
+cond_syscall(sys_eventfd);
index f0664bd5011c5633fda89e87bcdace3dad6e3de0..4073353abd4f8d05a017931ce6119dc552238237 100644 (file)
@@ -77,6 +77,7 @@ extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
+extern int sysctl_stat_interval;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -857,6 +858,17 @@ static ctl_table vm_table[] = {
                .extra2         = &one_hundred,
        },
 #endif
+#ifdef CONFIG_SMP
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "stat_interval",
+               .data           = &sysctl_stat_interval,
+               .maxlen         = sizeof(sysctl_stat_interval),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_jiffies,
+               .strategy       = &sysctl_jiffies,
+       },
+#endif
 #if defined(CONFIG_X86_32) || \
    (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
        {
index fe5c7db2424700f8587284950cf8aecd926c06c6..3db5c3c460d74a845aa6f3ce0074cbd72a29f837 100644 (file)
@@ -74,15 +74,17 @@ static struct clocksource *watchdog;
 static struct timer_list watchdog_timer;
 static DEFINE_SPINLOCK(watchdog_lock);
 static cycle_t watchdog_last;
+static int watchdog_resumed;
+
 /*
- * Interval: 0.5sec Treshold: 0.0625s
+ * Interval: 0.5sec Threshold: 0.0625s
  */
 #define WATCHDOG_INTERVAL (HZ >> 1)
-#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4)
+#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)
 
 static void clocksource_ratewd(struct clocksource *cs, int64_t delta)
 {
-       if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD)
+       if (delta > -WATCHDOG_THRESHOLD && delta < WATCHDOG_THRESHOLD)
                return;
 
        printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
@@ -98,15 +100,26 @@ static void clocksource_watchdog(unsigned long data)
        struct clocksource *cs, *tmp;
        cycle_t csnow, wdnow;
        int64_t wd_nsec, cs_nsec;
+       int resumed;
 
        spin_lock(&watchdog_lock);
 
+       resumed = watchdog_resumed;
+       if (unlikely(resumed))
+               watchdog_resumed = 0;
+
        wdnow = watchdog->read();
        wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask);
        watchdog_last = wdnow;
 
        list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
                csnow = cs->read();
+
+               if (unlikely(resumed)) {
+                       cs->wd_last = csnow;
+                       continue;
+               }
+
                /* Initialized ? */
                if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
                        if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&
@@ -136,6 +149,13 @@ static void clocksource_watchdog(unsigned long data)
        }
        spin_unlock(&watchdog_lock);
 }
+static void clocksource_resume_watchdog(void)
+{
+       spin_lock(&watchdog_lock);
+       watchdog_resumed = 1;
+       spin_unlock(&watchdog_lock);
+}
+
 static void clocksource_check_watchdog(struct clocksource *cs)
 {
        struct clocksource *cse;
@@ -182,8 +202,33 @@ static void clocksource_check_watchdog(struct clocksource *cs)
        if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
                cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
 }
+
+static inline void clocksource_resume_watchdog(void) { }
 #endif
 
+/**
+ * clocksource_resume - resume the clocksource(s)
+ */
+void clocksource_resume(void)
+{
+       struct list_head *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clocksource_lock, flags);
+
+       list_for_each(tmp, &clocksource_list) {
+               struct clocksource *cs;
+
+               cs = list_entry(tmp, struct clocksource, list);
+               if (cs->resume)
+                       cs->resume();
+       }
+
+       clocksource_resume_watchdog();
+
+       spin_unlock_irqrestore(&clocksource_lock, flags);
+}
+
 /**
  * clocksource_get_next - Returns the selected clocksource
  *
index b734ca4bc75e2e80814b48602df3258058c69a0b..8bbcfb77f7d22acb65caa4343bffe3df573a4bcf 100644 (file)
@@ -65,7 +65,7 @@ print_timer(struct seq_file *m, struct hrtimer *timer, int idx, u64 now)
        SEQ_printf(m, ", %s/%d", tmp, timer->start_pid);
 #endif
        SEQ_printf(m, "\n");
-       SEQ_printf(m, " # expires at %Ld nsecs [in %Ld nsecs]\n",
+       SEQ_printf(m, " # expires at %Lu nsecs [in %Lu nsecs]\n",
                (unsigned long long)ktime_to_ns(timer->expires),
                (unsigned long long)(ktime_to_ns(timer->expires) - now));
 }
@@ -111,14 +111,14 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
 {
        SEQ_printf(m, "  .index:      %d\n",
                        base->index);
-       SEQ_printf(m, "  .resolution: %Ld nsecs\n",
+       SEQ_printf(m, "  .resolution: %Lu nsecs\n",
                        (unsigned long long)ktime_to_ns(base->resolution));
        SEQ_printf(m,   "  .get_time:   ");
        print_name_offset(m, base->get_time);
        SEQ_printf(m,   "\n");
 #ifdef CONFIG_HIGH_RES_TIMERS
-       SEQ_printf(m, "  .offset:     %Ld nsecs\n",
-                       ktime_to_ns(base->offset));
+       SEQ_printf(m, "  .offset:     %Lu nsecs\n",
+                  (unsigned long long) ktime_to_ns(base->offset));
 #endif
        SEQ_printf(m,   "active timers:\n");
        print_active_timers(m, base, now);
@@ -135,10 +135,11 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
                print_base(m, cpu_base->clock_base + i, now);
        }
 #define P(x) \
-       SEQ_printf(m, "  .%-15s: %Ld\n", #x, (u64)(cpu_base->x))
+       SEQ_printf(m, "  .%-15s: %Lu\n", #x, \
+                  (unsigned long long)(cpu_base->x))
 #define P_ns(x) \
-       SEQ_printf(m, "  .%-15s: %Ld nsecs\n", #x, \
-               (u64)(ktime_to_ns(cpu_base->x)))
+       SEQ_printf(m, "  .%-15s: %Lu nsecs\n", #x, \
+                  (unsigned long long)(ktime_to_ns(cpu_base->x)))
 
 #ifdef CONFIG_HIGH_RES_TIMERS
        P_ns(expires_next);
@@ -150,10 +151,11 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
 
 #ifdef CONFIG_TICK_ONESHOT
 # define P(x) \
-       SEQ_printf(m, "  .%-15s: %Ld\n", #x, (u64)(ts->x))
+       SEQ_printf(m, "  .%-15s: %Lu\n", #x, \
+                  (unsigned long long)(ts->x))
 # define P_ns(x) \
-       SEQ_printf(m, "  .%-15s: %Ld nsecs\n", #x, \
-               (u64)(ktime_to_ns(ts->x)))
+       SEQ_printf(m, "  .%-15s: %Lu nsecs\n", #x, \
+                  (unsigned long long)(ktime_to_ns(ts->x)))
        {
                struct tick_sched *ts = tick_get_tick_sched(cpu);
                P(nohz_mode);
@@ -167,7 +169,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
                P(last_jiffies);
                P(next_jiffies);
                P_ns(idle_expires);
-               SEQ_printf(m, "jiffies: %Ld\n", (u64)jiffies);
+               SEQ_printf(m, "jiffies: %Lu\n",
+                          (unsigned long long)jiffies);
        }
 #endif
 
index 7a6448340f9032d798cb470c0d028a5f13aaaa68..a6c580ac084b9b507ca994bf9f0fdddc679fb40d 100644 (file)
@@ -1293,11 +1293,13 @@ static int __cpuinit timer_cpu_notify(struct notifier_block *self,
        long cpu = (long)hcpu;
        switch(action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                if (init_timers_cpu(cpu) < 0)
                        return NOTIFY_BAD;
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                migrate_timers(cpu);
                break;
 #endif
@@ -1497,6 +1499,8 @@ unregister_time_interpolator(struct time_interpolator *ti)
                prev = &curr->next;
        }
 
+       clocksource_resume();
+
        write_seqlock_irqsave(&xtime_lock, flags);
        if (ti == time_interpolator) {
                /* we lost the best time-interpolator: */
index 59a82f63275df037dd5bfb1062cffe317a698383..444ddbfaefc490839e2cf913cb688c7ebb9f0df9 100644 (file)
@@ -61,7 +61,7 @@ EXPORT_SYMBOL(remove_wait_queue);
  * The spin_unlock() itself is semi-permeable and only protects
  * one way (it only protects stuff inside the critical region and
  * stops them from bleeding out - it would still allow subsequent
- * loads to move into the the critical region).
+ * loads to move into the critical region).
  */
 void fastcall
 prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
index b6fa5e63085d65b42f46fe97735751b6f402cab4..fb56fedd5c0274a3458bd0e7cbc8ae4e0d86cf6d 100644 (file)
 /*
  * The per-CPU workqueue (if single thread, we always use the first
  * possible cpu).
- *
- * The sequence counters are for flush_scheduled_work().  It wants to wait
- * until all currently-scheduled works are completed, but it doesn't
- * want to be livelocked by new, incoming ones.  So it waits until
- * remove_sequence is >= the insert_sequence which pertained when
- * flush_scheduled_work() was called.
  */
 struct cpu_workqueue_struct {
 
        spinlock_t lock;
 
-       long remove_sequence;   /* Least-recently added (next to run) */
-       long insert_sequence;   /* Next to add */
-
        struct list_head worklist;
        wait_queue_head_t more_work;
-       wait_queue_head_t work_done;
+       struct work_struct *current_work;
 
        struct workqueue_struct *wq;
        struct task_struct *thread;
+       int should_stop;
 
        int run_depth;          /* Detect run_workqueue() recursion depth */
-
-       int freezeable;         /* Freeze the thread during suspend */
 } ____cacheline_aligned;
 
 /*
@@ -68,8 +58,10 @@ struct cpu_workqueue_struct {
  */
 struct workqueue_struct {
        struct cpu_workqueue_struct *cpu_wq;
+       struct list_head list;
        const char *name;
-       struct list_head list;  /* Empty if single thread */
+       int singlethread;
+       int freezeable;         /* Freeze threads during suspend */
 };
 
 /* All the per-cpu workqueues on the system, for hotplug cpu to add/remove
@@ -77,106 +69,68 @@ struct workqueue_struct {
 static DEFINE_MUTEX(workqueue_mutex);
 static LIST_HEAD(workqueues);
 
-static int singlethread_cpu;
+static int singlethread_cpu __read_mostly;
+static cpumask_t cpu_singlethread_map __read_mostly;
+/* optimization, we could use cpu_possible_map */
+static cpumask_t cpu_populated_map __read_mostly;
 
 /* If it's single threaded, it isn't in the list of workqueues. */
 static inline int is_single_threaded(struct workqueue_struct *wq)
 {
-       return list_empty(&wq->list);
+       return wq->singlethread;
+}
+
+static const cpumask_t *wq_cpu_map(struct workqueue_struct *wq)
+{
+       return is_single_threaded(wq)
+               ? &cpu_singlethread_map : &cpu_populated_map;
+}
+
+static
+struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
+{
+       if (unlikely(is_single_threaded(wq)))
+               cpu = singlethread_cpu;
+       return per_cpu_ptr(wq->cpu_wq, cpu);
 }
 
 /*
  * Set the workqueue on which a work item is to be run
  * - Must *only* be called if the pending flag is set
  */
-static inline void set_wq_data(struct work_struct *work, void *wq)
+static inline void set_wq_data(struct work_struct *work,
+                               struct cpu_workqueue_struct *cwq)
 {
        unsigned long new;
 
        BUG_ON(!work_pending(work));
 
-       new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING);
+       new = (unsigned long) cwq | (1UL << WORK_STRUCT_PENDING);
        new |= WORK_STRUCT_FLAG_MASK & *work_data_bits(work);
        atomic_long_set(&work->data, new);
 }
 
-static inline void *get_wq_data(struct work_struct *work)
+static inline
+struct cpu_workqueue_struct *get_wq_data(struct work_struct *work)
 {
        return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
 }
 
-static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)
+static void insert_work(struct cpu_workqueue_struct *cwq,
+                               struct work_struct *work, int tail)
 {
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cwq->lock, flags);
+       set_wq_data(work, cwq);
        /*
-        * We need to re-validate the work info after we've gotten
-        * the cpu_workqueue lock. We can run the work now iff:
-        *
-        *  - the wq_data still matches the cpu_workqueue_struct
-        *  - AND the work is still marked pending
-        *  - AND the work is still on a list (which will be this
-        *    workqueue_struct list)
-        *
-        * All these conditions are important, because we
-        * need to protect against the work being run right
-        * now on another CPU (all but the last one might be
-        * true if it's currently running and has not been
-        * released yet, for example).
+        * Ensure that we get the right work->data if we see the
+        * result of list_add() below, see try_to_grab_pending().
         */
-       if (get_wq_data(work) == cwq
-           && work_pending(work)
-           && !list_empty(&work->entry)) {
-               work_func_t f = work->func;
-               list_del_init(&work->entry);
-               spin_unlock_irqrestore(&cwq->lock, flags);
-
-               if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
-                       work_release(work);
-               f(work);
-
-               spin_lock_irqsave(&cwq->lock, flags);
-               cwq->remove_sequence++;
-               wake_up(&cwq->work_done);
-               ret = 1;
-       }
-       spin_unlock_irqrestore(&cwq->lock, flags);
-       return ret;
-}
-
-/**
- * run_scheduled_work - run scheduled work synchronously
- * @work: work to run
- *
- * This checks if the work was pending, and runs it
- * synchronously if so. It returns a boolean to indicate
- * whether it had any scheduled work to run or not.
- *
- * NOTE! This _only_ works for normal work_structs. You
- * CANNOT use this for delayed work, because the wq data
- * for delayed work will not point properly to the per-
- * CPU workqueue struct, but will change!
- */
-int fastcall run_scheduled_work(struct work_struct *work)
-{
-       for (;;) {
-               struct cpu_workqueue_struct *cwq;
-
-               if (!work_pending(work))
-                       return 0;
-               if (list_empty(&work->entry))
-                       return 0;
-               /* NOTE! This depends intimately on __queue_work! */
-               cwq = get_wq_data(work);
-               if (!cwq)
-                       return 0;
-               if (__run_work(cwq, work))
-                       return 1;
-       }
+       smp_wmb();
+       if (tail)
+               list_add_tail(&work->entry, &cwq->worklist);
+       else
+               list_add(&work->entry, &cwq->worklist);
+       wake_up(&cwq->more_work);
 }
-EXPORT_SYMBOL(run_scheduled_work);
 
 /* Preempt must be disabled. */
 static void __queue_work(struct cpu_workqueue_struct *cwq,
@@ -185,10 +139,7 @@ static void __queue_work(struct cpu_workqueue_struct *cwq,
        unsigned long flags;
 
        spin_lock_irqsave(&cwq->lock, flags);
-       set_wq_data(work, cwq);
-       list_add_tail(&work->entry, &cwq->worklist);
-       cwq->insert_sequence++;
-       wake_up(&cwq->more_work);
+       insert_work(cwq, work, 1);
        spin_unlock_irqrestore(&cwq->lock, flags);
 }
 
@@ -204,16 +155,14 @@ static void __queue_work(struct cpu_workqueue_struct *cwq,
  */
 int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
 {
-       int ret = 0, cpu = get_cpu();
+       int ret = 0;
 
        if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
-               if (unlikely(is_single_threaded(wq)))
-                       cpu = singlethread_cpu;
                BUG_ON(!list_empty(&work->entry));
-               __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
+               __queue_work(wq_per_cpu(wq, get_cpu()), work);
+               put_cpu();
                ret = 1;
        }
-       put_cpu();
        return ret;
 }
 EXPORT_SYMBOL_GPL(queue_work);
@@ -221,13 +170,10 @@ EXPORT_SYMBOL_GPL(queue_work);
 void delayed_work_timer_fn(unsigned long __data)
 {
        struct delayed_work *dwork = (struct delayed_work *)__data;
-       struct workqueue_struct *wq = get_wq_data(&dwork->work);
-       int cpu = smp_processor_id();
+       struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work);
+       struct workqueue_struct *wq = cwq->wq;
 
-       if (unlikely(is_single_threaded(wq)))
-               cpu = singlethread_cpu;
-
-       __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), &dwork->work);
+       __queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work);
 }
 
 /**
@@ -241,27 +187,11 @@ void delayed_work_timer_fn(unsigned long __data)
 int fastcall queue_delayed_work(struct workqueue_struct *wq,
                        struct delayed_work *dwork, unsigned long delay)
 {
-       int ret = 0;
-       struct timer_list *timer = &dwork->timer;
-       struct work_struct *work = &dwork->work;
-
-       timer_stats_timer_set_start_info(timer);
+       timer_stats_timer_set_start_info(&dwork->timer);
        if (delay == 0)
-               return queue_work(wq, work);
-
-       if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
-               BUG_ON(timer_pending(timer));
-               BUG_ON(!list_empty(&work->entry));
+               return queue_work(wq, &dwork->work);
 
-               /* This stores wq for the moment, for the timer_fn */
-               set_wq_data(work, wq);
-               timer->expires = jiffies + delay;
-               timer->data = (unsigned long)dwork;
-               timer->function = delayed_work_timer_fn;
-               add_timer(timer);
-               ret = 1;
-       }
-       return ret;
+       return queue_delayed_work_on(-1, wq, dwork, delay);
 }
 EXPORT_SYMBOL_GPL(queue_delayed_work);
 
@@ -285,12 +215,16 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
                BUG_ON(timer_pending(timer));
                BUG_ON(!list_empty(&work->entry));
 
-               /* This stores wq for the moment, for the timer_fn */
-               set_wq_data(work, wq);
+               /* This stores cwq for the moment, for the timer_fn */
+               set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
                timer->expires = jiffies + delay;
                timer->data = (unsigned long)dwork;
                timer->function = delayed_work_timer_fn;
-               add_timer_on(timer, cpu);
+
+               if (unlikely(cpu >= 0))
+                       add_timer_on(timer, cpu);
+               else
+                       add_timer(timer);
                ret = 1;
        }
        return ret;
@@ -299,13 +233,7 @@ EXPORT_SYMBOL_GPL(queue_delayed_work_on);
 
 static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
-       unsigned long flags;
-
-       /*
-        * Keep taking off work from the queue until
-        * done.
-        */
-       spin_lock_irqsave(&cwq->lock, flags);
+       spin_lock_irq(&cwq->lock);
        cwq->run_depth++;
        if (cwq->run_depth > 3) {
                /* morton gets to eat his hat */
@@ -318,12 +246,12 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
                                                struct work_struct, entry);
                work_func_t f = work->func;
 
+               cwq->current_work = work;
                list_del_init(cwq->worklist.next);
-               spin_unlock_irqrestore(&cwq->lock, flags);
+               spin_unlock_irq(&cwq->lock);
 
                BUG_ON(get_wq_data(work) != cwq);
-               if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
-                       work_release(work);
+               work_clear_pending(work);
                f(work);
 
                if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
@@ -337,63 +265,81 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
                        dump_stack();
                }
 
-               spin_lock_irqsave(&cwq->lock, flags);
-               cwq->remove_sequence++;
-               wake_up(&cwq->work_done);
+               spin_lock_irq(&cwq->lock);
+               cwq->current_work = NULL;
        }
        cwq->run_depth--;
-       spin_unlock_irqrestore(&cwq->lock, flags);
+       spin_unlock_irq(&cwq->lock);
+}
+
+/*
+ * NOTE: the caller must not touch *cwq if this func returns true
+ */
+static int cwq_should_stop(struct cpu_workqueue_struct *cwq)
+{
+       int should_stop = cwq->should_stop;
+
+       if (unlikely(should_stop)) {
+               spin_lock_irq(&cwq->lock);
+               should_stop = cwq->should_stop && list_empty(&cwq->worklist);
+               if (should_stop)
+                       cwq->thread = NULL;
+               spin_unlock_irq(&cwq->lock);
+       }
+
+       return should_stop;
 }
 
 static int worker_thread(void *__cwq)
 {
        struct cpu_workqueue_struct *cwq = __cwq;
-       DECLARE_WAITQUEUE(wait, current);
-       struct k_sigaction sa;
-       sigset_t blocked;
+       DEFINE_WAIT(wait);
 
-       if (!cwq->freezeable)
+       if (!cwq->wq->freezeable)
                current->flags |= PF_NOFREEZE;
 
        set_user_nice(current, -5);
 
-       /* Block and flush all signals */
-       sigfillset(&blocked);
-       sigprocmask(SIG_BLOCK, &blocked, NULL);
-       flush_signals(current);
-
-       /*
-        * We inherited MPOL_INTERLEAVE from the booting kernel.
-        * Set MPOL_DEFAULT to insure node local allocations.
-        */
-       numa_default_policy();
-
-       /* SIG_IGN makes children autoreap: see do_notify_parent(). */
-       sa.sa.sa_handler = SIG_IGN;
-       sa.sa.sa_flags = 0;
-       siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
-       do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+       for (;;) {
+               prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
+               if (!freezing(current) && !cwq->should_stop
+                   && list_empty(&cwq->worklist))
+                       schedule();
+               finish_wait(&cwq->more_work, &wait);
 
-       set_current_state(TASK_INTERRUPTIBLE);
-       while (!kthread_should_stop()) {
-               if (cwq->freezeable)
-                       try_to_freeze();
+               try_to_freeze();
 
-               add_wait_queue(&cwq->more_work, &wait);
-               if (list_empty(&cwq->worklist))
-                       schedule();
-               else
-                       __set_current_state(TASK_RUNNING);
-               remove_wait_queue(&cwq->more_work, &wait);
+               if (cwq_should_stop(cwq))
+                       break;
 
-               if (!list_empty(&cwq->worklist))
-                       run_workqueue(cwq);
-               set_current_state(TASK_INTERRUPTIBLE);
+               run_workqueue(cwq);
        }
-       __set_current_state(TASK_RUNNING);
+
        return 0;
 }
 
+struct wq_barrier {
+       struct work_struct      work;
+       struct completion       done;
+};
+
+static void wq_barrier_func(struct work_struct *work)
+{
+       struct wq_barrier *barr = container_of(work, struct wq_barrier, work);
+       complete(&barr->done);
+}
+
+static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
+                                       struct wq_barrier *barr, int tail)
+{
+       INIT_WORK(&barr->work, wq_barrier_func);
+       __set_bit(WORK_STRUCT_PENDING, work_data_bits(&barr->work));
+
+       init_completion(&barr->done);
+
+       insert_work(cwq, &barr->work, tail);
+}
+
 static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
 {
        if (cwq->thread == current) {
@@ -403,21 +349,18 @@ static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
                 */
                run_workqueue(cwq);
        } else {
-               DEFINE_WAIT(wait);
-               long sequence_needed;
+               struct wq_barrier barr;
+               int active = 0;
 
                spin_lock_irq(&cwq->lock);
-               sequence_needed = cwq->insert_sequence;
-
-               while (sequence_needed - cwq->remove_sequence > 0) {
-                       prepare_to_wait(&cwq->work_done, &wait,
-                                       TASK_UNINTERRUPTIBLE);
-                       spin_unlock_irq(&cwq->lock);
-                       schedule();
-                       spin_lock_irq(&cwq->lock);
+               if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
+                       insert_wq_barrier(cwq, &barr, 1);
+                       active = 1;
                }
-               finish_wait(&cwq->work_done, &wait);
                spin_unlock_irq(&cwq->lock);
+
+               if (active)
+                       wait_for_completion(&barr.done);
        }
 }
 
@@ -428,151 +371,145 @@ static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
  * Forces execution of the workqueue and blocks until its completion.
  * This is typically used in driver shutdown handlers.
  *
- * This function will sample each workqueue's current insert_sequence number and
- * will sleep until the head sequence is greater than or equal to that.  This
- * means that we sleep until all works which were queued on entry have been
- * handled, but we are not livelocked by new incoming ones.
+ * We sleep until all works which were queued on entry have been handled,
+ * but we are not livelocked by new incoming ones.
  *
  * This function used to run the workqueues itself.  Now we just wait for the
  * helper threads to do it.
  */
 void fastcall flush_workqueue(struct workqueue_struct *wq)
 {
+       const cpumask_t *cpu_map = wq_cpu_map(wq);
+       int cpu;
+
        might_sleep();
+       for_each_cpu_mask(cpu, *cpu_map)
+               flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
+}
+EXPORT_SYMBOL_GPL(flush_workqueue);
 
-       if (is_single_threaded(wq)) {
-               /* Always use first cpu's area. */
-               flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
-       } else {
-               int cpu;
+/*
+ * Upon a successful return, the caller "owns" WORK_STRUCT_PENDING bit,
+ * so this work can't be re-armed in any way.
+ */
+static int try_to_grab_pending(struct work_struct *work)
+{
+       struct cpu_workqueue_struct *cwq;
+       int ret = 0;
 
-               mutex_lock(&workqueue_mutex);
-               for_each_online_cpu(cpu)
-                       flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
-               mutex_unlock(&workqueue_mutex);
+       if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work)))
+               return 1;
+
+       /*
+        * The queueing is in progress, or it is already queued. Try to
+        * steal it from ->worklist without clearing WORK_STRUCT_PENDING.
+        */
+
+       cwq = get_wq_data(work);
+       if (!cwq)
+               return ret;
+
+       spin_lock_irq(&cwq->lock);
+       if (!list_empty(&work->entry)) {
+               /*
+                * This work is queued, but perhaps we locked the wrong cwq.
+                * In that case we must see the new value after rmb(), see
+                * insert_work()->wmb().
+                */
+               smp_rmb();
+               if (cwq == get_wq_data(work)) {
+                       list_del_init(&work->entry);
+                       ret = 1;
+               }
        }
+       spin_unlock_irq(&cwq->lock);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(flush_workqueue);
 
-static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
-                                                  int cpu, int freezeable)
+static void wait_on_cpu_work(struct cpu_workqueue_struct *cwq,
+                               struct work_struct *work)
 {
-       struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-       struct task_struct *p;
+       struct wq_barrier barr;
+       int running = 0;
 
-       spin_lock_init(&cwq->lock);
-       cwq->wq = wq;
-       cwq->thread = NULL;
-       cwq->insert_sequence = 0;
-       cwq->remove_sequence = 0;
-       cwq->freezeable = freezeable;
-       INIT_LIST_HEAD(&cwq->worklist);
-       init_waitqueue_head(&cwq->more_work);
-       init_waitqueue_head(&cwq->work_done);
+       spin_lock_irq(&cwq->lock);
+       if (unlikely(cwq->current_work == work)) {
+               insert_wq_barrier(cwq, &barr, 0);
+               running = 1;
+       }
+       spin_unlock_irq(&cwq->lock);
 
-       if (is_single_threaded(wq))
-               p = kthread_create(worker_thread, cwq, "%s", wq->name);
-       else
-               p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
-       if (IS_ERR(p))
-               return NULL;
-       cwq->thread = p;
-       return p;
+       if (unlikely(running))
+               wait_for_completion(&barr.done);
 }
 
-struct workqueue_struct *__create_workqueue(const char *name,
-                                           int singlethread, int freezeable)
+static void wait_on_work(struct work_struct *work)
 {
-       int cpu, destroy = 0;
+       struct cpu_workqueue_struct *cwq;
        struct workqueue_struct *wq;
-       struct task_struct *p;
+       const cpumask_t *cpu_map;
+       int cpu;
 
-       wq = kzalloc(sizeof(*wq), GFP_KERNEL);
-       if (!wq)
-               return NULL;
+       might_sleep();
 
-       wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
-       if (!wq->cpu_wq) {
-               kfree(wq);
-               return NULL;
-       }
+       cwq = get_wq_data(work);
+       if (!cwq)
+               return;
 
-       wq->name = name;
-       mutex_lock(&workqueue_mutex);
-       if (singlethread) {
-               INIT_LIST_HEAD(&wq->list);
-               p = create_workqueue_thread(wq, singlethread_cpu, freezeable);
-               if (!p)
-                       destroy = 1;
-               else
-                       wake_up_process(p);
-       } else {
-               list_add(&wq->list, &workqueues);
-               for_each_online_cpu(cpu) {
-                       p = create_workqueue_thread(wq, cpu, freezeable);
-                       if (p) {
-                               kthread_bind(p, cpu);
-                               wake_up_process(p);
-                       } else
-                               destroy = 1;
-               }
-       }
-       mutex_unlock(&workqueue_mutex);
+       wq = cwq->wq;
+       cpu_map = wq_cpu_map(wq);
 
-       /*
-        * Was there any error during startup? If yes then clean up:
-        */
-       if (destroy) {
-               destroy_workqueue(wq);
-               wq = NULL;
-       }
-       return wq;
+       for_each_cpu_mask(cpu, *cpu_map)
+               wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
 }
-EXPORT_SYMBOL_GPL(__create_workqueue);
 
-static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
+/**
+ * cancel_work_sync - block until a work_struct's callback has terminated
+ * @work: the work which is to be flushed
+ *
+ * cancel_work_sync() will cancel the work if it is queued. If the work's
+ * callback appears to be running, cancel_work_sync() will block until it
+ * has completed.
+ *
+ * It is possible to use this function if the work re-queues itself. It can
+ * cancel the work even if it migrates to another workqueue, however in that
+ * case it only guarantees that work->func() has completed on the last queued
+ * workqueue.
+ *
+ * cancel_work_sync(&delayed_work->work) should be used only if ->timer is not
+ * pending, otherwise it goes into a busy-wait loop until the timer expires.
+ *
+ * The caller must ensure that workqueue_struct on which this work was last
+ * queued can't be destroyed before this function returns.
+ */
+void cancel_work_sync(struct work_struct *work)
 {
-       struct cpu_workqueue_struct *cwq;
-       unsigned long flags;
-       struct task_struct *p;
-
-       cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-       spin_lock_irqsave(&cwq->lock, flags);
-       p = cwq->thread;
-       cwq->thread = NULL;
-       spin_unlock_irqrestore(&cwq->lock, flags);
-       if (p)
-               kthread_stop(p);
+       while (!try_to_grab_pending(work))
+               cpu_relax();
+       wait_on_work(work);
+       work_clear_pending(work);
 }
+EXPORT_SYMBOL_GPL(cancel_work_sync);
 
 /**
- * destroy_workqueue - safely terminate a workqueue
- * @wq: target workqueue
+ * cancel_rearming_delayed_work - reliably kill off a delayed work.
+ * @dwork: the delayed work struct
  *
- * Safely destroy a workqueue. All work currently pending will be done first.
+ * It is possible to use this function if @dwork rearms itself via queue_work()
+ * or queue_delayed_work(). See also the comment for cancel_work_sync().
  */
-void destroy_workqueue(struct workqueue_struct *wq)
+void cancel_rearming_delayed_work(struct delayed_work *dwork)
 {
-       int cpu;
-
-       flush_workqueue(wq);
-
-       /* We don't need the distraction of CPUs appearing and vanishing. */
-       mutex_lock(&workqueue_mutex);
-       if (is_single_threaded(wq))
-               cleanup_workqueue_thread(wq, singlethread_cpu);
-       else {
-               for_each_online_cpu(cpu)
-                       cleanup_workqueue_thread(wq, cpu);
-               list_del(&wq->list);
-       }
-       mutex_unlock(&workqueue_mutex);
-       free_percpu(wq->cpu_wq);
-       kfree(wq);
+       while (!del_timer(&dwork->timer) &&
+              !try_to_grab_pending(&dwork->work))
+               cpu_relax();
+       wait_on_work(&dwork->work);
+       work_clear_pending(&dwork->work);
 }
-EXPORT_SYMBOL_GPL(destroy_workqueue);
+EXPORT_SYMBOL(cancel_rearming_delayed_work);
 
-static struct workqueue_struct *keventd_wq;
+static struct workqueue_struct *keventd_wq __read_mostly;
 
 /**
  * schedule_work - put work task in global workqueue
@@ -638,7 +575,7 @@ int schedule_on_each_cpu(work_func_t func)
        if (!works)
                return -ENOMEM;
 
-       mutex_lock(&workqueue_mutex);
+       preempt_disable();              /* CPU hotplug */
        for_each_online_cpu(cpu) {
                struct work_struct *work = per_cpu_ptr(works, cpu);
 
@@ -646,7 +583,7 @@ int schedule_on_each_cpu(work_func_t func)
                set_bit(WORK_STRUCT_PENDING, work_data_bits(work));
                __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work);
        }
-       mutex_unlock(&workqueue_mutex);
+       preempt_enable();
        flush_workqueue(keventd_wq);
        free_percpu(works);
        return 0;
@@ -658,29 +595,6 @@ void flush_scheduled_work(void)
 }
 EXPORT_SYMBOL(flush_scheduled_work);
 
-/**
- * cancel_rearming_delayed_workqueue - reliably kill off a delayed work whose handler rearms the delayed work.
- * @wq:   the controlling workqueue structure
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
-                                      struct delayed_work *dwork)
-{
-       while (!cancel_delayed_work(dwork))
-               flush_workqueue(wq);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_workqueue);
-
-/**
- * cancel_rearming_delayed_work - reliably kill off a delayed keventd work whose handler rearms the delayed work.
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_work(struct delayed_work *dwork)
-{
-       cancel_rearming_delayed_workqueue(keventd_wq, dwork);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_work);
-
 /**
  * execute_in_process_context - reliably execute the routine with user context
  * @fn:                the function to execute
@@ -728,94 +642,209 @@ int current_is_keventd(void)
 
 }
 
-/* Take the work from this (downed) CPU. */
-static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+static struct cpu_workqueue_struct *
+init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
 {
        struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
-       struct list_head list;
-       struct work_struct *work;
 
-       spin_lock_irq(&cwq->lock);
-       list_replace_init(&cwq->worklist, &list);
+       cwq->wq = wq;
+       spin_lock_init(&cwq->lock);
+       INIT_LIST_HEAD(&cwq->worklist);
+       init_waitqueue_head(&cwq->more_work);
+
+       return cwq;
+}
+
+static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+       struct workqueue_struct *wq = cwq->wq;
+       const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
+       struct task_struct *p;
+
+       p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
+       /*
+        * Nobody can add the work_struct to this cwq,
+        *      if (caller is __create_workqueue)
+        *              nobody should see this wq
+        *      else // caller is CPU_UP_PREPARE
+        *              cpu is not on cpu_online_map
+        * so we can abort safely.
+        */
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       cwq->thread = p;
+       cwq->should_stop = 0;
+
+       return 0;
+}
+
+static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+       struct task_struct *p = cwq->thread;
 
-       while (!list_empty(&list)) {
-               printk("Taking work for %s\n", wq->name);
-               work = list_entry(list.next,struct work_struct,entry);
-               list_del(&work->entry);
-               __queue_work(per_cpu_ptr(wq->cpu_wq, smp_processor_id()), work);
+       if (p != NULL) {
+               if (cpu >= 0)
+                       kthread_bind(p, cpu);
+               wake_up_process(p);
        }
-       spin_unlock_irq(&cwq->lock);
 }
 
-/* We're holding the cpucontrol mutex here */
-static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
-                                 unsigned long action,
-                                 void *hcpu)
+struct workqueue_struct *__create_workqueue(const char *name,
+                                           int singlethread, int freezeable)
 {
-       unsigned int hotcpu = (unsigned long)hcpu;
        struct workqueue_struct *wq;
+       struct cpu_workqueue_struct *cwq;
+       int err = 0, cpu;
 
-       switch (action) {
-       case CPU_UP_PREPARE:
-               mutex_lock(&workqueue_mutex);
-               /* Create a new workqueue thread for it. */
-               list_for_each_entry(wq, &workqueues, list) {
-                       if (!create_workqueue_thread(wq, hotcpu, 0)) {
-                               printk("workqueue for %i failed\n", hotcpu);
-                               return NOTIFY_BAD;
-                       }
-               }
-               break;
+       wq = kzalloc(sizeof(*wq), GFP_KERNEL);
+       if (!wq)
+               return NULL;
 
-       case CPU_ONLINE:
-               /* Kick off worker threads. */
-               list_for_each_entry(wq, &workqueues, list) {
-                       struct cpu_workqueue_struct *cwq;
+       wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
+       if (!wq->cpu_wq) {
+               kfree(wq);
+               return NULL;
+       }
 
-                       cwq = per_cpu_ptr(wq->cpu_wq, hotcpu);
-                       kthread_bind(cwq->thread, hotcpu);
-                       wake_up_process(cwq->thread);
-               }
-               mutex_unlock(&workqueue_mutex);
-               break;
+       wq->name = name;
+       wq->singlethread = singlethread;
+       wq->freezeable = freezeable;
+       INIT_LIST_HEAD(&wq->list);
 
-       case CPU_UP_CANCELED:
-               list_for_each_entry(wq, &workqueues, list) {
-                       if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
+       if (singlethread) {
+               cwq = init_cpu_workqueue(wq, singlethread_cpu);
+               err = create_workqueue_thread(cwq, singlethread_cpu);
+               start_workqueue_thread(cwq, -1);
+       } else {
+               mutex_lock(&workqueue_mutex);
+               list_add(&wq->list, &workqueues);
+
+               for_each_possible_cpu(cpu) {
+                       cwq = init_cpu_workqueue(wq, cpu);
+                       if (err || !cpu_online(cpu))
                                continue;
-                       /* Unbind so it can run. */
-                       kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
-                                    any_online_cpu(cpu_online_map));
-                       cleanup_workqueue_thread(wq, hotcpu);
+                       err = create_workqueue_thread(cwq, cpu);
+                       start_workqueue_thread(cwq, cpu);
                }
                mutex_unlock(&workqueue_mutex);
-               break;
+       }
+
+       if (err) {
+               destroy_workqueue(wq);
+               wq = NULL;
+       }
+       return wq;
+}
+EXPORT_SYMBOL_GPL(__create_workqueue);
+
+static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+       struct wq_barrier barr;
+       int alive = 0;
+
+       spin_lock_irq(&cwq->lock);
+       if (cwq->thread != NULL) {
+               insert_wq_barrier(cwq, &barr, 1);
+               cwq->should_stop = 1;
+               alive = 1;
+       }
+       spin_unlock_irq(&cwq->lock);
+
+       if (alive) {
+               wait_for_completion(&barr.done);
 
-       case CPU_DOWN_PREPARE:
+               while (unlikely(cwq->thread != NULL))
+                       cpu_relax();
+               /*
+                * Wait until cwq->thread unlocks cwq->lock,
+                * it won't touch *cwq after that.
+                */
+               smp_rmb();
+               spin_unlock_wait(&cwq->lock);
+       }
+}
+
+/**
+ * destroy_workqueue - safely terminate a workqueue
+ * @wq: target workqueue
+ *
+ * Safely destroy a workqueue. All work currently pending will be done first.
+ */
+void destroy_workqueue(struct workqueue_struct *wq)
+{
+       const cpumask_t *cpu_map = wq_cpu_map(wq);
+       struct cpu_workqueue_struct *cwq;
+       int cpu;
+
+       mutex_lock(&workqueue_mutex);
+       list_del(&wq->list);
+       mutex_unlock(&workqueue_mutex);
+
+       for_each_cpu_mask(cpu, *cpu_map) {
+               cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+               cleanup_workqueue_thread(cwq, cpu);
+       }
+
+       free_percpu(wq->cpu_wq);
+       kfree(wq);
+}
+EXPORT_SYMBOL_GPL(destroy_workqueue);
+
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+                                               unsigned long action,
+                                               void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+       struct cpu_workqueue_struct *cwq;
+       struct workqueue_struct *wq;
+
+       action &= ~CPU_TASKS_FROZEN;
+
+       switch (action) {
+       case CPU_LOCK_ACQUIRE:
                mutex_lock(&workqueue_mutex);
-               break;
+               return NOTIFY_OK;
 
-       case CPU_DOWN_FAILED:
+       case CPU_LOCK_RELEASE:
                mutex_unlock(&workqueue_mutex);
-               break;
+               return NOTIFY_OK;
 
-       case CPU_DEAD:
-               list_for_each_entry(wq, &workqueues, list)
-                       cleanup_workqueue_thread(wq, hotcpu);
-               list_for_each_entry(wq, &workqueues, list)
-                       take_over_work(wq, hotcpu);
-               mutex_unlock(&workqueue_mutex);
-               break;
+       case CPU_UP_PREPARE:
+               cpu_set(cpu, cpu_populated_map);
+       }
+
+       list_for_each_entry(wq, &workqueues, list) {
+               cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+
+               switch (action) {
+               case CPU_UP_PREPARE:
+                       if (!create_workqueue_thread(cwq, cpu))
+                               break;
+                       printk(KERN_ERR "workqueue for %i failed\n", cpu);
+                       return NOTIFY_BAD;
+
+               case CPU_ONLINE:
+                       start_workqueue_thread(cwq, cpu);
+                       break;
+
+               case CPU_UP_CANCELED:
+                       start_workqueue_thread(cwq, -1);
+               case CPU_DEAD:
+                       cleanup_workqueue_thread(cwq, cpu);
+                       break;
+               }
        }
 
        return NOTIFY_OK;
 }
 
-void init_workqueues(void)
+void __init init_workqueues(void)
 {
+       cpu_populated_map = cpu_online_map;
        singlethread_cpu = first_cpu(cpu_possible_map);
+       cpu_singlethread_map = cpumask_of_cpu(singlethread_cpu);
        hotcpu_notifier(workqueue_cpu_callback, 0);
        keventd_wq = create_workqueue("events");
        BUG_ON(!keventd_wq);
 }
-
index 96d6e8ca8b70c4c90ea4a96f182dd1af16a72043..2e7ae6b9215b2d390d30171c4e61e000f7079705 100644 (file)
@@ -23,6 +23,14 @@ config CRC16
          the kernel tree does. Such modules that use library CRC16
          functions require M here.
 
+config CRC_ITU_T
+       tristate "CRC ITU-T V.41 functions"
+       help
+         This option is provided for the case where no in-kernel-tree
+         modules require CRC ITU-T V.41 functions, but a module built outside
+         the kernel tree does. Such modules that use library CRC ITU-T V.41
+         functions require M here.
+
 config CRC32
        tristate "CRC32 functions"
        default y
index ae57f357fec07e0cf9d65fb3824d0bd193c37739..c8c8e20784cecf24aefc24406a164589ff020627 100644 (file)
@@ -13,7 +13,7 @@ lib-$(CONFIG_SMP) += cpumask.o
 lib-y  += kobject.o kref.o kobject_uevent.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
-        bust_spinlocks.o
+        bust_spinlocks.o hexdump.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
@@ -41,6 +41,7 @@ endif
 obj-$(CONFIG_BITREVERSE) += bitrev.o
 obj-$(CONFIG_CRC_CCITT)        += crc-ccitt.o
 obj-$(CONFIG_CRC16)    += crc16.o
+obj-$(CONFIG_CRC_ITU_T)        += crc-itu-t.o
 obj-$(CONFIG_CRC32)    += crc32.o
 obj-$(CONFIG_LIBCRC32C)        += libcrc32c.o
 obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
diff --git a/lib/crc-itu-t.c b/lib/crc-itu-t.c
new file mode 100644 (file)
index 0000000..a63472b
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *      crc-itu-t.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc-itu-t.h>
+
+/** CRC table for the CRC ITU-T V.41 0x0x1021 (x^16 + x^12 + x^15 + 1) */
+const u16 crc_itu_t_table[256] = {
+       0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+       0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+       0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+       0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+       0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+       0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+       0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+       0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+       0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+       0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+       0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+       0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+       0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+       0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+       0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+       0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+       0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+       0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+       0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+       0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+       0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+       0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+       0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+       0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+       0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+       0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+       0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+       0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+       0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+       0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+       0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+       0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+EXPORT_SYMBOL(crc_itu_t_table);
+
+/**
+ * crc_itu_t - Compute the CRC-ITU-T for the data buffer
+ *
+ * @crc:     previous CRC value
+ * @buffer:  data pointer
+ * @len:     number of bytes in the buffer
+ *
+ * Returns the updated CRC value
+ */
+u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len)
+{
+       while (len--)
+               crc = crc_itu_t_byte(crc, *buffer++);
+       return crc;
+}
+EXPORT_SYMBOL(crc_itu_t);
+
+MODULE_DESCRIPTION("CRC ITU-T V.41 calculations");
+MODULE_LICENSE("GPL");
+
diff --git a/lib/hexdump.c b/lib/hexdump.c
new file mode 100644 (file)
index 0000000..e6da5b7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * lib/hexdump.c
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/**
+ * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NUL
+ *
+ * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * 16 bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
+ * to a hex + ASCII dump at the supplied memory location.
+ * The converted output is always NUL-terminated.
+ *
+ * E.g.:
+ *     hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf));
+ *
+ * example output buffer:
+ * 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
+ */
+void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+                       size_t linebuflen)
+{
+       const u8 *ptr = buf;
+       u8 ch;
+       int j, lx = 0;
+
+       for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) {
+               if (j && !(j % 4))
+                       linebuf[lx++] = ' ';
+               ch = ptr[j];
+               linebuf[lx++] = hex_asc(ch >> 4);
+               linebuf[lx++] = hex_asc(ch & 0x0f);
+       }
+       if ((lx + 2) < linebuflen) {
+               linebuf[lx++] = ' ';
+               linebuf[lx++] = ' ';
+       }
+       for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++)
+               linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.';
+       linebuf[lx++] = '\0';
+}
+EXPORT_SYMBOL(hex_dump_to_buffer);
+
+/**
+ * print_hex_dump - print a text hex dump to syslog for a binary blob of data
+ * @level: kernel log level (e.g. KERN_DEBUG)
+ * @prefix_type: controls whether prefix of an offset, address, or none
+ *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ *
+ * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
+ * to the kernel log at the specified kernel log level, with an optional
+ * leading prefix.
+ *
+ * E.g.:
+ *   print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len);
+ *
+ * Example output using %DUMP_PREFIX_OFFSET:
+ * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f  @ABCDEFGHIJKLMNO
+ * Example output using %DUMP_PREFIX_ADDRESS:
+ * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f  pqrstuvwxyz{|}~.
+ */
+void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len)
+{
+       u8 *ptr = buf;
+       int i, linelen, remaining = len;
+       unsigned char linebuf[100];
+
+       for (i = 0; i < len; i += 16) {
+               linelen = min(remaining, 16);
+               remaining -= 16;
+               hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf));
+
+               switch (prefix_type) {
+               case DUMP_PREFIX_ADDRESS:
+                       printk("%s%*p: %s\n", level,
+                               (int)(2 * sizeof(void *)), ptr + i, linebuf);
+                       break;
+               case DUMP_PREFIX_OFFSET:
+                       printk("%s%.8x: %s\n", level, i, linebuf);
+                       break;
+               default:
+                       printk("%s%s\n", level, linebuf);
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL(print_hex_dump);
index d69ddbe438655be6b65672d2c7366371baadfd85..402eb4eb6b23634492245c4393a0c2829de81de0 100644 (file)
@@ -1004,7 +1004,7 @@ static int radix_tree_callback(struct notifier_block *nfb,
        struct radix_tree_preload *rtp;
 
        /* Free per-cpu pool of perloaded nodes */
-       if (action == CPU_DEAD) {
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
                rtp = &per_cpu(radix_tree_preloads, cpu);
                while (rtp->nr) {
                        kmem_cache_free(radix_tree_node_cachep,
index a4b730a2180cc129a46df390c4707ee247cf012f..5b0d8522b7ca16882b54cee337536a665cb825d0 100644 (file)
@@ -56,6 +56,7 @@ static DEFINE_MUTEX(rslistlock);
  * rs_init - Initialize a Reed-Solomon codec
  * @symsize:   symbol size, bits (1-8)
  * @gfpoly:    Field generator polynomial coefficients
+ * @gffunc:    Field generator function
  * @fcr:       first root of RS code generator polynomial, index form
  * @prim:      primitive element to generate polynomial roots
  * @nroots:    RS code generator polynomial degree (number of roots)
@@ -63,8 +64,8 @@ static DEFINE_MUTEX(rslistlock);
  * Allocate a control structure and the polynom arrays for faster
  * en/decoding. Fill the arrays according to the given parameters.
  */
-static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
-                                  int prim, int nroots)
+static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
+                                  int fcr, int prim, int nroots)
 {
        struct rs_control *rs;
        int i, j, sr, root, iprim;
@@ -82,6 +83,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
        rs->prim = prim;
        rs->nroots = nroots;
        rs->gfpoly = gfpoly;
+       rs->gffunc = gffunc;
 
        /* Allocate the arrays */
        rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
@@ -99,17 +101,26 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
        /* Generate Galois field lookup tables */
        rs->index_of[0] = rs->nn;       /* log(zero) = -inf */
        rs->alpha_to[rs->nn] = 0;       /* alpha**-inf = 0 */
-       sr = 1;
-       for (i = 0; i < rs->nn; i++) {
-               rs->index_of[sr] = i;
-               rs->alpha_to[i] = sr;
-               sr <<= 1;
-               if (sr & (1 << symsize))
-                       sr ^= gfpoly;
-               sr &= rs->nn;
+       if (gfpoly) {
+               sr = 1;
+               for (i = 0; i < rs->nn; i++) {
+                       rs->index_of[sr] = i;
+                       rs->alpha_to[i] = sr;
+                       sr <<= 1;
+                       if (sr & (1 << symsize))
+                               sr ^= gfpoly;
+                       sr &= rs->nn;
+               }
+       } else {
+               sr = gffunc(0);
+               for (i = 0; i < rs->nn; i++) {
+                       rs->index_of[sr] = i;
+                       rs->alpha_to[i] = sr;
+                       sr = gffunc(sr);
+               }
        }
        /* If it's not primitive, exit */
-       if(sr != 1)
+       if(sr != rs->alpha_to[0])
                goto errpol;
 
        /* Find prim-th root of 1, used in decoding */
@@ -173,18 +184,22 @@ void free_rs(struct rs_control *rs)
 }
 
 /**
- * init_rs - Find a matching or allocate a new rs control structure
+ * init_rs_internal - Find a matching or allocate a new rs control structure
  *  @symsize:  the symbol size (number of bits)
  *  @gfpoly:   the extended Galois field generator polynomial coefficients,
  *             with the 0th coefficient in the low order bit. The polynomial
  *             must be primitive;
+ *  @gffunc:   pointer to function to generate the next field element,
+ *             or the multiplicative identity element if given 0.  Used
+ *             instead of gfpoly if gfpoly is 0
  *  @fcr:      the first consecutive root of the rs code generator polynomial
  *             in index form
  *  @prim:     primitive element to generate polynomial roots
  *  @nroots:   RS code generator polynomial degree (number of roots)
  */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-                          int nroots)
+static struct rs_control *init_rs_internal(int symsize, int gfpoly,
+                                           int (*gffunc)(int), int fcr,
+                                           int prim, int nroots)
 {
        struct list_head        *tmp;
        struct rs_control       *rs;
@@ -208,6 +223,8 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                        continue;
                if (gfpoly != rs->gfpoly)
                        continue;
+               if (gffunc != rs->gffunc)
+                       continue;
                if (fcr != rs->fcr)
                        continue;
                if (prim != rs->prim)
@@ -220,7 +237,7 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
        }
 
        /* Create a new one */
-       rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
+       rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
        if (rs) {
                rs->users = 1;
                list_add(&rs->list, &rslist);
@@ -230,6 +247,42 @@ out:
        return rs;
 }
 
+/**
+ * init_rs - Find a matching or allocate a new rs control structure
+ *  @symsize:  the symbol size (number of bits)
+ *  @gfpoly:   the extended Galois field generator polynomial coefficients,
+ *             with the 0th coefficient in the low order bit. The polynomial
+ *             must be primitive;
+ *  @fcr:      the first consecutive root of the rs code generator polynomial
+ *             in index form
+ *  @prim:     primitive element to generate polynomial roots
+ *  @nroots:   RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
+                           int nroots)
+{
+       return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+}
+
+/**
+ * init_rs_non_canonical - Find a matching or allocate a new rs control
+ *                         structure, for fields with non-canonical
+ *                         representation
+ *  @symsize:  the symbol size (number of bits)
+ *  @gffunc:   pointer to function to generate the next field element,
+ *             or the multiplicative identity element if given 0.  Used
+ *             instead of gfpoly if gfpoly is 0
+ *  @fcr:      the first consecutive root of the rs code generator polynomial
+ *             in index form
+ *  @prim:     primitive element to generate polynomial roots
+ *  @nroots:   RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
+                                         int fcr, int prim, int nroots)
+{
+       return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+}
+
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
@@ -321,6 +374,7 @@ EXPORT_SYMBOL_GPL(decode_rs16);
 #endif
 
 EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
 EXPORT_SYMBOL_GPL(free_rs);
 
 MODULE_LICENSE("GPL");
index 1ac718f636ec6f5842217bd6b06c7ef0bff0dd21..a17da8bafe62758b6f0d86816d9d6c64b464e687 100644 (file)
@@ -166,5 +166,5 @@ config ZONE_DMA_FLAG
 config NR_QUICK
        int
        depends on QUICKLIST
+       default "2" if SUPERH
        default "1"
-
index 9cbf4fea4a5923b94743b3eda4db3b5a0086b974..7b48b2ad00e773853780c1dbc314b850307199cb 100644 (file)
@@ -750,6 +750,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
        read_unlock_irq(&mapping->tree_lock);
        return i;
 }
+EXPORT_SYMBOL(find_get_pages_contig);
 
 /**
  * find_get_pages_tag - find and return pages that match @tag
@@ -778,6 +779,7 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
        read_unlock_irq(&mapping->tree_lock);
        return ret;
 }
+EXPORT_SYMBOL(find_get_pages_tag);
 
 /**
  * grab_cache_page_nowait - returns locked page at given index in given cache
@@ -1782,7 +1784,7 @@ struct page *read_cache_page_async(struct address_space *mapping,
 retry:
        page = __read_cache_page(mapping, index, filler, data);
        if (IS_ERR(page))
-               goto out;
+               return page;
        mark_page_accessed(page);
        if (PageUptodate(page))
                goto out;
@@ -1800,9 +1802,9 @@ retry:
        err = filler(data, page);
        if (err < 0) {
                page_cache_release(page);
-               page = ERR_PTR(err);
+               return ERR_PTR(err);
        }
- out:
+out:
        mark_page_accessed(page);
        return page;
 }
index cbb335813ec01509ccf0b5525ccb1a3e0f51e1cc..1b49dab9b25d5d04aa3b98fdfc9b69de5f1d4acb 100644 (file)
@@ -434,7 +434,6 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
        unsigned blocksize;
        unsigned length;
        struct page *page;
-       void *kaddr;
 
        BUG_ON(!mapping->a_ops->get_xip_page);
 
@@ -458,11 +457,7 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
                else
                        return PTR_ERR(page);
        }
-       kaddr = kmap_atomic(page, KM_USER0);
-       memset(kaddr + offset, 0, length);
-       kunmap_atomic(kaddr, KM_USER0);
-
-       flush_dcache_page(page);
+       zero_user_page(page, offset, length, KM_USER0);
        return 0;
 }
 EXPORT_SYMBOL_GPL(xip_truncate_page);
index 36db012b38dde252c827d0af4719c2e7b79e5083..eb7180db303326f73f7e099f84e2557e84cc87b1 100644 (file)
@@ -140,6 +140,8 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        return page;
 
 fail:
+       if (vma->vm_flags & VM_MAYSHARE)
+               resv_huge_pages++;
        spin_unlock(&hugetlb_lock);
        return NULL;
 }
@@ -172,6 +174,17 @@ static int __init hugetlb_setup(char *s)
 }
 __setup("hugepages=", hugetlb_setup);
 
+static unsigned int cpuset_mems_nr(unsigned int *array)
+{
+       int node;
+       unsigned int nr = 0;
+
+       for_each_node_mask(node, cpuset_current_mems_allowed)
+               nr += array[node];
+
+       return nr;
+}
+
 #ifdef CONFIG_SYSCTL
 static void update_and_free_page(struct page *page)
 {
@@ -817,6 +830,26 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to)
        chg = region_chg(&inode->i_mapping->private_list, from, to);
        if (chg < 0)
                return chg;
+       /*
+        * When cpuset is configured, it breaks the strict hugetlb page
+        * reservation as the accounting is done on a global variable. Such
+        * reservation is completely rubbish in the presence of cpuset because
+        * the reservation is not checked against page availability for the
+        * current cpuset. Application can still potentially OOM'ed by kernel
+        * with lack of free htlb page in cpuset that the task is in.
+        * Attempt to enforce strict accounting with cpuset is almost
+        * impossible (or too ugly) because cpuset is too fluid that
+        * task or memory node can be dynamically moved between cpusets.
+        *
+        * The change of semantics for shared hugetlb mapping with cpuset is
+        * undesirable. However, in order to preserve some of the semantics,
+        * we fall back to check against current free page availability as
+        * a best attempt and hopefully to minimize the impact of changing
+        * semantics that cpuset has.
+        */
+       if (chg > cpuset_mems_nr(free_huge_pages_node))
+               return -ENOMEM;
+
        ret = hugetlb_acct_memory(chg);
        if (ret < 0)
                return ret;
index cc1f543eb1b85e1ddfce5927704f9763f3d74233..68b9ad2ef1d6917c28721419627fa9fd4a29e3b3 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1720,7 +1720,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
 
 /*
  * Split a vma into two pieces at address 'addr', a new vma is allocated
- * either for the first part or the the tail.
+ * either for the first part or the tail.
  */
 int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
              unsigned long addr, int new_below)
index 63cd88840eb2d0bf758de29265ba9426a6d20ab4..eec1481ba44f2ab1ec8b3d31b62ba244557b221f 100644 (file)
@@ -588,31 +588,27 @@ void __init page_writeback_init(void)
 }
 
 /**
- * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * write_cache_pages - walk the list of dirty pages of the given address space and write all of them.
  * @mapping: address space structure to write
  * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ * @writepage: function called for each page
+ * @data: data passed to writepage function
  *
- * This is a library function, which implements the writepages()
- * address_space_operation.
- *
- * If a page is already under I/O, generic_writepages() skips it, even
+ * If a page is already under I/O, write_cache_pages() skips it, even
  * if it's dirty.  This is desirable behaviour for memory-cleaning writeback,
  * but it is INCORRECT for data-integrity system calls such as fsync().  fsync()
  * and msync() need to guarantee that all the data which was dirty at the time
  * the call was made get new I/O started against them.  If wbc->sync_mode is
  * WB_SYNC_ALL then we were called for data integrity and we must wait for
  * existing IO to complete.
- *
- * Derived from mpage_writepages() - if you fix this you should check that
- * also!
  */
-int generic_writepages(struct address_space *mapping,
-                      struct writeback_control *wbc)
+int write_cache_pages(struct address_space *mapping,
+                     struct writeback_control *wbc, writepage_t writepage,
+                     void *data)
 {
        struct backing_dev_info *bdi = mapping->backing_dev_info;
        int ret = 0;
        int done = 0;
-       int (*writepage)(struct page *page, struct writeback_control *wbc);
        struct pagevec pvec;
        int nr_pages;
        pgoff_t index;
@@ -625,12 +621,6 @@ int generic_writepages(struct address_space *mapping,
                return 0;
        }
 
-       writepage = mapping->a_ops->writepage;
-
-       /* deal with chardevs and other special file */
-       if (!writepage)
-               return 0;
-
        pagevec_init(&pvec, 0);
        if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
@@ -682,8 +672,7 @@ retry:
                                continue;
                        }
 
-                       ret = (*writepage)(page, wbc);
-                       mapping_set_error(mapping, ret);
+                       ret = (*writepage)(page, wbc, data);
 
                        if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
                                unlock_page(page);
@@ -710,6 +699,38 @@ retry:
                mapping->writeback_index = index;
        return ret;
 }
+EXPORT_SYMBOL(write_cache_pages);
+
+/*
+ * Function used by generic_writepages to call the real writepage
+ * function and set the mapping flags on error
+ */
+static int __writepage(struct page *page, struct writeback_control *wbc,
+                      void *data)
+{
+       struct address_space *mapping = data;
+       int ret = mapping->a_ops->writepage(page, wbc);
+       mapping_set_error(mapping, ret);
+       return ret;
+}
+
+/**
+ * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * @mapping: address space structure to write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ *
+ * This is a library function, which implements the writepages()
+ * address_space_operation.
+ */
+int generic_writepages(struct address_space *mapping,
+                      struct writeback_control *wbc)
+{
+       /* deal with chardevs and other special file */
+       if (!mapping->a_ops->writepage)
+               return 0;
+
+       return write_cache_pages(mapping, wbc, __writepage, mapping);
+}
 
 EXPORT_SYMBOL(generic_writepages);
 
index 6fd0b7455b0be26a476a72ff229794b4f64c8d85..ae96dd8444323e679d3d530e3f6150b1dde11e2e 100644 (file)
@@ -691,43 +691,26 @@ static void __init setup_nr_node_ids(void) {}
 
 #ifdef CONFIG_NUMA
 /*
- * Called from the slab reaper to drain pagesets on a particular node that
- * belongs to the currently executing processor.
+ * Called from the vmstat counter updater to drain pagesets of this
+ * currently executing processor on remote nodes after they have
+ * expired.
+ *
  * Note that this function must be called with the thread pinned to
  * a single processor.
  */
-void drain_node_pages(int nodeid)
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
 {
-       int i;
-       enum zone_type z;
        unsigned long flags;
+       int to_drain;
 
-       for (z = 0; z < MAX_NR_ZONES; z++) {
-               struct zone *zone = NODE_DATA(nodeid)->node_zones + z;
-               struct per_cpu_pageset *pset;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               pset = zone_pcp(zone, smp_processor_id());
-               for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-                       struct per_cpu_pages *pcp;
-
-                       pcp = &pset->pcp[i];
-                       if (pcp->count) {
-                               int to_drain;
-
-                               local_irq_save(flags);
-                               if (pcp->count >= pcp->batch)
-                                       to_drain = pcp->batch;
-                               else
-                                       to_drain = pcp->count;
-                               free_pages_bulk(zone, to_drain, &pcp->list, 0);
-                               pcp->count -= to_drain;
-                               local_irq_restore(flags);
-                       }
-               }
-       }
+       local_irq_save(flags);
+       if (pcp->count >= pcp->batch)
+               to_drain = pcp->batch;
+       else
+               to_drain = pcp->count;
+       free_pages_bulk(zone, to_drain, &pcp->list, 0);
+       pcp->count -= to_drain;
+       local_irq_restore(flags);
 }
 #endif
 
@@ -2148,11 +2131,14 @@ static int __cpuinit pageset_cpuup_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                if (process_zones(cpu))
                        ret = NOTIFY_BAD;
                break;
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                free_zone_pagesets(cpu);
                break;
        default:
@@ -2298,7 +2284,7 @@ static int __meminit next_active_region_index_in_nid(int index, int nid)
  * was used and there are no special requirements, this is a convenient
  * alternative
  */
-int __init early_pfn_to_nid(unsigned long pfn)
+int __meminit early_pfn_to_nid(unsigned long pfn)
 {
        int i;
 
@@ -3012,7 +2998,7 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
 {
        int cpu = (unsigned long)hcpu;
 
-       if (action == CPU_DEAD) {
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
                local_irq_disable();
                __drain_pages(cpu);
                vm_events_fold_cpu(cpu);
index acda7e2d66e4e9f4f6b7513a7c00cf91bf0873c4..944b20581f8c421369828fb2090381ad53aa3969 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -928,12 +928,6 @@ static void next_reap_node(void)
 {
        int node = __get_cpu_var(reap_node);
 
-       /*
-        * Also drain per cpu pages on remote zones
-        */
-       if (node != numa_node_id())
-               drain_node_pages(node);
-
        node = next_node(node, node_online_map);
        if (unlikely(node >= MAX_NUMNODES))
                node = first_node(node_online_map);
@@ -1186,8 +1180,11 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
        int memsize = sizeof(struct kmem_list3);
 
        switch (action) {
-       case CPU_UP_PREPARE:
+       case CPU_LOCK_ACQUIRE:
                mutex_lock(&cache_chain_mutex);
+               break;
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                /*
                 * We need to do this right in the beginning since
                 * alloc_arraycache's are going to use this list.
@@ -1274,17 +1271,28 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                }
                break;
        case CPU_ONLINE:
-               mutex_unlock(&cache_chain_mutex);
+       case CPU_ONLINE_FROZEN:
                start_cpu_timer(cpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
-       case CPU_DOWN_PREPARE:
-               mutex_lock(&cache_chain_mutex);
-               break;
-       case CPU_DOWN_FAILED:
-               mutex_unlock(&cache_chain_mutex);
-               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               /*
+                * Shutdown cache reaper. Note that the cache_chain_mutex is
+                * held so that if cache_reap() is invoked it cannot do
+                * anything expensive but will only modify reap_work
+                * and reschedule the timer.
+               */
+               cancel_rearming_delayed_work(&per_cpu(reap_work, cpu));
+               /* Now the cache_reaper is guaranteed to be not running. */
+               per_cpu(reap_work, cpu).work.func = NULL;
+               break;
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               start_cpu_timer(cpu);
+               break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                /*
                 * Even if all the cpus of a node are down, we don't free the
                 * kmem_list3 of any cache. This to avoid a race between
@@ -1296,6 +1304,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                /* fall thru */
 #endif
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
                list_for_each_entry(cachep, &cache_chain, next) {
                        struct array_cache *nc;
                        struct array_cache *shared;
@@ -1354,6 +1363,8 @@ free_array_cache:
                                continue;
                        drain_freelist(cachep, l3, l3->free_objects);
                }
+               break;
+       case CPU_LOCK_RELEASE:
                mutex_unlock(&cache_chain_mutex);
                break;
        }
@@ -3742,7 +3753,6 @@ EXPORT_SYMBOL(__kmalloc);
 
 /**
  * krealloc - reallocate memory. The contents will remain unchanged.
- *
  * @p: object to reallocate memory for.
  * @new_size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
@@ -4140,7 +4150,6 @@ next:
        check_irq_on();
        mutex_unlock(&cache_chain_mutex);
        next_reap_node();
-       refresh_cpu_vm_stats(smp_processor_id());
 out:
        /* Set up the next iteration */
        schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC));
index 5db3da5a60bf15507227eead81474a2575dfc653..b39c8a69a4ff4f79faecc51b6d8cfeaabf707754 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
  * SLUB assigns one slab for allocation to each processor.
  * Allocations only occur from these slabs called cpu slabs.
  *
- * Slabs with free elements are kept on a partial list.
- * There is no list for full slabs. If an object in a full slab is
+ * Slabs with free elements are kept on a partial list and during regular
+ * operations no list for full slabs is used. If an object in a full slab is
  * freed then the slab will show up again on the partial lists.
- * Otherwise there is no need to track full slabs unless we have to
- * track full slabs for debugging purposes.
+ * We track full slabs for debugging purposes though because otherwise we
+ * cannot scan all objects.
  *
  * Slabs are freed when they become empty. Teardown and setup is
  * minimal so we rely on the page allocators per cpu caches for
  * PageActive          The slab is used as a cpu cache. Allocations
  *                     may be performed from the slab. The slab is not
  *                     on any slab list and cannot be moved onto one.
+ *                     The cpu slab may be equipped with an additioanl
+ *                     lockless_freelist that allows lockless access to
+ *                     free objects in addition to the regular freelist
+ *                     that requires the slab lock.
  *
  * PageError           Slab requires special handling due to debug
  *                     options set. This moves slab handling out of
- *                     the fast path.
+ *                     the fast path and disables lockless freelists.
  */
 
+static inline int SlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+       return PageError(page);
+#else
+       return 0;
+#endif
+}
+
+static inline void SetSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+       SetPageError(page);
+#endif
+}
+
+static inline void ClearSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+       ClearPageError(page);
+#endif
+}
+
 /*
  * Issues still to be resolved:
  *
  * - The per cpu array is updated for each new slab and and is a remote
  *   cacheline for most nodes. This could become a bouncing cacheline given
- *   enough frequent updates. There are 16 pointers in a cacheline.so at
- *   max 16 cpus could compete. Likely okay.
+ *   enough frequent updates. There are 16 pointers in a cachelineso at
+ *   max 16 cpus could compete for the cacheline which may be okay.
  *
  * - Support PAGE_ALLOC_DEBUG. Should be easy to do.
  *
 
 #define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
                                SLAB_POISON | SLAB_STORE_USER)
+
 /*
  * Set of flags that will prevent slab merging
  */
 /* Internal SLUB flags */
 #define __OBJECT_POISON 0x80000000     /* Poison object */
 
+/* Not all arches define cache_line_size */
+#ifndef cache_line_size
+#define cache_line_size()      L1_CACHE_BYTES
+#endif
+
 static int kmem_size = sizeof(struct kmem_cache);
 
 #ifdef CONFIG_SMP
@@ -166,7 +199,7 @@ static struct notifier_block slab_notifier;
 static enum {
        DOWN,           /* No slab functionality available */
        PARTIAL,        /* kmem_cache_open() works but kmalloc does not */
-       UP,             /* Everything works */
+       UP,             /* Everything works but does not show up in sysfs */
        SYSFS           /* Sysfs up */
 } slab_state = DOWN;
 
@@ -174,7 +207,19 @@ static enum {
 static DECLARE_RWSEM(slub_lock);
 LIST_HEAD(slab_caches);
 
-#ifdef CONFIG_SYSFS
+/*
+ * Tracking user of a slab.
+ */
+struct track {
+       void *addr;             /* Called from address */
+       int cpu;                /* Was running on cpu */
+       int pid;                /* Pid context */
+       unsigned long when;     /* When did the operation occur */
+};
+
+enum track_item { TRACK_ALLOC, TRACK_FREE };
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
 static int sysfs_slab_add(struct kmem_cache *);
 static int sysfs_slab_alias(struct kmem_cache *, const char *);
 static void sysfs_slab_remove(struct kmem_cache *);
@@ -202,6 +247,63 @@ static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
 #endif
 }
 
+static inline int check_valid_pointer(struct kmem_cache *s,
+                               struct page *page, const void *object)
+{
+       void *base;
+
+       if (!object)
+               return 1;
+
+       base = page_address(page);
+       if (object < base || object >= base + s->objects * s->size ||
+               (object - base) % s->size) {
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Slow version of get and set free pointer.
+ *
+ * This version requires touching the cache lines of kmem_cache which
+ * we avoid to do in the fast alloc free paths. There we obtain the offset
+ * from the page struct.
+ */
+static inline void *get_freepointer(struct kmem_cache *s, void *object)
+{
+       return *(void **)(object + s->offset);
+}
+
+static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+{
+       *(void **)(object + s->offset) = fp;
+}
+
+/* Loop over all objects in a slab */
+#define for_each_object(__p, __s, __addr) \
+       for (__p = (__addr); __p < (__addr) + (__s)->objects * (__s)->size;\
+                       __p += (__s)->size)
+
+/* Scan freelist */
+#define for_each_free_object(__p, __s, __free) \
+       for (__p = (__free); __p; __p = get_freepointer((__s), __p))
+
+/* Determine object index from a given position */
+static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
+{
+       return (p - addr) / s->size;
+}
+
+#ifdef CONFIG_SLUB_DEBUG
+/*
+ * Debug settings:
+ */
+static int slub_debug;
+
+static char *slub_debug_slabs;
+
 /*
  * Object debugging
  */
@@ -237,35 +339,6 @@ static void print_section(char *text, u8 *addr, unsigned int length)
        }
 }
 
-/*
- * Slow version of get and set free pointer.
- *
- * This requires touching the cache lines of kmem_cache.
- * The offset can also be obtained from the page. In that
- * case it is in the cacheline that we already need to touch.
- */
-static void *get_freepointer(struct kmem_cache *s, void *object)
-{
-       return *(void **)(object + s->offset);
-}
-
-static void set_freepointer(struct kmem_cache *s, void *object, void *fp)
-{
-       *(void **)(object + s->offset) = fp;
-}
-
-/*
- * Tracking user of a slab.
- */
-struct track {
-       void *addr;             /* Called from address */
-       int cpu;                /* Was running on cpu */
-       int pid;                /* Pid context */
-       unsigned long when;     /* When did the operation occur */
-};
-
-enum track_item { TRACK_ALLOC, TRACK_FREE };
-
 static struct track *get_track(struct kmem_cache *s, void *object,
        enum track_item alloc)
 {
@@ -400,24 +473,6 @@ static int check_bytes(u8 *start, unsigned int value, unsigned int bytes)
        return 1;
 }
 
-
-static int check_valid_pointer(struct kmem_cache *s, struct page *page,
-                                        void *object)
-{
-       void *base;
-
-       if (!object)
-               return 1;
-
-       base = page_address(page);
-       if (object < base || object >= base + s->objects * s->size ||
-               (object - base) % s->size) {
-               return 0;
-       }
-
-       return 1;
-}
-
 /*
  * Object layout:
  *
@@ -425,26 +480,34 @@ static int check_valid_pointer(struct kmem_cache *s, struct page *page,
  *     Bytes of the object to be managed.
  *     If the freepointer may overlay the object then the free
  *     pointer is the first word of the object.
+ *
  *     Poisoning uses 0x6b (POISON_FREE) and the last byte is
  *     0xa5 (POISON_END)
  *
  * object + s->objsize
  *     Padding to reach word boundary. This is also used for Redzoning.
- *     Padding is extended to word size if Redzoning is enabled
- *     and objsize == inuse.
+ *     Padding is extended by another word if Redzoning is enabled and
+ *     objsize == inuse.
+ *
  *     We fill with 0xbb (RED_INACTIVE) for inactive objects and with
  *     0xcc (RED_ACTIVE) for objects in use.
  *
  * object + s->inuse
+ *     Meta data starts here.
+ *
  *     A. Free pointer (if we cannot overwrite object on free)
  *     B. Tracking data for SLAB_STORE_USER
- *     C. Padding to reach required alignment boundary
- *             Padding is done using 0x5a (POISON_INUSE)
+ *     C. Padding to reach required alignment boundary or at mininum
+ *             one word if debuggin is on to be able to detect writes
+ *             before the word boundary.
+ *
+ *     Padding is done using 0x5a (POISON_INUSE)
  *
  * object + s->size
+ *     Nothing is used beyond s->size.
  *
- * If slabcaches are merged then the objsize and inuse boundaries are to
- * be ignored. And therefore no slab options that rely on these boundaries
+ * If slabcaches are merged then the objsize and inuse boundaries are mostly
+ * ignored. And therefore no slab options that rely on these boundaries
  * may be used with merged slabcaches.
  */
 
@@ -570,8 +633,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
                /*
                 * No choice but to zap it and thus loose the remainder
                 * of the free objects in this slab. May cause
-                * another error because the object count maybe
-                * wrong now.
+                * another error because the object count is now wrong.
                 */
                set_freepointer(s, p, NULL);
                return 0;
@@ -611,9 +673,8 @@ static int check_slab(struct kmem_cache *s, struct page *page)
 }
 
 /*
- * Determine if a certain object on a page is on the freelist and
- * therefore free. Must hold the slab lock for cpu slabs to
- * guarantee that the chains are consistent.
+ * Determine if a certain object on a page is on the freelist. Must hold the
+ * slab lock to guarantee that the chains are in a consistent state.
  */
 static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 {
@@ -659,7 +720,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 }
 
 /*
- * Tracking of fully allocated slabs for debugging
+ * Tracking of fully allocated slabs for debugging purposes.
  */
 static void add_full(struct kmem_cache_node *n, struct page *page)
 {
@@ -710,7 +771,7 @@ bad:
                /*
                 * If this is a slab page then lets do the best we can
                 * to avoid issues in the future. Marking all objects
-                * as used avoids touching the remainder.
+                * as used avoids touching the remaining objects.
                 */
                printk(KERN_ERR "@@@ SLUB: %s slab 0x%p. Marking all objects used.\n",
                        s->name, page);
@@ -764,6 +825,113 @@ fail:
        return 0;
 }
 
+static void trace(struct kmem_cache *s, struct page *page, void *object, int alloc)
+{
+       if (s->flags & SLAB_TRACE) {
+               printk(KERN_INFO "TRACE %s %s 0x%p inuse=%d fp=0x%p\n",
+                       s->name,
+                       alloc ? "alloc" : "free",
+                       object, page->inuse,
+                       page->freelist);
+
+               if (!alloc)
+                       print_section("Object", (void *)object, s->objsize);
+
+               dump_stack();
+       }
+}
+
+static int __init setup_slub_debug(char *str)
+{
+       if (!str || *str != '=')
+               slub_debug = DEBUG_DEFAULT_FLAGS;
+       else {
+               str++;
+               if (*str == 0 || *str == ',')
+                       slub_debug = DEBUG_DEFAULT_FLAGS;
+               else
+               for( ;*str && *str != ','; str++)
+                       switch (*str) {
+                       case 'f' : case 'F' :
+                               slub_debug |= SLAB_DEBUG_FREE;
+                               break;
+                       case 'z' : case 'Z' :
+                               slub_debug |= SLAB_RED_ZONE;
+                               break;
+                       case 'p' : case 'P' :
+                               slub_debug |= SLAB_POISON;
+                               break;
+                       case 'u' : case 'U' :
+                               slub_debug |= SLAB_STORE_USER;
+                               break;
+                       case 't' : case 'T' :
+                               slub_debug |= SLAB_TRACE;
+                               break;
+                       default:
+                               printk(KERN_ERR "slub_debug option '%c' "
+                                       "unknown. skipped\n",*str);
+                       }
+       }
+
+       if (*str == ',')
+               slub_debug_slabs = str + 1;
+       return 1;
+}
+
+__setup("slub_debug", setup_slub_debug);
+
+static void kmem_cache_open_debug_check(struct kmem_cache *s)
+{
+       /*
+        * The page->offset field is only 16 bit wide. This is an offset
+        * in units of words from the beginning of an object. If the slab
+        * size is bigger then we cannot move the free pointer behind the
+        * object anymore.
+        *
+        * On 32 bit platforms the limit is 256k. On 64bit platforms
+        * the limit is 512k.
+        *
+        * Debugging or ctor/dtors may create a need to move the free
+        * pointer. Fail if this happens.
+        */
+       if (s->size >= 65535 * sizeof(void *)) {
+               BUG_ON(s->flags & (SLAB_RED_ZONE | SLAB_POISON |
+                               SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
+               BUG_ON(s->ctor || s->dtor);
+       }
+       else
+               /*
+                * Enable debugging if selected on the kernel commandline.
+                */
+               if (slub_debug && (!slub_debug_slabs ||
+                   strncmp(slub_debug_slabs, s->name,
+                       strlen(slub_debug_slabs)) == 0))
+                               s->flags |= slub_debug;
+}
+#else
+
+static inline int alloc_object_checks(struct kmem_cache *s,
+               struct page *page, void *object) { return 0; }
+
+static inline int free_object_checks(struct kmem_cache *s,
+               struct page *page, void *object) { return 0; }
+
+static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+static inline void remove_full(struct kmem_cache *s, struct page *page) {}
+static inline void trace(struct kmem_cache *s, struct page *page,
+                       void *object, int alloc) {}
+static inline void init_object(struct kmem_cache *s,
+                       void *object, int active) {}
+static inline void init_tracking(struct kmem_cache *s, void *object) {}
+static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
+                       { return 1; }
+static inline int check_object(struct kmem_cache *s, struct page *page,
+                       void *object, int active) { return 1; }
+static inline void set_track(struct kmem_cache *s, void *object,
+                       enum track_item alloc, void *addr) {}
+static inline void kmem_cache_open_debug_check(struct kmem_cache *s) {}
+#define slub_debug 0
+#endif
 /*
  * Slab allocation and freeing
  */
@@ -797,7 +965,7 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 static void setup_object(struct kmem_cache *s, struct page *page,
                                void *object)
 {
-       if (PageError(page)) {
+       if (SlabDebug(page)) {
                init_object(s, object, 0);
                init_tracking(s, object);
        }
@@ -832,7 +1000,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        page->flags |= 1 << PG_slab;
        if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
                        SLAB_STORE_USER | SLAB_TRACE))
-               page->flags |= 1 << PG_error;
+               SetSlabDebug(page);
 
        start = page_address(page);
        end = start + s->objects * s->size;
@@ -841,7 +1009,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
                memset(start, POISON_INUSE, PAGE_SIZE << s->order);
 
        last = start;
-       for (p = start + s->size; p < end; p += s->size) {
+       for_each_object(p, s, start) {
                setup_object(s, page, last);
                set_freepointer(s, last, p);
                last = p;
@@ -850,6 +1018,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        set_freepointer(s, last, NULL);
 
        page->freelist = start;
+       page->lockless_freelist = NULL;
        page->inuse = 0;
 out:
        if (flags & __GFP_WAIT)
@@ -861,13 +1030,11 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
 {
        int pages = 1 << s->order;
 
-       if (unlikely(PageError(page) || s->dtor)) {
-               void *start = page_address(page);
-               void *end = start + (pages << PAGE_SHIFT);
+       if (unlikely(SlabDebug(page) || s->dtor)) {
                void *p;
 
                slab_pad_check(s, page);
-               for (p = start; p <= end - s->size; p += s->size) {
+               for_each_object(p, s, page_address(page)) {
                        if (s->dtor)
                                s->dtor(p, s, 0);
                        check_object(s, page, p, 0);
@@ -910,7 +1077,8 @@ static void discard_slab(struct kmem_cache *s, struct page *page)
 
        atomic_long_dec(&n->nr_slabs);
        reset_page_mapcount(page);
-       page->flags &= ~(1 << PG_slab | 1 << PG_error);
+       ClearSlabDebug(page);
+       __ClearPageSlab(page);
        free_slab(s, page);
 }
 
@@ -966,9 +1134,9 @@ static void remove_partial(struct kmem_cache *s,
 }
 
 /*
- * Lock page and remove it from the partial list
+ * Lock slab and remove from the partial list.
  *
- * Must hold list_lock
+ * Must hold list_lock.
  */
 static int lock_and_del_slab(struct kmem_cache_node *n, struct page *page)
 {
@@ -981,7 +1149,7 @@ static int lock_and_del_slab(struct kmem_cache_node *n, struct page *page)
 }
 
 /*
- * Try to get a partial slab from a specific node
+ * Try to allocate a partial slab from a specific node.
  */
 static struct page *get_partial_node(struct kmem_cache_node *n)
 {
@@ -990,7 +1158,8 @@ static struct page *get_partial_node(struct kmem_cache_node *n)
        /*
         * Racy check. If we mistakenly see no partial slabs then we
         * just allocate an empty slab. If we mistakenly try to get a
-        * partial slab then get_partials() will return NULL.
+        * partial slab and there is none available then get_partials()
+        * will return NULL.
         */
        if (!n || !n->nr_partial)
                return NULL;
@@ -1006,8 +1175,7 @@ out:
 }
 
 /*
- * Get a page from somewhere. Search in increasing NUMA
- * distances.
+ * Get a page from somewhere. Search in increasing NUMA distances.
  */
 static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
 {
@@ -1017,24 +1185,22 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
        struct page *page;
 
        /*
-        * The defrag ratio allows to configure the tradeoffs between
-        * inter node defragmentation and node local allocations.
-        * A lower defrag_ratio increases the tendency to do local
-        * allocations instead of scanning throught the partial
-        * lists on other nodes.
+        * The defrag ratio allows a configuration of the tradeoffs between
+        * inter node defragmentation and node local allocations. A lower
+        * defrag_ratio increases the tendency to do local allocations
+        * instead of attempting to obtain partial slabs from other nodes.
         *
-        * If defrag_ratio is set to 0 then kmalloc() always
-        * returns node local objects. If its higher then kmalloc()
-        * may return off node objects in order to avoid fragmentation.
-        *
-        * A higher ratio means slabs may be taken from other nodes
-        * thus reducing the number of partial slabs on those nodes.
+        * If the defrag_ratio is set to 0 then kmalloc() always
+        * returns node local objects. If the ratio is higher then kmalloc()
+        * may return off node objects because partial slabs are obtained
+        * from other nodes and filled up.
         *
         * If /sys/slab/xx/defrag_ratio is set to 100 (which makes
-        * defrag_ratio = 1000) then every (well almost) allocation
-        * will first attempt to defrag slab caches on other nodes. This
-        * means scanning over all nodes to look for partial slabs which
-        * may be a bit expensive to do on every slab allocation.
+        * defrag_ratio = 1000) then every (well almost) allocation will
+        * first attempt to defrag slab caches on other nodes. This means
+        * scanning over all nodes to look for partial slabs which may be
+        * expensive if we do it every time we are trying to find a slab
+        * with available objects.
         */
        if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
                return NULL;
@@ -1087,18 +1253,19 @@ static void putback_slab(struct kmem_cache *s, struct page *page)
 
                if (page->freelist)
                        add_partial(n, page);
-               else if (PageError(page) && (s->flags & SLAB_STORE_USER))
+               else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER))
                        add_full(n, page);
                slab_unlock(page);
 
        } else {
                if (n->nr_partial < MIN_PARTIAL) {
                        /*
-                        * Adding an empty page to the partial slabs in order
-                        * to avoid page allocator overhead. This page needs to
-                        * come after all the others that are not fully empty
-                        * in order to make sure that we do maximum
-                        * defragmentation.
+                        * Adding an empty slab to the partial slabs in order
+                        * to avoid page allocator overhead. This slab needs
+                        * to come after the other slabs with objects in
+                        * order to fill them up. That way the size of the
+                        * partial list stays small. kmem_cache_shrink can
+                        * reclaim empty slabs from the partial list.
                         */
                        add_partial_tail(n, page);
                        slab_unlock(page);
@@ -1114,6 +1281,23 @@ static void putback_slab(struct kmem_cache *s, struct page *page)
  */
 static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu)
 {
+       /*
+        * Merge cpu freelist into freelist. Typically we get here
+        * because both freelists are empty. So this is unlikely
+        * to occur.
+        */
+       while (unlikely(page->lockless_freelist)) {
+               void **object;
+
+               /* Retrieve object from cpu_freelist */
+               object = page->lockless_freelist;
+               page->lockless_freelist = page->lockless_freelist[page->offset];
+
+               /* And put onto the regular freelist */
+               object[page->offset] = page->freelist;
+               page->freelist = object;
+               page->inuse--;
+       }
        s->cpu_slab[cpu] = NULL;
        ClearPageActive(page);
 
@@ -1160,47 +1344,46 @@ static void flush_all(struct kmem_cache *s)
 }
 
 /*
- * slab_alloc is optimized to only modify two cachelines on the fast path
- * (aside from the stack):
+ * Slow path. The lockless freelist is empty or we need to perform
+ * debugging duties.
+ *
+ * Interrupts are disabled.
  *
- * 1. The page struct
- * 2. The first cacheline of the object to be allocated.
+ * Processing is still very fast if new objects have been freed to the
+ * regular freelist. In that case we simply take over the regular freelist
+ * as the lockless freelist and zap the regular freelist.
  *
- * The only cache lines that are read (apart from code) is the
- * per cpu array in the kmem_cache struct.
+ * If that is not working then we fall back to the partial lists. We take the
+ * first element of the freelist as the object to allocate now and move the
+ * rest of the freelist to the lockless freelist.
  *
- * Fastpath is not possible if we need to get a new slab or have
- * debugging enabled (which means all slabs are marked with PageError)
+ * And if we were unable to get a new slab from the partial slab lists then
+ * we need to allocate a new slab. This is slowest path since we may sleep.
  */
-static void *slab_alloc(struct kmem_cache *s,
-                               gfp_t gfpflags, int node, void *addr)
+static void *__slab_alloc(struct kmem_cache *s,
+               gfp_t gfpflags, int node, void *addr, struct page *page)
 {
-       struct page *page;
        void **object;
-       unsigned long flags;
-       int cpu;
+       int cpu = smp_processor_id();
 
-       local_irq_save(flags);
-       cpu = smp_processor_id();
-       page = s->cpu_slab[cpu];
        if (!page)
                goto new_slab;
 
        slab_lock(page);
        if (unlikely(node != -1 && page_to_nid(page) != node))
                goto another_slab;
-redo:
+load_freelist:
        object = page->freelist;
        if (unlikely(!object))
                goto another_slab;
-       if (unlikely(PageError(page)))
+       if (unlikely(SlabDebug(page)))
                goto debug;
 
-have_object:
-       page->inuse++;
-       page->freelist = object[page->offset];
+       object = page->freelist;
+       page->lockless_freelist = object[page->offset];
+       page->inuse = s->objects;
+       page->freelist = NULL;
        slab_unlock(page);
-       local_irq_restore(flags);
        return object;
 
 another_slab:
@@ -1208,11 +1391,11 @@ another_slab:
 
 new_slab:
        page = get_partial(s, gfpflags, node);
-       if (likely(page)) {
+       if (page) {
 have_slab:
                s->cpu_slab[cpu] = page;
                SetPageActive(page);
-               goto redo;
+               goto load_freelist;
        }
 
        page = new_slab(s, gfpflags, node);
@@ -1220,9 +1403,11 @@ have_slab:
                cpu = smp_processor_id();
                if (s->cpu_slab[cpu]) {
                        /*
-                        * Someone else populated the cpu_slab while we enabled
-                        * interrupts, or we have got scheduled on another cpu.
-                        * The page may not be on the requested node.
+                        * Someone else populated the cpu_slab while we
+                        * enabled interrupts, or we have gotten scheduled
+                        * on another cpu. The page may not be on the
+                        * requested node even if __GFP_THISNODE was
+                        * specified. So we need to recheck.
                         */
                        if (node == -1 ||
                                page_to_nid(s->cpu_slab[cpu]) == node) {
@@ -1233,29 +1418,60 @@ have_slab:
                                discard_slab(s, page);
                                page = s->cpu_slab[cpu];
                                slab_lock(page);
-                               goto redo;
+                               goto load_freelist;
                        }
-                       /* Dump the current slab */
+                       /* New slab does not fit our expectations */
                        flush_slab(s, s->cpu_slab[cpu], cpu);
                }
                slab_lock(page);
                goto have_slab;
        }
-       local_irq_restore(flags);
        return NULL;
 debug:
+       object = page->freelist;
        if (!alloc_object_checks(s, page, object))
                goto another_slab;
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_ALLOC, addr);
-       if (s->flags & SLAB_TRACE) {
-               printk(KERN_INFO "TRACE %s alloc 0x%p inuse=%d fp=0x%p\n",
-                       s->name, object, page->inuse,
-                       page->freelist);
-               dump_stack();
-       }
+       trace(s, page, object, 1);
        init_object(s, object, 1);
-       goto have_object;
+
+       page->inuse++;
+       page->freelist = object[page->offset];
+       slab_unlock(page);
+       return object;
+}
+
+/*
+ * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
+ * have the fastpath folded into their functions. So no function call
+ * overhead for requests that can be satisfied on the fastpath.
+ *
+ * The fastpath works by first checking if the lockless freelist can be used.
+ * If not then __slab_alloc is called for slow processing.
+ *
+ * Otherwise we can simply pick the next object from the lockless free list.
+ */
+static void __always_inline *slab_alloc(struct kmem_cache *s,
+                               gfp_t gfpflags, int node, void *addr)
+{
+       struct page *page;
+       void **object;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       page = s->cpu_slab[smp_processor_id()];
+       if (unlikely(!page || !page->lockless_freelist ||
+                       (node != -1 && page_to_nid(page) != node)))
+
+               object = __slab_alloc(s, gfpflags, node, addr, page);
+
+       else {
+               object = page->lockless_freelist;
+               page->lockless_freelist = object[page->offset];
+       }
+       local_irq_restore(flags);
+       return object;
 }
 
 void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
@@ -1273,22 +1489,22 @@ EXPORT_SYMBOL(kmem_cache_alloc_node);
 #endif
 
 /*
- * The fastpath only writes the cacheline of the page struct and the first
- * cacheline of the object.
+ * Slow patch handling. This may still be called frequently since objects
+ * have a longer lifetime than the cpu slabs in most processing loads.
  *
- * No special cachelines need to be read
+ * So we still attempt to reduce cache line usage. Just take the slab
+ * lock and free the item. If there is no additional partial page
+ * handling required then we can return immediately.
  */
-static void slab_free(struct kmem_cache *s, struct page *page,
+static void __slab_free(struct kmem_cache *s, struct page *page,
                                        void *x, void *addr)
 {
        void *prior;
        void **object = (void *)x;
-       unsigned long flags;
 
-       local_irq_save(flags);
        slab_lock(page);
 
-       if (unlikely(PageError(page)))
+       if (unlikely(SlabDebug(page)))
                goto debug;
 checks_ok:
        prior = object[page->offset] = page->freelist;
@@ -1315,19 +1531,17 @@ checks_ok:
 
 out_unlock:
        slab_unlock(page);
-       local_irq_restore(flags);
        return;
 
 slab_empty:
        if (prior)
                /*
-                * Slab on the partial list.
+                * Slab still on the partial list.
                 */
                remove_partial(s, page);
 
        slab_unlock(page);
        discard_slab(s, page);
-       local_irq_restore(flags);
        return;
 
 debug:
@@ -1337,17 +1551,39 @@ debug:
                remove_full(s, page);
        if (s->flags & SLAB_STORE_USER)
                set_track(s, x, TRACK_FREE, addr);
-       if (s->flags & SLAB_TRACE) {
-               printk(KERN_INFO "TRACE %s free 0x%p inuse=%d fp=0x%p\n",
-                       s->name, object, page->inuse,
-                       page->freelist);
-               print_section("Object", (void *)object, s->objsize);
-               dump_stack();
-       }
+       trace(s, page, object, 0);
        init_object(s, object, 0);
        goto checks_ok;
 }
 
+/*
+ * Fastpath with forced inlining to produce a kfree and kmem_cache_free that
+ * can perform fastpath freeing without additional function calls.
+ *
+ * The fastpath is only possible if we are freeing to the current cpu slab
+ * of this processor. This typically the case if we have just allocated
+ * the item before.
+ *
+ * If fastpath is not possible then fall back to __slab_free where we deal
+ * with all sorts of special processing.
+ */
+static void __always_inline slab_free(struct kmem_cache *s,
+                       struct page *page, void *x, void *addr)
+{
+       void **object = (void *)x;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       if (likely(page == s->cpu_slab[smp_processor_id()] &&
+                                               !SlabDebug(page))) {
+               object[page->offset] = page->lockless_freelist;
+               page->lockless_freelist = object;
+       } else
+               __slab_free(s, page, x, addr);
+
+       local_irq_restore(flags);
+}
+
 void kmem_cache_free(struct kmem_cache *s, void *x)
 {
        struct page *page;
@@ -1370,22 +1606,16 @@ static struct page *get_object_page(const void *x)
 }
 
 /*
- * kmem_cache_open produces objects aligned at "size" and the first object
- * is placed at offset 0 in the slab (We have no metainformation on the
- * slab, all slabs are in essence "off slab").
- *
- * In order to get the desired alignment one just needs to align the
- * size.
+ * Object placement in a slab is made very easy because we always start at
+ * offset 0. If we tune the size of the object to the alignment then we can
+ * get the required alignment by putting one properly sized object after
+ * another.
  *
  * Notice that the allocation order determines the sizes of the per cpu
  * caches. Each processor has always one slab available for allocations.
  * Increasing the allocation order reduces the number of times that slabs
- * must be moved on and off the partial lists and therefore may influence
+ * must be moved on and off the partial lists and is therefore a factor in
  * locking overhead.
- *
- * The offset is used to relocate the free list link in each object. It is
- * therefore possible to move the free list link behind the object. This
- * is necessary for RCU to work properly and also useful for debugging.
  */
 
 /*
@@ -1396,76 +1626,110 @@ static struct page *get_object_page(const void *x)
  */
 static int slub_min_order;
 static int slub_max_order = DEFAULT_MAX_ORDER;
-
-/*
- * Minimum number of objects per slab. This is necessary in order to
- * reduce locking overhead. Similar to the queue size in SLAB.
- */
 static int slub_min_objects = DEFAULT_MIN_OBJECTS;
 
 /*
  * Merge control. If this is set then no merging of slab caches will occur.
+ * (Could be removed. This was introduced to pacify the merge skeptics.)
  */
 static int slub_nomerge;
 
-/*
- * Debug settings:
- */
-static int slub_debug;
-
-static char *slub_debug_slabs;
-
 /*
  * Calculate the order of allocation given an slab object size.
  *
- * The order of allocation has significant impact on other elements
- * of the system. Generally order 0 allocations should be preferred
- * since they do not cause fragmentation in the page allocator. Larger
- * objects may have problems with order 0 because there may be too much
- * space left unused in a slab. We go to a higher order if more than 1/8th
- * of the slab would be wasted.
+ * The order of allocation has significant impact on performance and other
+ * system components. Generally order 0 allocations should be preferred since
+ * order 0 does not cause fragmentation in the page allocator. Larger objects
+ * be problematic to put into order 0 slabs because there may be too much
+ * unused space left. We go to a higher order if more than 1/8th of the slab
+ * would be wasted.
+ *
+ * In order to reach satisfactory performance we must ensure that a minimum
+ * number of objects is in one slab. Otherwise we may generate too much
+ * activity on the partial lists which requires taking the list_lock. This is
+ * less a concern for large slabs though which are rarely used.
  *
- * In order to reach satisfactory performance we must ensure that
- * a minimum number of objects is in one slab. Otherwise we may
- * generate too much activity on the partial lists. This is less a
- * concern for large slabs though. slub_max_order specifies the order
- * where we begin to stop considering the number of objects in a slab.
+ * slub_max_order specifies the order where we begin to stop considering the
+ * number of objects in a slab as critical. If we reach slub_max_order then
+ * we try to keep the page order as low as possible. So we accept more waste
+ * of space in favor of a small page order.
  *
- * Higher order allocations also allow the placement of more objects
- * in a slab and thereby reduce object handling overhead. If the user
- * has requested a higher mininum order then we start with that one
- * instead of zero.
+ * Higher order allocations also allow the placement of more objects in a
+ * slab and thereby reduce object handling overhead. If the user has
+ * requested a higher mininum order then we start with that one instead of
+ * the smallest order which will fit the object.
  */
-static int calculate_order(int size)
+static inline int slab_order(int size, int min_objects,
+                               int max_order, int fract_leftover)
 {
        int order;
        int rem;
 
-       for (order = max(slub_min_order, fls(size - 1) - PAGE_SHIFT);
-                       order < MAX_ORDER; order++) {
-               unsigned long slab_size = PAGE_SIZE << order;
+       for (order = max(slub_min_order,
+                               fls(min_objects * size - 1) - PAGE_SHIFT);
+                       order <= max_order; order++) {
 
-               if (slub_max_order > order &&
-                               slab_size < slub_min_objects * size)
-                       continue;
+               unsigned long slab_size = PAGE_SIZE << order;
 
-               if (slab_size < size)
+               if (slab_size < min_objects * size)
                        continue;
 
                rem = slab_size % size;
 
-               if (rem <= (PAGE_SIZE << order) / 8)
+               if (rem <= slab_size / fract_leftover)
                        break;
 
        }
-       if (order >= MAX_ORDER)
-               return -E2BIG;
+
        return order;
 }
 
+static inline int calculate_order(int size)
+{
+       int order;
+       int min_objects;
+       int fraction;
+
+       /*
+        * Attempt to find best configuration for a slab. This
+        * works by first attempting to generate a layout with
+        * the best configuration and backing off gradually.
+        *
+        * First we reduce the acceptable waste in a slab. Then
+        * we reduce the minimum objects required in a slab.
+        */
+       min_objects = slub_min_objects;
+       while (min_objects > 1) {
+               fraction = 8;
+               while (fraction >= 4) {
+                       order = slab_order(size, min_objects,
+                                               slub_max_order, fraction);
+                       if (order <= slub_max_order)
+                               return order;
+                       fraction /= 2;
+               }
+               min_objects /= 2;
+       }
+
+       /*
+        * We were unable to place multiple objects in a slab. Now
+        * lets see if we can place a single object there.
+        */
+       order = slab_order(size, 1, slub_max_order, 1);
+       if (order <= slub_max_order)
+               return order;
+
+       /*
+        * Doh this slab cannot be placed using slub_max_order.
+        */
+       order = slab_order(size, 1, MAX_ORDER, 1);
+       if (order <= MAX_ORDER)
+               return order;
+       return -ENOSYS;
+}
+
 /*
- * Function to figure out which alignment to use from the
- * various ways of specifying it.
+ * Figure out what the alignment of the objects will be.
  */
 static unsigned long calculate_alignment(unsigned long flags,
                unsigned long align, unsigned long size)
@@ -1480,8 +1744,8 @@ static unsigned long calculate_alignment(unsigned long flags,
         * then use it.
         */
        if ((flags & SLAB_HWCACHE_ALIGN) &&
-                       size > L1_CACHE_BYTES / 2)
-               return max_t(unsigned long, align, L1_CACHE_BYTES);
+                       size > cache_line_size() / 2)
+               return max_t(unsigned long, align, cache_line_size());
 
        if (align < ARCH_SLAB_MINALIGN)
                return ARCH_SLAB_MINALIGN;
@@ -1619,22 +1883,23 @@ static int calculate_sizes(struct kmem_cache *s)
         */
        size = ALIGN(size, sizeof(void *));
 
+#ifdef CONFIG_SLUB_DEBUG
        /*
-        * If we are redzoning then check if there is some space between the
+        * If we are Redzoning then check if there is some space between the
         * end of the object and the free pointer. If not then add an
-        * additional word, so that we can establish a redzone between
-        * the object and the freepointer to be able to check for overwrites.
+        * additional word to have some bytes to store Redzone information.
         */
        if ((flags & SLAB_RED_ZONE) && size == s->objsize)
                size += sizeof(void *);
+#endif
 
        /*
-        * With that we have determined how much of the slab is in actual
-        * use by the object. This is the potential offset to the free
-        * pointer.
+        * With that we have determined the number of bytes in actual use
+        * by the object. This is the potential offset to the free pointer.
         */
        s->inuse = size;
 
+#ifdef CONFIG_SLUB_DEBUG
        if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) ||
                s->ctor || s->dtor)) {
                /*
@@ -1656,7 +1921,7 @@ static int calculate_sizes(struct kmem_cache *s)
                 */
                size += 2 * sizeof(struct track);
 
-       if (flags & DEBUG_DEFAULT_FLAGS)
+       if (flags & SLAB_RED_ZONE)
                /*
                 * Add some empty padding so that we can catch
                 * overwrites from earlier objects rather than let
@@ -1665,10 +1930,12 @@ static int calculate_sizes(struct kmem_cache *s)
                 * of the object.
                 */
                size += sizeof(void *);
+#endif
+
        /*
         * Determine the alignment based on various parameters that the
-        * user specified (this is unecessarily complex due to the attempt
-        * to be compatible with SLAB. Should be cleaned up some day).
+        * user specified and the dynamic determination of cache line size
+        * on bootup.
         */
        align = calculate_alignment(flags, align, s->objsize);
 
@@ -1700,23 +1967,6 @@ static int calculate_sizes(struct kmem_cache *s)
 
 }
 
-static int __init finish_bootstrap(void)
-{
-       struct list_head *h;
-       int err;
-
-       slab_state = SYSFS;
-
-       list_for_each(h, &slab_caches) {
-               struct kmem_cache *s =
-                       container_of(h, struct kmem_cache, list);
-
-               err = sysfs_slab_add(s);
-               BUG_ON(err);
-       }
-       return 0;
-}
-
 static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
                const char *name, size_t size,
                size_t align, unsigned long flags,
@@ -1730,32 +1980,7 @@ static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
        s->objsize = size;
        s->flags = flags;
        s->align = align;
-
-       /*
-        * The page->offset field is only 16 bit wide. This is an offset
-        * in units of words from the beginning of an object. If the slab
-        * size is bigger then we cannot move the free pointer behind the
-        * object anymore.
-        *
-        * On 32 bit platforms the limit is 256k. On 64bit platforms
-        * the limit is 512k.
-        *
-        * Debugging or ctor/dtors may create a need to move the free
-        * pointer. Fail if this happens.
-        */
-       if (s->size >= 65535 * sizeof(void *)) {
-               BUG_ON(flags & (SLAB_RED_ZONE | SLAB_POISON |
-                               SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
-               BUG_ON(ctor || dtor);
-       }
-       else
-               /*
-                * Enable debugging if selected on the kernel commandline.
-                */
-               if (slub_debug && (!slub_debug_slabs ||
-                   strncmp(slub_debug_slabs, name,
-                       strlen(slub_debug_slabs)) == 0))
-                               s->flags |= slub_debug;
+       kmem_cache_open_debug_check(s);
 
        if (!calculate_sizes(s))
                goto error;
@@ -1783,7 +2008,6 @@ EXPORT_SYMBOL(kmem_cache_open);
 int kmem_ptr_validate(struct kmem_cache *s, const void *object)
 {
        struct page * page;
-       void *addr;
 
        page = get_object_page(object);
 
@@ -1791,13 +2015,7 @@ int kmem_ptr_validate(struct kmem_cache *s, const void *object)
                /* No slab or wrong slab */
                return 0;
 
-       addr = page_address(page);
-       if (object < addr || object >= addr + s->objects * s->size)
-               /* Out of bounds */
-               return 0;
-
-       if ((object - addr) % s->size)
-               /* Improperly aligned */
+       if (!check_valid_pointer(s, page, object))
                return 0;
 
        /*
@@ -1826,7 +2044,8 @@ const char *kmem_cache_name(struct kmem_cache *s)
 EXPORT_SYMBOL(kmem_cache_name);
 
 /*
- * Attempt to free all slabs on a node
+ * Attempt to free all slabs on a node. Return the number of slabs we
+ * were unable to free.
  */
 static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
                        struct list_head *list)
@@ -1847,7 +2066,7 @@ static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
 }
 
 /*
- * Release all resources used by slab cache
+ * Release all resources used by a slab cache.
  */
 static int kmem_cache_close(struct kmem_cache *s)
 {
@@ -1932,45 +2151,6 @@ static int __init setup_slub_nomerge(char *str)
 
 __setup("slub_nomerge", setup_slub_nomerge);
 
-static int __init setup_slub_debug(char *str)
-{
-       if (!str || *str != '=')
-               slub_debug = DEBUG_DEFAULT_FLAGS;
-       else {
-               str++;
-               if (*str == 0 || *str == ',')
-                       slub_debug = DEBUG_DEFAULT_FLAGS;
-               else
-               for( ;*str && *str != ','; str++)
-                       switch (*str) {
-                       case 'f' : case 'F' :
-                               slub_debug |= SLAB_DEBUG_FREE;
-                               break;
-                       case 'z' : case 'Z' :
-                               slub_debug |= SLAB_RED_ZONE;
-                               break;
-                       case 'p' : case 'P' :
-                               slub_debug |= SLAB_POISON;
-                               break;
-                       case 'u' : case 'U' :
-                               slub_debug |= SLAB_STORE_USER;
-                               break;
-                       case 't' : case 'T' :
-                               slub_debug |= SLAB_TRACE;
-                               break;
-                       default:
-                               printk(KERN_ERR "slub_debug option '%c' "
-                                       "unknown. skipped\n",*str);
-                       }
-       }
-
-       if (*str == ',')
-               slub_debug_slabs = str + 1;
-       return 1;
-}
-
-__setup("slub_debug", setup_slub_debug);
-
 static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
                const char *name, int size, gfp_t gfp_flags)
 {
@@ -2108,13 +2288,14 @@ void kfree(const void *x)
 EXPORT_SYMBOL(kfree);
 
 /*
- *  kmem_cache_shrink removes empty slabs from the partial lists
- *  and then sorts the partially allocated slabs by the number
- *  of items in use. The slabs with the most items in use
- *  come first. New allocations will remove these from the
- *  partial list because they are full. The slabs with the
- *  least items are placed last. If it happens that the objects
- *  are freed then the page can be returned to the page allocator.
+ * kmem_cache_shrink removes empty slabs from the partial lists and sorts
+ * the remaining slabs by the number of items in use. The slabs with the
+ * most items in use come first. New allocations will then fill those up
+ * and thus they can be removed from the partial lists.
+ *
+ * The slabs with the least items are placed last. This results in them
+ * being allocated from last increasing the chance that the last objects
+ * are freed in them.
  */
 int kmem_cache_shrink(struct kmem_cache *s)
 {
@@ -2143,12 +2324,10 @@ int kmem_cache_shrink(struct kmem_cache *s)
                spin_lock_irqsave(&n->list_lock, flags);
 
                /*
-                * Build lists indexed by the items in use in
-                * each slab or free slabs if empty.
+                * Build lists indexed by the items in use in each slab.
                 *
-                * Note that concurrent frees may occur while
-                * we hold the list_lock. page->inuse here is
-                * the upper limit.
+                * Note that concurrent frees may occur while we hold the
+                * list_lock. page->inuse here is the upper limit.
                 */
                list_for_each_entry_safe(page, t, &n->partial, lru) {
                        if (!page->inuse && slab_trylock(page)) {
@@ -2172,8 +2351,8 @@ int kmem_cache_shrink(struct kmem_cache *s)
                        goto out;
 
                /*
-                * Rebuild the partial list with the slabs filled up
-                * most first and the least used slabs at the end.
+                * Rebuild the partial list with the slabs filled up most
+                * first and the least used slabs at the end.
                 */
                for (i = s->objects - 1; i >= 0; i--)
                        list_splice(slabs_by_inuse + i, n->partial.prev);
@@ -2189,7 +2368,6 @@ EXPORT_SYMBOL(kmem_cache_shrink);
 
 /**
  * krealloc - reallocate memory. The contents will remain unchanged.
- *
  * @p: object to reallocate memory for.
  * @new_size: how many bytes of memory are required.
  * @flags: the type of memory to allocate.
@@ -2201,9 +2379,8 @@ EXPORT_SYMBOL(kmem_cache_shrink);
  */
 void *krealloc(const void *p, size_t new_size, gfp_t flags)
 {
-       struct kmem_cache *new_cache;
        void *ret;
-       struct page *page;
+       size_t ks;
 
        if (unlikely(!p))
                return kmalloc(new_size, flags);
@@ -2213,19 +2390,13 @@ void *krealloc(const void *p, size_t new_size, gfp_t flags)
                return NULL;
        }
 
-       page = virt_to_head_page(p);
-
-       new_cache = get_slab(new_size, flags);
-
-       /*
-        * If new size fits in the current cache, bail out.
-        */
-       if (likely(page->slab == new_cache))
+       ks = ksize(p);
+       if (ks >= new_size)
                return (void *)p;
 
        ret = kmalloc(new_size, flags);
        if (ret) {
-               memcpy(ret, p, min(new_size, ksize(p)));
+               memcpy(ret, p, min(new_size, ks));
                kfree(p);
        }
        return ret;
@@ -2243,7 +2414,7 @@ void __init kmem_cache_init(void)
 #ifdef CONFIG_NUMA
        /*
         * Must first have the slab cache available for the allocations of the
-        * struct kmalloc_cache_node's. There is special bootstrap code in
+        * struct kmem_cache_node's. There is special bootstrap code in
         * kmem_cache_open for slab_state == DOWN.
         */
        create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
@@ -2274,13 +2445,12 @@ void __init kmem_cache_init(void)
        register_cpu_notifier(&slab_notifier);
 #endif
 
-       if (nr_cpu_ids) /* Remove when nr_cpu_ids is fixed upstream ! */
-               kmem_size = offsetof(struct kmem_cache, cpu_slab)
-                        + nr_cpu_ids * sizeof(struct page *);
+       kmem_size = offsetof(struct kmem_cache, cpu_slab) +
+                               nr_cpu_ids * sizeof(struct page *);
 
        printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
                " Processors=%d, Nodes=%d\n",
-               KMALLOC_SHIFT_HIGH, L1_CACHE_BYTES,
+               KMALLOC_SHIFT_HIGH, cache_line_size(),
                slub_min_order, slub_max_order, slub_min_objects,
                nr_cpu_ids, nr_node_ids);
 }
@@ -2415,8 +2585,8 @@ static void for_all_slabs(void (*func)(struct kmem_cache *, int), int cpu)
 }
 
 /*
- * Use the cpu notifier to insure that the slab are flushed
- * when necessary.
+ * Use the cpu notifier to insure that the cpu slabs are flushed when
+ * necessary.
  */
 static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
                unsigned long action, void *hcpu)
@@ -2425,7 +2595,9 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
 
        switch (action) {
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                for_all_slabs(__flush_cpu_slab, cpu);
                break;
        default:
@@ -2439,153 +2611,6 @@ static struct notifier_block __cpuinitdata slab_notifier =
 
 #endif
 
-#ifdef CONFIG_NUMA
-
-/*****************************************************************
- * Generic reaper used to support the page allocator
- * (the cpu slabs are reaped by a per slab workqueue).
- *
- * Maybe move this to the page allocator?
- ****************************************************************/
-
-static DEFINE_PER_CPU(unsigned long, reap_node);
-
-static void init_reap_node(int cpu)
-{
-       int node;
-
-       node = next_node(cpu_to_node(cpu), node_online_map);
-       if (node == MAX_NUMNODES)
-               node = first_node(node_online_map);
-
-       __get_cpu_var(reap_node) = node;
-}
-
-static void next_reap_node(void)
-{
-       int node = __get_cpu_var(reap_node);
-
-       /*
-        * Also drain per cpu pages on remote zones
-        */
-       if (node != numa_node_id())
-               drain_node_pages(node);
-
-       node = next_node(node, node_online_map);
-       if (unlikely(node >= MAX_NUMNODES))
-               node = first_node(node_online_map);
-       __get_cpu_var(reap_node) = node;
-}
-#else
-#define init_reap_node(cpu) do { } while (0)
-#define next_reap_node(void) do { } while (0)
-#endif
-
-#define REAPTIMEOUT_CPUC       (2*HZ)
-
-#ifdef CONFIG_SMP
-static DEFINE_PER_CPU(struct delayed_work, reap_work);
-
-static void cache_reap(struct work_struct *unused)
-{
-       next_reap_node();
-       refresh_cpu_vm_stats(smp_processor_id());
-       schedule_delayed_work(&__get_cpu_var(reap_work),
-                                     REAPTIMEOUT_CPUC);
-}
-
-static void __devinit start_cpu_timer(int cpu)
-{
-       struct delayed_work *reap_work = &per_cpu(reap_work, cpu);
-
-       /*
-        * When this gets called from do_initcalls via cpucache_init(),
-        * init_workqueues() has already run, so keventd will be setup
-        * at that time.
-        */
-       if (keventd_up() && reap_work->work.func == NULL) {
-               init_reap_node(cpu);
-               INIT_DELAYED_WORK(reap_work, cache_reap);
-               schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu);
-       }
-}
-
-static int __init cpucache_init(void)
-{
-       int cpu;
-
-       /*
-        * Register the timers that drain pcp pages and update vm statistics
-        */
-       for_each_online_cpu(cpu)
-               start_cpu_timer(cpu);
-       return 0;
-}
-__initcall(cpucache_init);
-#endif
-
-#ifdef SLUB_RESILIENCY_TEST
-static unsigned long validate_slab_cache(struct kmem_cache *s);
-
-static void resiliency_test(void)
-{
-       u8 *p;
-
-       printk(KERN_ERR "SLUB resiliency testing\n");
-       printk(KERN_ERR "-----------------------\n");
-       printk(KERN_ERR "A. Corruption after allocation\n");
-
-       p = kzalloc(16, GFP_KERNEL);
-       p[16] = 0x12;
-       printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
-                       " 0x12->0x%p\n\n", p + 16);
-
-       validate_slab_cache(kmalloc_caches + 4);
-
-       /* Hmmm... The next two are dangerous */
-       p = kzalloc(32, GFP_KERNEL);
-       p[32 + sizeof(void *)] = 0x34;
-       printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
-                       " 0x34 -> -0x%p\n", p);
-       printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
-
-       validate_slab_cache(kmalloc_caches + 5);
-       p = kzalloc(64, GFP_KERNEL);
-       p += 64 + (get_cycles() & 0xff) * sizeof(void *);
-       *p = 0x56;
-       printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
-                                                                       p);
-       printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
-       validate_slab_cache(kmalloc_caches + 6);
-
-       printk(KERN_ERR "\nB. Corruption after free\n");
-       p = kzalloc(128, GFP_KERNEL);
-       kfree(p);
-       *p = 0x78;
-       printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
-       validate_slab_cache(kmalloc_caches + 7);
-
-       p = kzalloc(256, GFP_KERNEL);
-       kfree(p);
-       p[50] = 0x9a;
-       printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p);
-       validate_slab_cache(kmalloc_caches + 8);
-
-       p = kzalloc(512, GFP_KERNEL);
-       kfree(p);
-       p[512] = 0xab;
-       printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
-       validate_slab_cache(kmalloc_caches + 9);
-}
-#else
-static void resiliency_test(void) {};
-#endif
-
-/*
- * These are not as efficient as kmalloc for the non debug case.
- * We do not have the page struct available so we have to touch one
- * cacheline in struct kmem_cache to check slab flags.
- */
 void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
 {
        struct kmem_cache *s = get_slab(size, gfpflags);
@@ -2607,13 +2632,12 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        return slab_alloc(s, gfpflags, node, caller);
 }
 
-#ifdef CONFIG_SYSFS
-
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
 static int validate_slab(struct kmem_cache *s, struct page *page)
 {
        void *p;
        void *addr = page_address(page);
-       unsigned long map[BITS_TO_LONGS(s->objects)];
+       DECLARE_BITMAP(map, s->objects);
 
        if (!check_slab(s, page) ||
                        !on_freelist(s, page, NULL))
@@ -2622,14 +2646,14 @@ static int validate_slab(struct kmem_cache *s, struct page *page)
        /* Now we know that a valid freelist exists */
        bitmap_zero(map, s->objects);
 
-       for(p = page->freelist; p; p = get_freepointer(s, p)) {
-               set_bit((p - addr) / s->size, map);
+       for_each_free_object(p, s, page->freelist) {
+               set_bit(slab_index(p, s, addr), map);
                if (!check_object(s, page, p, 0))
                        return 0;
        }
 
-       for(p = addr; p < addr + s->objects * s->size; p += s->size)
-               if (!test_bit((p - addr) / s->size, map))
+       for_each_object(p, s, addr)
+               if (!test_bit(slab_index(p, s, addr), map))
                        if (!check_object(s, page, p, 1))
                                return 0;
        return 1;
@@ -2645,12 +2669,12 @@ static void validate_slab_slab(struct kmem_cache *s, struct page *page)
                        s->name, page);
 
        if (s->flags & DEBUG_DEFAULT_FLAGS) {
-               if (!PageError(page))
-                       printk(KERN_ERR "SLUB %s: PageError not set "
+               if (!SlabDebug(page))
+                       printk(KERN_ERR "SLUB %s: SlabDebug not set "
                                "on slab 0x%p\n", s->name, page);
        } else {
-               if (PageError(page))
-                       printk(KERN_ERR "SLUB %s: PageError set on "
+               if (SlabDebug(page))
+                       printk(KERN_ERR "SLUB %s: SlabDebug set on "
                                "slab 0x%p\n", s->name, page);
        }
 }
@@ -2702,14 +2726,76 @@ static unsigned long validate_slab_cache(struct kmem_cache *s)
        return count;
 }
 
+#ifdef SLUB_RESILIENCY_TEST
+static void resiliency_test(void)
+{
+       u8 *p;
+
+       printk(KERN_ERR "SLUB resiliency testing\n");
+       printk(KERN_ERR "-----------------------\n");
+       printk(KERN_ERR "A. Corruption after allocation\n");
+
+       p = kzalloc(16, GFP_KERNEL);
+       p[16] = 0x12;
+       printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
+                       " 0x12->0x%p\n\n", p + 16);
+
+       validate_slab_cache(kmalloc_caches + 4);
+
+       /* Hmmm... The next two are dangerous */
+       p = kzalloc(32, GFP_KERNEL);
+       p[32 + sizeof(void *)] = 0x34;
+       printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
+                       " 0x34 -> -0x%p\n", p);
+       printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+
+       validate_slab_cache(kmalloc_caches + 5);
+       p = kzalloc(64, GFP_KERNEL);
+       p += 64 + (get_cycles() & 0xff) * sizeof(void *);
+       *p = 0x56;
+       printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
+                                                                       p);
+       printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+       validate_slab_cache(kmalloc_caches + 6);
+
+       printk(KERN_ERR "\nB. Corruption after free\n");
+       p = kzalloc(128, GFP_KERNEL);
+       kfree(p);
+       *p = 0x78;
+       printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
+       validate_slab_cache(kmalloc_caches + 7);
+
+       p = kzalloc(256, GFP_KERNEL);
+       kfree(p);
+       p[50] = 0x9a;
+       printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p);
+       validate_slab_cache(kmalloc_caches + 8);
+
+       p = kzalloc(512, GFP_KERNEL);
+       kfree(p);
+       p[512] = 0xab;
+       printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
+       validate_slab_cache(kmalloc_caches + 9);
+}
+#else
+static void resiliency_test(void) {};
+#endif
+
 /*
- * Generate lists of locations where slabcache objects are allocated
+ * Generate lists of code addresses where slabcache objects are allocated
  * and freed.
  */
 
 struct location {
        unsigned long count;
        void *addr;
+       long long sum_time;
+       long min_time;
+       long max_time;
+       long min_pid;
+       long max_pid;
+       cpumask_t cpus;
+       nodemask_t nodes;
 };
 
 struct loc_track {
@@ -2750,11 +2836,12 @@ static int alloc_loc_track(struct loc_track *t, unsigned long max)
 }
 
 static int add_location(struct loc_track *t, struct kmem_cache *s,
-                                               void *addr)
+                               const struct track *track)
 {
        long start, end, pos;
        struct location *l;
        void *caddr;
+       unsigned long age = jiffies - track->when;
 
        start = -1;
        end = t->count;
@@ -2770,19 +2857,36 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
                        break;
 
                caddr = t->loc[pos].addr;
-               if (addr == caddr) {
-                       t->loc[pos].count++;
+               if (track->addr == caddr) {
+
+                       l = &t->loc[pos];
+                       l->count++;
+                       if (track->when) {
+                               l->sum_time += age;
+                               if (age < l->min_time)
+                                       l->min_time = age;
+                               if (age > l->max_time)
+                                       l->max_time = age;
+
+                               if (track->pid < l->min_pid)
+                                       l->min_pid = track->pid;
+                               if (track->pid > l->max_pid)
+                                       l->max_pid = track->pid;
+
+                               cpu_set(track->cpu, l->cpus);
+                       }
+                       node_set(page_to_nid(virt_to_page(track)), l->nodes);
                        return 1;
                }
 
-               if (addr < caddr)
+               if (track->addr < caddr)
                        end = pos;
                else
                        start = pos;
        }
 
        /*
-        * Not found. Insert new tracking element
+        * Not found. Insert new tracking element.
         */
        if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max))
                return 0;
@@ -2793,7 +2897,16 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
                        (t->count - pos) * sizeof(struct location));
        t->count++;
        l->count = 1;
-       l->addr = addr;
+       l->addr = track->addr;
+       l->sum_time = age;
+       l->min_time = age;
+       l->max_time = age;
+       l->min_pid = track->pid;
+       l->max_pid = track->pid;
+       cpus_clear(l->cpus);
+       cpu_set(track->cpu, l->cpus);
+       nodes_clear(l->nodes);
+       node_set(page_to_nid(virt_to_page(track)), l->nodes);
        return 1;
 }
 
@@ -2801,19 +2914,16 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
                struct page *page, enum track_item alloc)
 {
        void *addr = page_address(page);
-       unsigned long map[BITS_TO_LONGS(s->objects)];
+       DECLARE_BITMAP(map, s->objects);
        void *p;
 
        bitmap_zero(map, s->objects);
-       for (p = page->freelist; p; p = get_freepointer(s, p))
-               set_bit((p - addr) / s->size, map);
+       for_each_free_object(p, s, page->freelist)
+               set_bit(slab_index(p, s, addr), map);
 
-       for (p = addr; p < addr + s->objects * s->size; p += s->size)
-               if (!test_bit((p - addr) / s->size, map)) {
-                       void *addr = get_track(s, p, alloc)->addr;
-
-                       add_location(t, s, addr);
-               }
+       for_each_object(p, s, addr)
+               if (!test_bit(slab_index(p, s, addr), map))
+                       add_location(t, s, get_track(s, p, alloc));
 }
 
 static int list_locations(struct kmem_cache *s, char *buf,
@@ -2847,15 +2957,47 @@ static int list_locations(struct kmem_cache *s, char *buf,
        }
 
        for (i = 0; i < t.count; i++) {
-               void *addr = t.loc[i].addr;
+               struct location *l = &t.loc[i];
 
                if (n > PAGE_SIZE - 100)
                        break;
-               n += sprintf(buf + n, "%7ld ", t.loc[i].count);
-               if (addr)
-                       n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr);
+               n += sprintf(buf + n, "%7ld ", l->count);
+
+               if (l->addr)
+                       n += sprint_symbol(buf + n, (unsigned long)l->addr);
                else
                        n += sprintf(buf + n, "<not-available>");
+
+               if (l->sum_time != l->min_time) {
+                       unsigned long remainder;
+
+                       n += sprintf(buf + n, " age=%ld/%ld/%ld",
+                       l->min_time,
+                       div_long_long_rem(l->sum_time, l->count, &remainder),
+                       l->max_time);
+               } else
+                       n += sprintf(buf + n, " age=%ld",
+                               l->min_time);
+
+               if (l->min_pid != l->max_pid)
+                       n += sprintf(buf + n, " pid=%ld-%ld",
+                               l->min_pid, l->max_pid);
+               else
+                       n += sprintf(buf + n, " pid=%ld",
+                               l->min_pid);
+
+               if (num_online_cpus() > 1 && !cpus_empty(l->cpus)) {
+                       n += sprintf(buf + n, " cpus=");
+                       n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+                                       l->cpus);
+               }
+
+               if (num_online_nodes() > 1 && !nodes_empty(l->nodes)) {
+                       n += sprintf(buf + n, " nodes=");
+                       n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+                                       l->nodes);
+               }
+
                n += sprintf(buf + n, "\n");
        }
 
@@ -3491,6 +3633,7 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
 
 static int __init slab_sysfs_init(void)
 {
+       struct list_head *h;
        int err;
 
        err = subsystem_register(&slab_subsys);
@@ -3499,7 +3642,15 @@ static int __init slab_sysfs_init(void)
                return -ENOSYS;
        }
 
-       finish_bootstrap();
+       slab_state = SYSFS;
+
+       list_for_each(h, &slab_caches) {
+               struct kmem_cache *s =
+                       container_of(h, struct kmem_cache, list);
+
+               err = sysfs_slab_add(s);
+               BUG_ON(err);
+       }
 
        while (alias_list) {
                struct saved_alias *al = alias_list;
@@ -3515,6 +3666,4 @@ static int __init slab_sysfs_init(void)
 }
 
 __initcall(slab_sysfs_init);
-#else
-__initcall(finish_bootstrap);
 #endif
index 218c52a24a216831a347736cde51045563854770..d3cb966fe9920734f9c97a1fb27cdda36829f493 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -488,7 +488,7 @@ static int cpu_swap_callback(struct notifier_block *nfb,
        long *committed;
 
        committed = &per_cpu(committed_space, (long)hcpu);
-       if (action == CPU_DEAD) {
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
                atomic_add(*committed, &vm_committed_space);
                *committed = 0;
                __lru_add_drain((long)hcpu);
index 9ef9071f99bcd7322b8e1f6808a477403b891211..c4c5205a9c35f82c2dc34b52b4b37a8b0a0ecc44 100644 (file)
@@ -48,9 +48,8 @@ void grab_swap_token(void)
                if (current_interval < current->mm->last_interval)
                        current->mm->token_priority++;
                else {
-                       current->mm->token_priority--;
-                       if (unlikely(current->mm->token_priority < 0))
-                               current->mm->token_priority = 0;
+                       if (likely(current->mm->token_priority > 0))
+                               current->mm->token_priority--;
                }
                /* Check if we deserve the token */
                if (current->mm->token_priority >
index 0f4b6d18ab0ed663360e0fba11f46f23e8c6b5b3..4fbe1a2da5fb973acc352b1b17d87ca390aab376 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/swap.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
+#include <linux/highmem.h>
 #include <linux/pagevec.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/buffer_head.h> /* grr. try_to_release_page,
@@ -46,7 +47,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
 
 static inline void truncate_partial_page(struct page *page, unsigned partial)
 {
-       memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+       zero_user_page(page, partial, PAGE_CACHE_SIZE - partial, KM_USER0);
        if (PagePrivate(page))
                do_invalidatepage(page, partial);
 }
index 1c8e75a1cfcd30dba6a59c84de754f9dd9be8ec6..1be5a6376ef0719b5e46937924a8a66cf59a35f1 100644 (file)
@@ -1528,7 +1528,7 @@ static int __devinit cpu_callback(struct notifier_block *nfb,
        pg_data_t *pgdat;
        cpumask_t mask;
 
-       if (action == CPU_ONLINE) {
+       if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) {
                for_each_online_pgdat(pgdat) {
                        mask = node_to_cpumask(pgdat->node_id);
                        if (any_online_cpu(mask) != NR_CPUS)
index 6c488d6ac425d948b7b77d78a6cac899be16af6a..8faf27e5aa98b8fdaee347963e220febef2f45e9 100644 (file)
@@ -281,6 +281,17 @@ EXPORT_SYMBOL(dec_zone_page_state);
 
 /*
  * Update the zone counters for one cpu.
+ *
+ * Note that refresh_cpu_vm_stats strives to only access
+ * node local memory. The per cpu pagesets on remote zones are placed
+ * in the memory local to the processor using that pageset. So the
+ * loop over all zones will access a series of cachelines local to
+ * the processor.
+ *
+ * The call to zone_page_state_add updates the cachelines with the
+ * statistics in the remote zone struct as well as the global cachelines
+ * with the global counters. These could cause remote node cache line
+ * bouncing and will have to be only done when necessary.
  */
 void refresh_cpu_vm_stats(int cpu)
 {
@@ -289,21 +300,54 @@ void refresh_cpu_vm_stats(int cpu)
        unsigned long flags;
 
        for_each_zone(zone) {
-               struct per_cpu_pageset *pcp;
+               struct per_cpu_pageset *p;
 
                if (!populated_zone(zone))
                        continue;
 
-               pcp = zone_pcp(zone, cpu);
+               p = zone_pcp(zone, cpu);
 
                for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-                       if (pcp->vm_stat_diff[i]) {
+                       if (p->vm_stat_diff[i]) {
                                local_irq_save(flags);
-                               zone_page_state_add(pcp->vm_stat_diff[i],
+                               zone_page_state_add(p->vm_stat_diff[i],
                                        zone, i);
-                               pcp->vm_stat_diff[i] = 0;
+                               p->vm_stat_diff[i] = 0;
+#ifdef CONFIG_NUMA
+                               /* 3 seconds idle till flush */
+                               p->expire = 3;
+#endif
                                local_irq_restore(flags);
                        }
+#ifdef CONFIG_NUMA
+               /*
+                * Deal with draining the remote pageset of this
+                * processor
+                *
+                * Check if there are pages remaining in this pageset
+                * if not then there is nothing to expire.
+                */
+               if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
+                       continue;
+
+               /*
+                * We never drain zones local to this processor.
+                */
+               if (zone_to_nid(zone) == numa_node_id()) {
+                       p->expire = 0;
+                       continue;
+               }
+
+               p->expire--;
+               if (p->expire)
+                       continue;
+
+               if (p->pcp[0].count)
+                       drain_zone_pages(zone, p->pcp + 0);
+
+               if (p->pcp[1].count)
+                       drain_zone_pages(zone, p->pcp + 1);
+#endif
        }
 }
 
@@ -640,6 +684,24 @@ const struct seq_operations vmstat_op = {
 #endif /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
+int sysctl_stat_interval __read_mostly = HZ;
+
+static void vmstat_update(struct work_struct *w)
+{
+       refresh_cpu_vm_stats(smp_processor_id());
+       schedule_delayed_work(&__get_cpu_var(vmstat_work),
+               sysctl_stat_interval);
+}
+
+static void __devinit start_cpu_timer(int cpu)
+{
+       struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
+
+       INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
+       schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
+}
+
 /*
  * Use the cpu notifier to insure that the thresholds are recalculated
  * when necessary.
@@ -648,10 +710,24 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
                unsigned long action,
                void *hcpu)
 {
+       long cpu = (long)hcpu;
+
        switch (action) {
-       case CPU_UP_PREPARE:
-       case CPU_UP_CANCELED:
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               start_cpu_timer(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
+               per_cpu(vmstat_work, cpu).work.func = NULL;
+               break;
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               start_cpu_timer(cpu);
+               break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                refresh_zone_stat_thresholds();
                break;
        default:
@@ -665,8 +741,13 @@ static struct notifier_block __cpuinitdata vmstat_notifier =
 
 int __init setup_vmstat(void)
 {
+       int cpu;
+
        refresh_zone_stat_thresholds();
        register_cpu_notifier(&vmstat_notifier);
+
+       for_each_online_cpu(cpu)
+               start_cpu_timer(cpu);
        return 0;
 }
 module_init(setup_vmstat)
index caeacd16656a044588d54b3ede24ea80e0252c59..f3de72978ab61e1866e1fa4e2d585abaf5496901 100644 (file)
@@ -218,6 +218,7 @@ config FIB_RULES
        bool
 
 menu "Wireless"
+       depends on !S390
 
 source "net/wireless/Kconfig"
 source "net/mac80211/Kconfig"
index 43dd86fca4d3d0cd558d6bce78793e6113a2604e..2a72aa96a568e023ace382de13205de1a17f016d 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig HAMRADIO
-       depends on NET
+       depends on NET && !S390
        bool "Amateur Radio support"
        help
          If you want to connect your Linux box to an amateur radio, answer Y
index 6929490d095afaf8d5321803a8cfa42b4e7da0ca..7725da95a767185c5a3cccd0713198a1e8070328 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig BT
-       depends on NET
+       depends on NET && !S390
        tristate "Bluetooth subsystem support"
        help
          Bluetooth is low-cost, low-power, short-range wireless technology.
index 3e77e8102e086b20f58a4e3fcf8392eed6cb7403..ceadfcf457c1d6346cf839cf0922d1d57f2a5e91 100644 (file)
@@ -174,7 +174,7 @@ static inline int hidp_queue_event(struct hidp_session *session, struct input_de
 
 static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct hidp_session *session = hid->driver_data;
 
        return hidp_queue_event(session, dev, type, code, value);
@@ -182,7 +182,7 @@ static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigne
 
 static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       struct hidp_session *session = dev->private;
+       struct hidp_session *session = input_get_drvdata(dev);
 
        return hidp_queue_event(session, dev, type, code, value);
 }
@@ -630,7 +630,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co
        struct input_dev *input = session->input;
        int i;
 
-       input->private = session;
+       input_set_drvdata(input, session);
 
        input->name = "Bluetooth HID Boot Protocol Device";
 
@@ -663,7 +663,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co
                input->relbit[0] |= BIT(REL_WHEEL);
        }
 
-       input->cdev.dev = hidp_get_device(session);
+       input->dev.parent = hidp_get_device(session);
 
        input->event = hidp_input_event;
 
@@ -862,7 +862,7 @@ failed:
        if (session->hid)
                hid_free_device(session->hid);
 
-       kfree(session->input);
+       input_free_device(session->input);
        kfree(session);
        return err;
 }
index 4317c1be4d3ff658fa8f8eec221aa8b96f247aaf..8301e2ac747fcf7500a9c3e2999061033b686637 100644 (file)
@@ -3450,7 +3450,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,
        unsigned int cpu, oldcpu = (unsigned long)ocpu;
        struct softnet_data *sd, *oldsd;
 
-       if (action != CPU_DEAD)
+       if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)
                return NOTIFY_OK;
 
        local_irq_disable();
index 5d25697920b1ae183fe83e627044c601cb845632..051430545a05364bb9864df299c93130edaa626a 100644 (file)
@@ -338,7 +338,7 @@ static int flow_cache_cpu(struct notifier_block *nfb,
                          unsigned long action,
                          void *hcpu)
 {
-       if (action == CPU_DEAD)
+       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
                __flow_cache_shrink((unsigned long)hcpu, 0);
        return NOTIFY_OK;
 }
index e3c26a9ccad6e097b098bc0783d9076c589199d9..a5e372b9ec4df3a866ff4a26b44c4fed96021b8b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
-#include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
@@ -27,8 +26,7 @@
 
 
 enum lw_bits {
-       LW_RUNNING = 0,
-       LW_SE_USED
+       LW_URGENT = 0,
 };
 
 static unsigned long linkwatch_flags;
@@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent;
 static void linkwatch_event(struct work_struct *dummy);
 static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);
 
-static LIST_HEAD(lweventlist);
+static struct net_device *lweventlist;
 static DEFINE_SPINLOCK(lweventlist_lock);
 
-struct lw_event {
-       struct list_head list;
-       struct net_device *dev;
-};
-
-/* Avoid kmalloc() for most systems */
-static struct lw_event singleevent;
-
 static unsigned char default_operstate(const struct net_device *dev)
 {
        if (!netif_carrier_ok(dev))
@@ -87,25 +77,102 @@ static void rfc2863_policy(struct net_device *dev)
 }
 
 
-/* Must be called with the rtnl semaphore held */
-void linkwatch_run_queue(void)
+static int linkwatch_urgent_event(struct net_device *dev)
 {
-       struct list_head head, *n, *next;
+       return netif_running(dev) && netif_carrier_ok(dev) &&
+              dev->qdisc != dev->qdisc_sleeping;
+}
+
+
+static void linkwatch_add_event(struct net_device *dev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&lweventlist_lock, flags);
+       dev->link_watch_next = lweventlist;
+       lweventlist = dev;
+       spin_unlock_irqrestore(&lweventlist_lock, flags);
+}
+
+
+static void linkwatch_schedule_work(int urgent)
+{
+       unsigned long delay = linkwatch_nextevent - jiffies;
+
+       if (test_bit(LW_URGENT, &linkwatch_flags))
+               return;
+
+       /* Minimise down-time: drop delay for up event. */
+       if (urgent) {
+               if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
+                       return;
+               delay = 0;
+       }
+
+       /* If we wrap around we'll delay it by at most HZ. */
+       if (delay > HZ)
+               delay = 0;
+
+       /*
+        * This is true if we've scheduled it immeditately or if we don't
+        * need an immediate execution and it's already pending.
+        */
+       if (schedule_delayed_work(&linkwatch_work, delay) == !delay)
+               return;
+
+       /* Don't bother if there is nothing urgent. */
+       if (!test_bit(LW_URGENT, &linkwatch_flags))
+               return;
+
+       /* It's already running which is good enough. */
+       if (!cancel_delayed_work(&linkwatch_work))
+               return;
+
+       /* Otherwise we reschedule it again for immediate exection. */
+       schedule_delayed_work(&linkwatch_work, 0);
+}
+
+
+static void __linkwatch_run_queue(int urgent_only)
+{
+       struct net_device *next;
+
+       /*
+        * Limit the number of linkwatch events to one
+        * per second so that a runaway driver does not
+        * cause a storm of messages on the netlink
+        * socket.  This limit does not apply to up events
+        * while the device qdisc is down.
+        */
+       if (!urgent_only)
+               linkwatch_nextevent = jiffies + HZ;
+       /* Limit wrap-around effect on delay. */
+       else if (time_after(linkwatch_nextevent, jiffies + HZ))
+               linkwatch_nextevent = jiffies;
+
+       clear_bit(LW_URGENT, &linkwatch_flags);
 
        spin_lock_irq(&lweventlist_lock);
-       list_replace_init(&lweventlist, &head);
+       next = lweventlist;
+       lweventlist = NULL;
        spin_unlock_irq(&lweventlist_lock);
 
-       list_for_each_safe(n, next, &head) {
-               struct lw_event *event = list_entry(n, struct lw_event, list);
-               struct net_device *dev = event->dev;
+       while (next) {
+               struct net_device *dev = next;
 
-               if (event == &singleevent) {
-                       clear_bit(LW_SE_USED, &linkwatch_flags);
-               } else {
-                       kfree(event);
+               next = dev->link_watch_next;
+
+               if (urgent_only && !linkwatch_urgent_event(dev)) {
+                       linkwatch_add_event(dev);
+                       continue;
                }
 
+               /*
+                * Make sure the above read is complete since it can be
+                * rewritten as soon as we clear the bit below.
+                */
+               smp_mb__before_clear_bit();
+
                /* We are about to handle this device,
                 * so new events can be accepted
                 */
@@ -124,58 +191,39 @@ void linkwatch_run_queue(void)
 
                dev_put(dev);
        }
+
+       if (lweventlist)
+               linkwatch_schedule_work(0);
 }
 
 
-static void linkwatch_event(struct work_struct *dummy)
+/* Must be called with the rtnl semaphore held */
+void linkwatch_run_queue(void)
 {
-       /* Limit the number of linkwatch events to one
-        * per second so that a runaway driver does not
-        * cause a storm of messages on the netlink
-        * socket
-        */
-       linkwatch_nextevent = jiffies + HZ;
-       clear_bit(LW_RUNNING, &linkwatch_flags);
+       __linkwatch_run_queue(0);
+}
 
+
+static void linkwatch_event(struct work_struct *dummy)
+{
        rtnl_lock();
-       linkwatch_run_queue();
+       __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));
        rtnl_unlock();
 }
 
 
 void linkwatch_fire_event(struct net_device *dev)
 {
-       if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
-               unsigned long flags;
-               struct lw_event *event;
-
-               if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) {
-                       event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC);
-
-                       if (unlikely(event == NULL)) {
-                               clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
-                               return;
-                       }
-               } else {
-                       event = &singleevent;
-               }
+       int urgent = linkwatch_urgent_event(dev);
 
+       if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
                dev_hold(dev);
-               event->dev = dev;
-
-               spin_lock_irqsave(&lweventlist_lock, flags);
-               list_add_tail(&event->list, &lweventlist);
-               spin_unlock_irqrestore(&lweventlist_lock, flags);
 
-               if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) {
-                       unsigned long delay = linkwatch_nextevent - jiffies;
+               linkwatch_add_event(dev);
+       } else if (!urgent)
+               return;
 
-                       /* If we wrap around we'll delay it by at most HZ. */
-                       if (delay > HZ)
-                               delay = 0;
-                       schedule_delayed_work(&linkwatch_work, delay);
-               }
-       }
+       linkwatch_schedule_work(urgent);
 }
 
 EXPORT_SYMBOL(linkwatch_fire_event);
index 9fbe87c938022b79c4f77f73d25cc328d051fbfe..bfa910b6ad25935af657beea80cadab38e843ee8 100644 (file)
@@ -1839,7 +1839,7 @@ static inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *que
 }
 
 /*
- * The DECnet spec requires the the "routing layer" accepts packets which
+ * The DECnet spec requires that the "routing layer" accepts packets which
  * are at least 230 bytes in size. This excludes any headers which the NSP
  * layer might add, so we always assume that we'll be using the maximal
  * length header on data packets. The variation in length is due to the
index 305a09de85a57d924a187abe72148c315b06868d..960ad13f5e9f41fc724aff31ee842dcaaf4a5e23 100644 (file)
@@ -94,6 +94,21 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
        return -1;
 }
 
+u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+{
+       const struct ieee80211_channel * ch;
+
+       /* Driver needs to initialize the geography map before using
+        * these helper functions */
+       if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+               return 0;
+
+       ch = ieee80211_get_channel(ieee, channel);
+       if (!ch->channel)
+               return 0;
+       return ch->freq;
+}
+
 u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
 {
        int i;
@@ -174,6 +189,7 @@ EXPORT_SYMBOL(ieee80211_get_channel);
 EXPORT_SYMBOL(ieee80211_get_channel_flags);
 EXPORT_SYMBOL(ieee80211_is_valid_channel);
 EXPORT_SYMBOL(ieee80211_freq_to_channel);
+EXPORT_SYMBOL(ieee80211_channel_to_freq);
 EXPORT_SYMBOL(ieee80211_channel_to_index);
 EXPORT_SYMBOL(ieee80211_set_geo);
 EXPORT_SYMBOL(ieee80211_get_geo);
index cee5e13bc4270687f76cea2330543f3d373930c7..523a137d49dd2b083406ee8517939f4c7e29c542 100644 (file)
@@ -89,15 +89,17 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
        }
 
-       /* Add frequency/channel */
+       /* Add channel and frequency */
        iwe.cmd = SIOCGIWFREQ;
-/*     iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
-       iwe.u.freq.e = 3; */
        iwe.u.freq.m = network->channel;
        iwe.u.freq.e = 0;
        iwe.u.freq.i = 0;
        start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
 
+       iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+       iwe.u.freq.e = 6;
+       start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
        /* Add encryption capability */
        iwe.cmd = SIOCGIWENCODE;
        if (network->capability & WLAN_CAPABILITY_PRIVACY)
index e62aee0ec4c588c9373ba484ca79beee2e20996e..c68196cc56abaea14b3922618fe67f7ca94f6b4f 100644 (file)
@@ -130,7 +130,7 @@ config IP_ROUTE_MULTIPATH_RR
        tristate "MULTIPATH: round robin algorithm"
        depends on IP_ROUTE_MULTIPATH_CACHED
        help
-         Mulitpath routes are chosen according to Round Robin
+         Multipath routes are chosen according to Round Robin
 
 config IP_ROUTE_MULTIPATH_RANDOM
        tristate "MULTIPATH: random algorithm"
@@ -651,7 +651,7 @@ config TCP_MD5SIG
        select CRYPTO
        select CRYPTO_MD5
        ---help---
-         RFC2385 specifices a method of giving MD5 protection to TCP sessions.
+         RFC2385 specifies a method of giving MD5 protection to TCP sessions.
          Its main (only?) use is to protect BGP sessions between core routers
          on the Internet.
 
index e1f18489db1d4f2cb36db0a20d774833f6573558..86a2b52aad3836c6aef2edf83413c3bda42a1319 100644 (file)
@@ -629,7 +629,7 @@ doi_walk_return:
  * @domain: the domain to add
  *
  * Description:
- * Adds the @domain to the the DOI specified by @doi_def, this function
+ * Adds the @domain to the DOI specified by @doi_def, this function
  * should only be called by external functions (i.e. NetLabel).  This function
  * does allocate memory.  Returns zero on success, negative values on failure.
  *
index b3050a6817e7af88ed58b7213ee342b4c6f9f1bd..68fe1d4d0210384d358947acbdd55ed17bdc4f8d 100644 (file)
@@ -2387,6 +2387,7 @@ void ip_vs_control_cleanup(void)
        EnterFunction(2);
        ip_vs_trash_cleanup();
        cancel_rearming_delayed_work(&defense_work);
+       cancel_work_sync(&defense_work.work);
        ip_vs_kill_estimator(&ip_vs_stats);
        unregister_sysctl_table(sysctl_header);
        proc_net_remove("ip_vs_stats");
index ff366f7390d9c7e15d4e5c42bafef20a3ccf40d0..dd7c128f9db33e48cc3cd4585a154c7dfa40f619 100644 (file)
@@ -18,7 +18,7 @@
  * The SED algorithm attempts to minimize each job's expected delay until
  * completion. The expected delay that the job will experience is
  * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
- * jobs on the the ith server and Ui is the fixed service rate (weight) of
+ * jobs on the ith server and Ui is the fixed service rate (weight) of
  * the ith server. The SED algorithm adopts a greedy policy that each does
  * what is in its own best interest, i.e. to join the queue which would
  * minimize its expected delay of completion.
index 7edea2a1696c010930cd77d89c76cc558f217063..75c0230625331e91ac2ed5d28841072a24a8db33 100644 (file)
@@ -15,128 +15,34 @@ MODULE_DESCRIPTION("arptables filter table");
 #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
                           (1 << NF_ARP_FORWARD))
 
-/* Standard entry. */
-struct arpt_standard
-{
-       struct arpt_entry entry;
-       struct arpt_standard_target target;
-};
-
-struct arpt_error_target
-{
-       struct arpt_entry_target target;
-       char errorname[ARPT_FUNCTION_MAXNAMELEN];
-};
-
-struct arpt_error
-{
-       struct arpt_entry entry;
-       struct arpt_error_target target;
-};
-
 static struct
 {
        struct arpt_replace repl;
        struct arpt_standard entries[3];
        struct arpt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
-      { [NF_ARP_IN] = 0,
-       [NF_ARP_OUT] = sizeof(struct arpt_standard),
-       [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
-      { [NF_ARP_IN] = 0,
-       [NF_ARP_OUT] = sizeof(struct arpt_standard),
-       [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
-      0, NULL, { } },
-    {
-           /* ARP_IN */
-           {
-                   {
-                           {
-                                   { 0 }, { 0 }, { 0 }, { 0 },
-                                   0, 0,
-                                   { { 0, }, { 0, } },
-                                   { { 0, }, { 0, } },
-                                   0, 0,
-                                   0, 0,
-                                   0, 0,
-                                   "", "", { 0 }, { 0 },
-                                   0, 0
-                           },
-                           sizeof(struct arpt_entry),
-                           sizeof(struct arpt_standard),
-                           0,
-                           { 0, 0 }, { } },
-                   { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-                     -NF_ACCEPT - 1 }
-           },
-           /* ARP_OUT */
-           {
-                   {
-                           {
-                                   { 0 }, { 0 }, { 0 }, { 0 },
-                                   0, 0,
-                                   { { 0, }, { 0, } },
-                                   { { 0, }, { 0, } },
-                                   0, 0,
-                                   0, 0,
-                                   0, 0,
-                                   "", "", { 0 }, { 0 },
-                                   0, 0
-                           },
-                           sizeof(struct arpt_entry),
-                           sizeof(struct arpt_standard),
-                           0,
-                           { 0, 0 }, { } },
-                   { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-                     -NF_ACCEPT - 1 }
-           },
-           /* ARP_FORWARD */
-           {
-                   {
-                           {
-                                   { 0 }, { 0 }, { 0 }, { 0 },
-                                   0, 0,
-                                   { { 0, }, { 0, } },
-                                   { { 0, }, { 0, } },
-                                   0, 0,
-                                   0, 0,
-                                   0, 0,
-                                   "", "", { 0 }, { 0 },
-                                   0, 0
-                           },
-                           sizeof(struct arpt_entry),
-                           sizeof(struct arpt_standard),
-                           0,
-                           { 0, 0 }, { } },
-                   { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
-                     -NF_ACCEPT - 1 }
-           }
-    },
-    /* ERROR */
-    {
-           {
-                   {
-                           { 0 }, { 0 }, { 0 }, { 0 },
-                           0, 0,
-                           { { 0, }, { 0, } },
-                           { { 0, }, { 0, } },
-                           0, 0,
-                           0, 0,
-                           0, 0,
-                           "", "", { 0 }, { 0 },
-                           0, 0
-                   },
-                   sizeof(struct arpt_entry),
-                   sizeof(struct arpt_error),
-                   0,
-                   { 0, 0 }, { } },
-           { { { { ARPT_ALIGN(sizeof(struct arpt_error_target)), ARPT_ERROR_TARGET } },
-               { } },
-             "ERROR"
-           }
-    }
+} initial_table __initdata = {
+       .repl = {
+               .name = "filter",
+               .valid_hooks = FILTER_VALID_HOOKS,
+               .num_entries = 4,
+               .size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
+               .hook_entry = {
+                       [NF_ARP_IN] = 0,
+                       [NF_ARP_OUT] = sizeof(struct arpt_standard),
+                       [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+               },
+               .underflow = {
+                       [NF_ARP_IN] = 0,
+                       [NF_ARP_OUT] = sizeof(struct arpt_standard),
+                       [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+               },
+       },
+       .entries = {
+               ARPT_STANDARD_INIT(NF_ACCEPT),  /* ARP_IN */
+               ARPT_STANDARD_INIT(NF_ACCEPT),  /* ARP_OUT */
+               ARPT_STANDARD_INIT(NF_ACCEPT),  /* ARP_FORWARD */
+       },
+       .term = ARPT_ERROR_INIT,
 };
 
 static struct arpt_table packet_filter = {
index 42728909eba0577a64693f4a460eb2f1edf133a9..4f51c1d7d2d60910de959be5554f01ca6bbcd664 100644 (file)
@@ -26,53 +26,29 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[3];
        struct ipt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
-      { [NF_IP_LOCAL_IN] = 0,
-       [NF_IP_FORWARD] = sizeof(struct ipt_standard),
-       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      { [NF_IP_LOCAL_IN] = 0,
-       [NF_IP_FORWARD] = sizeof(struct ipt_standard),
-       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
-      0, NULL, { } },
-    {
-           /* LOCAL_IN */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* FORWARD */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_OUT */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-       0,
-       sizeof(struct ipt_entry),
-       sizeof(struct ipt_error),
-       0, { 0, 0 }, { } },
-      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
-         { } },
-       "ERROR"
-      }
-    }
+} initial_table __initdata = {
+       .repl = {
+               .name = "filter",
+               .valid_hooks = FILTER_VALID_HOOKS,
+               .num_entries = 4,
+               .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+               .hook_entry = {
+                       [NF_IP_LOCAL_IN] = 0,
+                       [NF_IP_FORWARD] = sizeof(struct ipt_standard),
+                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+               },
+               .underflow = {
+                       [NF_IP_LOCAL_IN] = 0,
+                       [NF_IP_FORWARD] = sizeof(struct ipt_standard),
+                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+               },
+       },
+       .entries = {
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_IN */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* FORWARD */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
+       },
+       .term = IPT_ERROR_INIT,                 /* ERROR */
 };
 
 static struct xt_table packet_filter = {
@@ -105,7 +81,8 @@ ipt_local_out_hook(unsigned int hook,
        if ((*pskb)->len < sizeof(struct iphdr)
            || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
                if (net_ratelimit())
-                       printk("ipt_hook: happy cracking.\n");
+                       printk("iptable_filter: ignoring short SOCK_RAW "
+                              "packet.\n");
                return NF_ACCEPT;
        }
 
index 9278802f2742ce14df5a2fba0da8c36b027cbfb6..902446f7cbca8ae630677eb423ae1f0c9540ef56 100644 (file)
@@ -33,73 +33,35 @@ static struct
        struct ipt_replace repl;
        struct ipt_standard entries[5];
        struct ipt_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
-      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING]    = 0,
-       [NF_IP_LOCAL_IN]        = sizeof(struct ipt_standard),
-       [NF_IP_FORWARD]         = sizeof(struct ipt_standard) * 2,
-       [NF_IP_LOCAL_OUT]       = sizeof(struct ipt_standard) * 3,
-       [NF_IP_POST_ROUTING]    = sizeof(struct ipt_standard) * 4 },
-      { [NF_IP_PRE_ROUTING]    = 0,
-       [NF_IP_LOCAL_IN]        = sizeof(struct ipt_standard),
-       [NF_IP_FORWARD]         = sizeof(struct ipt_standard) * 2,
-       [NF_IP_LOCAL_OUT]       = sizeof(struct ipt_standard) * 3,
-       [NF_IP_POST_ROUTING]    = sizeof(struct ipt_standard) * 4 },
-      0, NULL, { } },
-    {
-           /* PRE_ROUTING */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_IN */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* FORWARD */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_OUT */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* POST_ROUTING */
-           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ipt_entry),
-               sizeof(struct ipt_standard),
-               0, { 0, 0 }, { } },
-             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-    },
-    /* ERROR */
-    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-       0,
-       sizeof(struct ipt_entry),
-       sizeof(struct ipt_error),
-       0, { 0, 0 }, { } },
-      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
-         { } },
-       "ERROR"
-      }
-    }
+} initial_table __initdata = {
+       .repl = {
+               .name = "mangle",
+               .valid_hooks = MANGLE_VALID_HOOKS,
+               .num_entries = 6,
+               .size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+               .hook_entry = {
+                       [NF_IP_PRE_ROUTING]     = 0,
+                       [NF_IP_LOCAL_IN]        = sizeof(struct ipt_standard),
+                       [NF_IP_FORWARD]         = sizeof(struct ipt_standard) * 2,
+                       [NF_IP_LOCAL_OUT]       = sizeof(struct ipt_standard) * 3,
+                       [NF_IP_POST_ROUTING]    = sizeof(struct ipt_standard) * 4,
+               },
+               .underflow = {
+                       [NF_IP_PRE_ROUTING]     = 0,
+                       [NF_IP_LOCAL_IN]        = sizeof(struct ipt_standard),
+                       [NF_IP_FORWARD]         = sizeof(struct ipt_standard) * 2,
+                       [NF_IP_LOCAL_OUT]       = sizeof(struct ipt_standard) * 3,
+                       [NF_IP_POST_ROUTING]    = sizeof(struct ipt_standard) * 4,
+               },
+       },
+       .entries = {
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* PRE_ROUTING */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_IN */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* FORWARD */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* POST_ROUTING */
+       },
+       .term = IPT_ERROR_INIT,                 /* ERROR */
 };
 
 static struct xt_table packet_mangler = {
@@ -138,7 +100,8 @@ ipt_local_hook(unsigned int hook,
        if ((*pskb)->len < sizeof(struct iphdr)
            || ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
                if (net_ratelimit())
-                       printk("ipt_hook: happy cracking.\n");
+                       printk("iptable_mangle: ignoring short SOCK_RAW "
+                              "packet.\n");
                return NF_ACCEPT;
        }
 
index 18c3d4c9ff51e23ecd8ffece105407d7fed94e91..d6e5033956844a4a86c23c721dba749f9d5fe64d 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
 
 #define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
 
@@ -21,62 +22,18 @@ static struct
                .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
                .hook_entry = {
                        [NF_IP_PRE_ROUTING] = 0,
-                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) },
+                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
+               },
                .underflow = {
                        [NF_IP_PRE_ROUTING] = 0,
-                       [NF_IP_LOCAL_OUT]  = sizeof(struct ipt_standard) },
+                       [NF_IP_LOCAL_OUT]  = sizeof(struct ipt_standard)
+               },
        },
        .entries = {
-            /* PRE_ROUTING */
-            {
-                    .entry = {
-                            .target_offset = sizeof(struct ipt_entry),
-                            .next_offset = sizeof(struct ipt_standard),
-                    },
-                    .target = {
-                         .target = {
-                                 .u = {
-                                         .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-                                 },
-                         },
-                         .verdict = -NF_ACCEPT - 1,
-                    },
-            },
-
-            /* LOCAL_OUT */
-            {
-                    .entry = {
-                            .target_offset = sizeof(struct ipt_entry),
-                            .next_offset = sizeof(struct ipt_standard),
-                    },
-                    .target = {
-                            .target = {
-                                    .u = {
-                                            .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-                                    },
-                            },
-                            .verdict = -NF_ACCEPT - 1,
-                    },
-            },
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* PRE_ROUTING */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
        },
-       /* ERROR */
-       .term = {
-               .entry = {
-                       .target_offset = sizeof(struct ipt_entry),
-                       .next_offset = sizeof(struct ipt_error),
-               },
-               .target = {
-                       .target = {
-                               .u = {
-                                       .user = {
-                                               .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
-                                               .name = IPT_ERROR_TARGET,
-                                       },
-                               },
-                       },
-                       .errorname = "ERROR",
-               },
-       }
+       .term = IPT_ERROR_INIT,                 /* ERROR */
 };
 
 static struct xt_table packet_raw = {
@@ -98,6 +55,24 @@ ipt_hook(unsigned int hook,
        return ipt_do_table(pskb, hook, in, out, &packet_raw);
 }
 
+static unsigned int
+ipt_local_hook(unsigned int hook,
+              struct sk_buff **pskb,
+              const struct net_device *in,
+              const struct net_device *out,
+              int (*okfn)(struct sk_buff *))
+{
+       /* root is playing with raw sockets. */
+       if ((*pskb)->len < sizeof(struct iphdr) ||
+           ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+               if (net_ratelimit())
+                       printk("iptable_raw: ignoring short SOCK_RAW"
+                              "packet.\n");
+               return NF_ACCEPT;
+       }
+       return ipt_do_table(pskb, hook, in, out, &packet_raw);
+}
+
 /* 'raw' is the very first table. */
 static struct nf_hook_ops ipt_ops[] = {
        {
@@ -108,7 +83,7 @@ static struct nf_hook_ops ipt_ops[] = {
                .owner = THIS_MODULE,
        },
        {
-               .hook = ipt_hook,
+               .hook = ipt_local_hook,
                .pf = PF_INET,
                .hooknum = NF_IP_LOCAL_OUT,
                .priority = NF_IP_PRI_RAW,
index 2534f718ab9286ae49693f1c1a78e16b3ea5241d..6740736c5e79d74e03bc529f6e0555c6009f6916 100644 (file)
@@ -46,77 +46,20 @@ static struct
                .hook_entry = {
                        [NF_IP_PRE_ROUTING] = 0,
                        [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+               },
                .underflow = {
                        [NF_IP_PRE_ROUTING] = 0,
                        [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
-                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+                       [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+               },
        },
        .entries = {
-               /* PRE_ROUTING */
-               {
-                       .entry = {
-                               .target_offset = sizeof(struct ipt_entry),
-                               .next_offset = sizeof(struct ipt_standard),
-                       },
-                       .target = {
-                               .target = {
-                                       .u = {
-                                               .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-                                       },
-                               },
-                               .verdict = -NF_ACCEPT - 1,
-                       },
-               },
-               /* POST_ROUTING */
-               {
-                       .entry = {
-                               .target_offset = sizeof(struct ipt_entry),
-                               .next_offset = sizeof(struct ipt_standard),
-                       },
-                       .target = {
-                               .target = {
-                                       .u = {
-                                               .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-                                       },
-                               },
-                               .verdict = -NF_ACCEPT - 1,
-                       },
-               },
-               /* LOCAL_OUT */
-               {
-                       .entry = {
-                               .target_offset = sizeof(struct ipt_entry),
-                               .next_offset = sizeof(struct ipt_standard),
-                       },
-                       .target = {
-                               .target = {
-                                       .u = {
-                                               .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
-                                       },
-                               },
-                               .verdict = -NF_ACCEPT - 1,
-                       },
-               },
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* PRE_ROUTING */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* POST_ROUTING */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
        },
-       /* ERROR */
-       .term = {
-               .entry = {
-                       .target_offset = sizeof(struct ipt_entry),
-                       .next_offset = sizeof(struct ipt_error),
-               },
-               .target = {
-                       .target = {
-                               .u = {
-                                       .user = {
-                                               .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
-                                               .name = IPT_ERROR_TARGET,
-                                       },
-                               },
-                       },
-                       .errorname = "ERROR",
-               },
-       }
+       .term = IPT_ERROR_INIT,                 /* ERROR */
 };
 
 static struct xt_table nat_table = {
@@ -230,9 +173,7 @@ static int ipt_dnat_checkentry(const char *tablename,
 }
 
 inline unsigned int
-alloc_null_binding(struct nf_conn *ct,
-                  struct nf_nat_info *info,
-                  unsigned int hooknum)
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
 {
        /* Force range to this IP; let proto decide mapping for
           per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
@@ -251,9 +192,7 @@ alloc_null_binding(struct nf_conn *ct,
 }
 
 unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
-                            struct nf_nat_info *info,
-                            unsigned int hooknum)
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
 {
        __be32 ip
                = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
@@ -275,8 +214,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
                     unsigned int hooknum,
                     const struct net_device *in,
                     const struct net_device *out,
-                    struct nf_conn *ct,
-                    struct nf_nat_info *info)
+                    struct nf_conn *ct)
 {
        int ret;
 
@@ -285,7 +223,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
        if (ret == NF_ACCEPT) {
                if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
                        /* NUL mapping */
-                       ret = alloc_null_binding(ct, info, hooknum);
+                       ret = alloc_null_binding(ct, hooknum);
        }
        return ret;
 }
index 64bbed2ba7808c494281f9940ff227928307634e..55dac36dbc8548dcd3706fda328c2481c66b956d 100644 (file)
@@ -80,7 +80,6 @@ nf_nat_fn(unsigned int hooknum,
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
        struct nf_conn_nat *nat;
-       struct nf_nat_info *info;
        /* maniptype == SRC for postrouting. */
        enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 
@@ -129,7 +128,6 @@ nf_nat_fn(unsigned int hooknum,
                }
                /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
        case IP_CT_NEW:
-               info = &nat->info;
 
                /* Seen it before?  This can happen for loopback, retrans,
                   or local packets.. */
@@ -138,14 +136,13 @@ nf_nat_fn(unsigned int hooknum,
 
                        if (unlikely(nf_ct_is_confirmed(ct)))
                                /* NAT module was loaded late */
-                               ret = alloc_null_binding_confirmed(ct, info,
-                                                                  hooknum);
+                               ret = alloc_null_binding_confirmed(ct, hooknum);
                        else if (hooknum == NF_IP_LOCAL_IN)
                                /* LOCAL_IN hook doesn't have a chain!  */
-                               ret = alloc_null_binding(ct, info, hooknum);
+                               ret = alloc_null_binding(ct, hooknum);
                        else
                                ret = nf_nat_rule_find(pskb, hooknum, in, out,
-                                                      ct, info);
+                                                      ct);
 
                        if (ret != NF_ACCEPT) {
                                return ret;
@@ -160,10 +157,8 @@ nf_nat_fn(unsigned int hooknum,
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
                             ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
-               info = &nat->info;
        }
 
-       NF_CT_ASSERT(info);
        return nf_nat_packet(ct, ctinfo, hooknum, pskb);
 }
 
index 113e0c4c8a928157d51f17abcd47804106ebdeca..4c7e95fa090d181234e3dbb1a2d1934a259c317f 100644 (file)
@@ -118,15 +118,15 @@ static int udp_port_rover;
  * Note about this hash function :
  * Typical use is probably daddr = 0, only dport is going to vary hash
  */
-static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
+static inline unsigned int udp_hash_port(__u16 port)
 {
-       addr ^= addr >> 16;
-       addr ^= addr >> 8;
-       return port ^ addr;
+       return port;
 }
 
 static inline int __udp_lib_port_inuse(unsigned int hash, int port,
-       __be32 daddr, struct hlist_head udptable[])
+                                      const struct sock *this_sk,
+                                      struct hlist_head udptable[],
+                                      const struct udp_get_port_ops *ops)
 {
        struct sock *sk;
        struct hlist_node *node;
@@ -138,7 +138,10 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port,
                inet = inet_sk(sk);
                if (inet->num != port)
                        continue;
-               if (inet->rcv_saddr == daddr)
+               if (this_sk) {
+                       if (ops->saddr_cmp(sk, this_sk))
+                               return 1;
+               } else if (ops->saddr_any(sk))
                        return 1;
        }
        return 0;
@@ -151,12 +154,11 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port,
  *  @snum:        port number to look up
  *  @udptable:    hash list table, must be of UDP_HTABLE_SIZE
  *  @port_rover:  pointer to record of last unallocated port
- *  @saddr_comp:  AF-dependent comparison of bound local IP addresses
+ *  @ops:         AF-dependent address operations
  */
 int __udp_lib_get_port(struct sock *sk, unsigned short snum,
                       struct hlist_head udptable[], int *port_rover,
-                      int (*saddr_comp)(const struct sock *sk1,
-                                        const struct sock *sk2 )    )
+                      const struct udp_get_port_ops *ops)
 {
        struct hlist_node *node;
        struct hlist_head *head;
@@ -176,8 +178,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
                for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
                        int size;
 
-                       hash = hash_port_and_addr(result,
-                                       inet_sk(sk)->rcv_saddr);
+                       hash = ops->hash_port_and_rcv_saddr(result, sk);
                        head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
                        if (hlist_empty(head)) {
                                if (result > sysctl_local_port_range[1])
@@ -203,17 +204,16 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
                                result = sysctl_local_port_range[0]
                                        + ((result - sysctl_local_port_range[0]) &
                                           (UDP_HTABLE_SIZE - 1));
-                       hash = hash_port_and_addr(result, 0);
+                       hash = udp_hash_port(result);
                        if (__udp_lib_port_inuse(hash, result,
-                                                0, udptable))
+                                                NULL, udptable, ops))
                                continue;
-                       if (!inet_sk(sk)->rcv_saddr)
+                       if (ops->saddr_any(sk))
                                break;
 
-                       hash = hash_port_and_addr(result,
-                                       inet_sk(sk)->rcv_saddr);
+                       hash = ops->hash_port_and_rcv_saddr(result, sk);
                        if (! __udp_lib_port_inuse(hash, result,
-                               inet_sk(sk)->rcv_saddr, udptable))
+                                                  sk, udptable, ops))
                                break;
                }
                if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -221,7 +221,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
 gotit:
                *port_rover = snum = result;
        } else {
-               hash = hash_port_and_addr(snum, 0);
+               hash = udp_hash_port(snum);
                head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 
                sk_for_each(sk2, node, head)
@@ -231,12 +231,11 @@ gotit:
                            (!sk2->sk_reuse || !sk->sk_reuse) &&
                            (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
                             sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
-                           (*saddr_comp)(sk, sk2))
+                           ops->saddr_cmp(sk, sk2))
                                goto fail;
 
-               if (inet_sk(sk)->rcv_saddr) {
-                       hash = hash_port_and_addr(snum,
-                                                 inet_sk(sk)->rcv_saddr);
+               if (!ops->saddr_any(sk)) {
+                       hash = ops->hash_port_and_rcv_saddr(snum, sk);
                        head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
 
                        sk_for_each(sk2, node, head)
@@ -248,7 +247,7 @@ gotit:
                                     !sk->sk_bound_dev_if ||
                                     sk2->sk_bound_dev_if ==
                                     sk->sk_bound_dev_if) &&
-                                   (*saddr_comp)(sk, sk2))
+                                   ops->saddr_cmp(sk, sk2))
                                        goto fail;
                }
        }
@@ -266,12 +265,12 @@ fail:
 }
 
 int udp_get_port(struct sock *sk, unsigned short snum,
-                       int (*scmp)(const struct sock *, const struct sock *))
+                const struct udp_get_port_ops *ops)
 {
-       return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
+       return  __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops);
 }
 
-int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 {
        struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
@@ -280,9 +279,33 @@ int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
                   inet1->rcv_saddr == inet2->rcv_saddr      ));
 }
 
+static int ipv4_rcv_saddr_any(const struct sock *sk)
+{
+       return !inet_sk(sk)->rcv_saddr;
+}
+
+static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr)
+{
+       addr ^= addr >> 16;
+       addr ^= addr >> 8;
+       return port ^ addr;
+}
+
+static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port,
+                                                const struct sock *sk)
+{
+       return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr);
+}
+
+const struct udp_get_port_ops udp_ipv4_ops = {
+       .saddr_cmp = ipv4_rcv_saddr_equal,
+       .saddr_any = ipv4_rcv_saddr_any,
+       .hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr,
+};
+
 static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
-       return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+       return udp_get_port(sk, snum, &udp_ipv4_ops);
 }
 
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@@ -297,8 +320,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
        unsigned int hash, hashwild;
        int score, best = -1, hport = ntohs(dport);
 
-       hash = hash_port_and_addr(hport, daddr);
-       hashwild = hash_port_and_addr(hport, 0);
+       hash = ipv4_hash_port_and_addr(hport, daddr);
+       hashwild = udp_hash_port(hport);
 
        read_lock(&udp_hash_lock);
 
@@ -983,7 +1006,7 @@ int udp_disconnect(struct sock *sk, int flags)
 }
 
 /* return:
- *     1  if the the UDP system should process it
+ *     1  if the UDP system should process it
  *     0  if we should drop this packet
  *     -1 if it should get processed by xfrm4_rcv_encap
  */
@@ -1198,8 +1221,8 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
        struct sock *sk, *skw, *sknext;
        int dif;
        int hport = ntohs(uh->dest);
-       unsigned int hash = hash_port_and_addr(hport, daddr);
-       unsigned int hashwild = hash_port_and_addr(hport, 0);
+       unsigned int hash = ipv4_hash_port_and_addr(hport, daddr);
+       unsigned int hashwild = udp_hash_port(hport);
 
        dif = skb->dev->ifindex;
 
index 820a477cfaa6e9899234b03ee8120c9ca158babd..06d94195e644848fa464f54456c4abb450496a25 100644 (file)
@@ -5,14 +5,14 @@
 #include <net/protocol.h>
 #include <net/inet_common.h>
 
+extern const struct udp_get_port_ops udp_ipv4_ops;
+
 extern int     __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
 extern void    __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
 
 extern int     __udp_lib_get_port(struct sock *sk, unsigned short snum,
                                   struct hlist_head udptable[], int *port_rover,
-                                  int (*)(const struct sock*,const struct sock*));
-extern int     ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
-
+                                  const struct udp_get_port_ops *ops);
 
 extern int     udp_setsockopt(struct sock *sk, int level, int optname,
                               char __user *optval, int optlen);
index f34fd686a8f15ac6e49b687742701c1037ab1417..3653b32dce2d79f6ec18eb2a484aaf325448578a 100644 (file)
@@ -19,14 +19,15 @@ struct hlist_head   udplite_hash[UDP_HTABLE_SIZE];
 static int             udplite_port_rover;
 
 int udplite_get_port(struct sock *sk, unsigned short p,
-                    int (*c)(const struct sock *, const struct sock *))
+                    const struct udp_get_port_ops *ops)
 {
-       return  __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c);
+       return  __udp_lib_get_port(sk, p, udplite_hash,
+                                  &udplite_port_rover, ops);
 }
 
 static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
 {
-       return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal);
+       return udplite_get_port(sk, snum, &udp_ipv4_ops);
 }
 
 static int udplite_rcv(struct sk_buff *skb)
index d02685c6bc69867f8f30682777fce1c0ce30e701..c7ea248fae2e28e7519052400f7256b491c016e9 100644 (file)
@@ -4204,6 +4204,10 @@ int __init addrconf_init(void)
                return err;
 
        ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+       ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+       ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#endif
 
        register_netdevice_notifier(&ipv6_dev_notf);
 
index 6d8e4ac7bdad84a7631bb9c3eabca4bb66c5b7c2..14be0b9b77a5f998614351e1c5dbc92a31f94df0 100644 (file)
@@ -660,6 +660,14 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
   Hop-by-hop options.
  **********************************/
 
+/*
+ * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
+ */
+static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
+{
+       return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
+}
+
 /* Router Alert as of RFC 2711 */
 
 static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
@@ -688,25 +696,25 @@ static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
        if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
                LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
                               nh[optoff+1]);
-               IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(ipv6_skb_idev(skb),
                                 IPSTATS_MIB_INHDRERRORS);
                goto drop;
        }
 
        pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
        if (pkt_len <= IPV6_MAXPLEN) {
-               IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+               IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
                return 0;
        }
        if (ipv6_hdr(skb)->payload_len) {
-               IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+               IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
                return 0;
        }
 
        if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
-               IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
+               IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
                goto drop;
        }
 
index f508171bab735b5e1901caa51bfff0248129e2c7..4704b5fc3085b9f8dab20bd5d1d36ea0b2d062a3 100644 (file)
@@ -463,10 +463,17 @@ int ip6_forward(struct sk_buff *skb)
                 */
                if (xrlim_allow(dst, 1*HZ))
                        ndisc_send_redirect(skb, n, target);
-       } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
-                                               |IPV6_ADDR_LINKLOCAL)) {
+       } else {
+               int addrtype = ipv6_addr_type(&hdr->saddr);
+
                /* This check is security critical. */
-               goto error;
+               if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
+                       goto error;
+               if (addrtype & IPV6_ADDR_LINKLOCAL) {
+                       icmpv6_send(skb, ICMPV6_DEST_UNREACH,
+                               ICMPV6_NOT_NEIGHBOUR, 0, skb->dev);
+                       goto error;
+               }
        }
 
        if (skb->len > dst_mtu(dst)) {
index bbe99f842f9f67e79e5e405abf60ed09a5c50c3f..838b8ddee8c03d6e40becb72ff15795cd2ab06ca 100644 (file)
@@ -28,7 +28,7 @@ config IP6_NF_QUEUE
          packets which enables users to receive the filtered packets
          with QUEUE target using libipq.
 
-         THis option enables the old IPv6-only "ip6_queue" implementation
+         This option enables the old IPv6-only "ip6_queue" implementation
          which has been obsoleted by the new "nfnetlink_queue" code (see
          CONFIG_NETFILTER_NETLINK_QUEUE).
 
index 76f0cf66f95c53cfb4e575b45dc93f36372572e1..7e32e2aaf7f7d62378fdcb11226a548435cfdaf0 100644 (file)
@@ -24,53 +24,29 @@ static struct
        struct ip6t_replace repl;
        struct ip6t_standard entries[3];
        struct ip6t_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
-      sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
-      { [NF_IP6_LOCAL_IN] = 0,
-       [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
-       [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
-      { [NF_IP6_LOCAL_IN] = 0,
-       [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
-       [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
-      0, NULL, { } },
-    {
-           /* LOCAL_IN */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* FORWARD */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_OUT */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-       0,
-       sizeof(struct ip6t_entry),
-       sizeof(struct ip6t_error),
-       0, { 0, 0 }, { } },
-      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
-         { } },
-       "ERROR"
-      }
-    }
+} initial_table __initdata = {
+       .repl = {
+               .name = "filter",
+               .valid_hooks = FILTER_VALID_HOOKS,
+               .num_entries = 4,
+               .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+               .hook_entry = {
+                       [NF_IP6_LOCAL_IN] = 0,
+                       [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+                       [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+               },
+               .underflow = {
+                       [NF_IP6_LOCAL_IN] = 0,
+                       [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+                       [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+               },
+       },
+       .entries = {
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_IN */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* FORWARD */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_OUT */
+       },
+       .term = IP6T_ERROR_INIT,                /* ERROR */
 };
 
 static struct xt_table packet_filter = {
index a9f10e32c163ef6e186bd3d36cbf777625a83603..f2d26495f41350edbf981e12dbdc4c8f4b4087c8 100644 (file)
@@ -32,73 +32,35 @@ static struct
        struct ip6t_replace repl;
        struct ip6t_standard entries[5];
        struct ip6t_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
-      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING]   = 0,
-       [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
-       [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
-       [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
-       [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4},
-      { [NF_IP6_PRE_ROUTING]   = 0,
-       [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
-       [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
-       [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
-       [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4},
-      0, NULL, { } },
-    {
-           /* PRE_ROUTING */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_IN */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* FORWARD */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* LOCAL_OUT */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } },
-           /* POST_ROUTING */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-               0,
-               sizeof(struct ip6t_entry),
-               sizeof(struct ip6t_standard),
-               0, { 0, 0 }, { } },
-             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } }
-    },
-    /* ERROR */
-    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
-       0,
-       sizeof(struct ip6t_entry),
-       sizeof(struct ip6t_error),
-       0, { 0, 0 }, { } },
-      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
-         { } },
-       "ERROR"
-      }
-    }
+} initial_table __initdata = {
+       .repl = {
+               .name = "mangle",
+               .valid_hooks = MANGLE_VALID_HOOKS,
+               .num_entries = 6,
+               .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+               .hook_entry = {
+                       [NF_IP6_PRE_ROUTING]    = 0,
+                       [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
+                       [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
+                       [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
+                       [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4,
+               },
+               .underflow = {
+                       [NF_IP6_PRE_ROUTING]    = 0,
+                       [NF_IP6_LOCAL_IN]       = sizeof(struct ip6t_standard),
+                       [NF_IP6_FORWARD]        = sizeof(struct ip6t_standard) * 2,
+                       [NF_IP6_LOCAL_OUT]      = sizeof(struct ip6t_standard) * 3,
+                       [NF_IP6_POST_ROUTING]   = sizeof(struct ip6t_standard) * 4,
+               },
+       },
+       .entries = {
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* PRE_ROUTING */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_IN */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* FORWARD */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_OUT */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* POST_ROUTING */
+       },
+       .term = IP6T_ERROR_INIT,                /* ERROR */
 };
 
 static struct xt_table packet_mangler = {
index a3eb5b8ce18d0abe8a7062b0cc340e1b6bb5b160..0acda45d455d7251df207fe799464cd342aeb15d 100644 (file)
@@ -35,56 +35,10 @@ static struct
                },
        },
        .entries = {
-               /* PRE_ROUTING */
-               {
-                       .entry = {
-                               .target_offset = sizeof(struct ip6t_entry),
-                               .next_offset = sizeof(struct ip6t_standard),
-                       },
-                       .target = {
-                               .target = {
-                                       .u = {
-                                               .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
-                                       },
-                               },
-                               .verdict = -NF_ACCEPT - 1,
-                       },
-               },
-
-               /* LOCAL_OUT */
-               {
-                       .entry = {
-                               .target_offset = sizeof(struct ip6t_entry),
-                               .next_offset = sizeof(struct ip6t_standard),
-                       },
-                       .target = {
-                               .target = {
-                                       .u = {
-                                               .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
-                                       },
-                               },
-                               .verdict = -NF_ACCEPT - 1,
-                       },
-               },
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* PRE_ROUTING */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_OUT */
        },
-       /* ERROR */
-       .term = {
-               .entry = {
-                       .target_offset = sizeof(struct ip6t_entry),
-                       .next_offset = sizeof(struct ip6t_error),
-               },
-               .target = {
-                       .target = {
-                               .u = {
-                                       .user = {
-                                               .target_size = IP6T_ALIGN(sizeof(struct ip6t_error_target)),
-                                               .name = IP6T_ERROR_TARGET,
-                                       },
-                               },
-                       },
-                       .errorname = "ERROR",
-               },
-       }
+       .term = IP6T_ERROR_INIT,                /* ERROR */
 };
 
 static struct xt_table packet_raw = {
index b083c09e3d2d1b4757042e08684a10d7dc48d649..a7ae59c954d5a2d68f7d18c6bdb3addf1abcbdaf 100644 (file)
 
 DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
 
+static int ipv6_rcv_saddr_any(const struct sock *sk)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+
+       return ipv6_addr_any(&np->rcv_saddr);
+}
+
+static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port,
+                                                const struct sock *sk)
+{
+       return port;
+}
+
+const struct udp_get_port_ops udp_ipv6_ops = {
+       .saddr_cmp = ipv6_rcv_saddr_equal,
+       .saddr_any = ipv6_rcv_saddr_any,
+       .hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr,
+};
+
 static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-       return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
+       return udp_get_port(sk, snum, &udp_ipv6_ops);
 }
 
 static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
index 6e252f318f7c91c81f5cdf04d2822b476f26a8ae..36b0c11a28a312dcad2bfa6f82d4bbd057dd307e 100644 (file)
@@ -6,6 +6,8 @@
 #include <net/addrconf.h>
 #include <net/inet_common.h>
 
+extern const struct udp_get_port_ops udp_ipv6_ops;
+
 extern int     __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
 extern void    __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
                               int , int , int , __be32 , struct hlist_head []);
index f54016a55004d2d931471c06f14db922efa5f84d..c40a51362f89ed6861d64acccdf371712ca7c61b 100644 (file)
@@ -37,7 +37,7 @@ static struct inet6_protocol udplitev6_protocol = {
 
 static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
 {
-       return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal);
+       return udplite_get_port(sk, snum, &udp_ipv6_ops);
 }
 
 struct proto udplitev6_prot = {
index 9efb17ba48acc9c6995cb72af28af9678dd84210..c8671a7ffb3cd11153fad20d0f6cfc16479b6e1e 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig IRDA
-       depends on NET
+       depends on NET && !S390
        tristate "IrDA (infrared) subsystem support"
        select CRC_CCITT
        ---help---
index fb3faf72e8508f73cea2e435182ea534f84a0ecc..b7333061016dfffbf8122460f63dda56e724a3c8 100644 (file)
@@ -556,6 +556,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
 
        switch (action) {
        case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
                if (!percpu_populate(iucv_irq_data,
                                     sizeof(struct iucv_irq_data),
                                     GFP_KERNEL|GFP_DMA, cpu))
@@ -567,15 +568,20 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                }
                break;
        case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                percpu_depopulate(iucv_param, cpu);
                percpu_depopulate(iucv_irq_data, cpu);
                break;
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
        case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
                smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
                break;
        case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
                cpumask = iucv_buffer_cpumask;
                cpu_clear(cpu, cpumask);
                if (cpus_empty(cpumask))
index 7d9fa38b6a7d14ca5a35d8c782d5b7e0f383a34a..6b8a103cf9e66f198984fed8656ddacf9781718a 100644 (file)
@@ -324,7 +324,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                memset(&laddr, 0, sizeof(laddr));
                memset(&daddr, 0, sizeof(daddr));
                /*
-                * FIXME: check if the the address is multicast,
+                * FIXME: check if the address is multicast,
                 *        only SOCK_DGRAM can do this.
                 */
                memcpy(laddr.mac, addr->sllc_mac, IFHWADDRLEN);
index 822917debeff897760fc3222d17312f9b364511b..3e07e9d6fa426f8dd7184c9ee4244b312ff52f7b 100644 (file)
@@ -17,6 +17,7 @@
  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
  *    SSID)
  */
+#include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -27,7 +28,6 @@
 #include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
-#include <asm/delay.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
index ea6211cade0acd2b464822eedec0ed819fc50583..a567dae8e5fdff5a3b0a80080f71d23fa0196236 100644 (file)
@@ -197,7 +197,7 @@ config NF_CONNTRACK_PPTP
 
          Please note that not all PPTP modes of operation are supported yet.
          Specifically these limitations exist:
-           - Blindy assumes that control connections are always established
+           - Blindly assumes that control connections are always established
              in PNS->PAC direction. This is a violation of RFC2637.
            - Only supports a single call within each session
 
index e132c8ae87840306f41f9a56043fd543ffeaa7f4..e8b5c2d7db62355981a82475b5226ab672ae4d8f 100644 (file)
@@ -299,7 +299,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
 {
        struct nf_conn *ct = (struct nf_conn *)nfct;
        struct nf_conn_help *help = nfct_help(ct);
-       struct nf_conntrack_l3proto *l3proto;
        struct nf_conntrack_l4proto *l4proto;
        typeof(nf_conntrack_destroyed) destroyed;
 
@@ -317,10 +316,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
         * destroy_conntrack() MUST NOT be called with a write lock
         * to nf_conntrack_lock!!! -HW */
        rcu_read_lock();
-       l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
-       if (l3proto && l3proto->destroy)
-               l3proto->destroy(ct);
-
        l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
                                       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
        if (l4proto && l4proto->destroy)
@@ -893,8 +888,13 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
        NF_CT_DUMP_TUPLE(newreply);
 
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-       if (!ct->master && help && help->expecting == 0)
-               help->helper = __nf_ct_helper_find(newreply);
+       if (!ct->master && help && help->expecting == 0) {
+               struct nf_conntrack_helper *helper;
+               helper = __nf_ct_helper_find(newreply);
+               if (helper)
+                       memset(&help->help, 0, sizeof(help->help));
+               help->helper = helper;
+       }
        write_unlock_bh(&nf_conntrack_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
index c31af29a4439f9266592abe0c162cf97fef291b7..117cbfdb910c57bf08b4f62e1a254cccb32df7c1 100644 (file)
@@ -177,7 +177,7 @@ void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
        struct nf_conntrack_expect *i;
 
        write_lock_bh(&nf_conntrack_lock);
-       /* choose the the oldest expectation to evict */
+       /* choose the oldest expectation to evict */
        list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
                if (expect_matches(i, exp) && del_timer(&i->timeout)) {
                        nf_ct_unlink_expect(i);
index aa1a97ee514ba5efc513ea71c1059f19385305ba..d6d39e2413278b5b8fa9a60523be7a74ded14979 100644 (file)
@@ -830,11 +830,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
        char *helpname;
        int err;
 
-       if (!help) {
-               /* FIXME: we need to reallocate and rehash */
-               return -EBUSY;
-       }
-
        /* don't change helper of sibling connections */
        if (ct->master)
                return -EINVAL;
@@ -843,25 +838,34 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
        if (err < 0)
                return err;
 
-       helper = __nf_conntrack_helper_find_byname(helpname);
-       if (!helper) {
-               if (!strcmp(helpname, ""))
-                       helper = NULL;
-               else
-                       return -EINVAL;
-       }
-
-       if (help->helper) {
-               if (!helper) {
+       if (!strcmp(helpname, "")) {
+               if (help && help->helper) {
                        /* we had a helper before ... */
                        nf_ct_remove_expectations(ct);
                        help->helper = NULL;
-               } else {
-                       /* need to zero data of old helper */
-                       memset(&help->help, 0, sizeof(help->help));
                }
+
+               return 0;
        }
 
+       if (!help) {
+               /* FIXME: we need to reallocate and rehash */
+               return -EBUSY;
+       }
+
+       helper = __nf_conntrack_helper_find_byname(helpname);
+       if (helper == NULL)
+               return -EINVAL;
+
+       if (help->helper == helper)
+               return 0;
+
+       if (help->helper)
+               /* we had a helper before ... */
+               nf_ct_remove_expectations(ct);
+
+       /* need to zero data of old helper */
+       memset(&help->help, 0, sizeof(help->help));
        help->helper = helper;
 
        return 0;
index f4ea8fe07a5369ef46bdb95512def06540a80e27..189ded5f378bb100035e6d5b69770f9d8577b52e 100644 (file)
@@ -134,12 +134,66 @@ static void destroy(const struct xt_match *match, void *matchinfo)
        nf_ct_l3proto_module_put(match->family);
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_xt_conntrack_info
+{
+       compat_uint_t                   statemask;
+       compat_uint_t                   statusmask;
+       struct ip_conntrack_old_tuple   tuple[IP_CT_DIR_MAX];
+       struct in_addr                  sipmsk[IP_CT_DIR_MAX];
+       struct in_addr                  dipmsk[IP_CT_DIR_MAX];
+       compat_ulong_t                  expires_min;
+       compat_ulong_t                  expires_max;
+       u_int8_t                        flags;
+       u_int8_t                        invflags;
+};
+
+static void compat_from_user(void *dst, void *src)
+{
+       struct compat_xt_conntrack_info *cm = src;
+       struct xt_conntrack_info m = {
+               .statemask      = cm->statemask,
+               .statusmask     = cm->statusmask,
+               .expires_min    = cm->expires_min,
+               .expires_max    = cm->expires_max,
+               .flags          = cm->flags,
+               .invflags       = cm->invflags,
+       };
+       memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
+       memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
+       memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
+       memcpy(dst, &m, sizeof(m));
+}
+
+static int compat_to_user(void __user *dst, void *src)
+{
+       struct xt_conntrack_info *m = src;
+       struct compat_xt_conntrack_info cm = {
+               .statemask      = m->statemask,
+               .statusmask     = m->statusmask,
+               .expires_min    = m->expires_min,
+               .expires_max    = m->expires_max,
+               .flags          = m->flags,
+               .invflags       = m->invflags,
+       };
+       memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
+       memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
+       memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
+       return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
+}
+#endif
+
 static struct xt_match conntrack_match = {
        .name           = "conntrack",
        .match          = match,
        .checkentry     = checkentry,
        .destroy        = destroy,
        .matchsize      = sizeof(struct xt_conntrack_info),
+#ifdef CONFIG_COMPAT
+       .compatsize     = sizeof(struct compat_xt_conntrack_info),
+       .compat_from_user = compat_from_user,
+       .compat_to_user = compat_to_user,
+#endif
        .family         = AF_INET,
        .me             = THIS_MODULE,
 };
index ce08b78647ce85a168ccce87ade906b9b13c3e0c..90fa107a8af99bc82fa7a6fd5a28d13885c121a0 100644 (file)
@@ -59,14 +59,14 @@ static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
 
        ret = ip_route_output_key(&rt, &fl);
        if (ret < 0) {
-               kleave(" [route err %d]", ret);
+               _leave(" [route err %d]", ret);
                return;
        }
 
        peer->if_mtu = dst_mtu(&rt->u.dst);
        dst_release(&rt->u.dst);
 
-       kleave(" [if_mtu %u]", peer->if_mtu);
+       _leave(" [if_mtu %u]", peer->if_mtu);
 }
 
 /*
index 3385ee5925418d73da404e429c33b20f6db9f4a1..f28bb2dc58d0af3f17c7430eafe9d110ec6cba31 100644 (file)
@@ -71,12 +71,9 @@ void qdisc_unlock_tree(struct net_device *dev)
 
 
 /* Kick device.
-   Note, that this procedure can be called by a watchdog timer, so that
-   we do not check dev->tbusy flag here.
 
-   Returns:  0  - queue is empty.
-           >0  - queue is not empty, but throttled.
-           <0  - queue is not empty. Device is throttled, if dev->tbusy != 0.
+   Returns:  0  - queue is empty or throttled.
+           >0  - queue is not empty.
 
    NOTE: Called under dev->queue_lock with locally disabled BH.
 */
@@ -115,7 +112,7 @@ static inline int qdisc_restart(struct net_device *dev)
                                        kfree_skb(skb);
                                        if (net_ratelimit())
                                                printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
-                                       return -1;
+                                       goto out;
                                }
                                __get_cpu_var(netdev_rx_stat).cpu_collision++;
                                goto requeue;
@@ -135,10 +132,12 @@ static inline int qdisc_restart(struct net_device *dev)
                                                netif_tx_unlock(dev);
                                        }
                                        spin_lock(&dev->queue_lock);
-                                       return -1;
+                                       q = dev->qdisc;
+                                       goto out;
                                }
                                if (ret == NETDEV_TX_LOCKED && nolock) {
                                        spin_lock(&dev->queue_lock);
+                                       q = dev->qdisc;
                                        goto collision;
                                }
                        }
@@ -163,26 +162,28 @@ static inline int qdisc_restart(struct net_device *dev)
                 */
 
 requeue:
-               if (skb->next)
+               if (unlikely(q == &noop_qdisc))
+                       kfree_skb(skb);
+               else if (skb->next)
                        dev->gso_skb = skb;
                else
                        q->ops->requeue(skb, q);
                netif_schedule(dev);
-               return 1;
+               return 0;
        }
+
+out:
        BUG_ON((int) q->q.qlen < 0);
        return q->q.qlen;
 }
 
 void __qdisc_run(struct net_device *dev)
 {
-       if (unlikely(dev->qdisc == &noop_qdisc))
-               goto out;
-
-       while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
-               /* NOTHING */;
+       do {
+               if (!qdisc_restart(dev))
+                       break;
+       } while (!netif_queue_stopped(dev));
 
-out:
        clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
 }
 
@@ -544,6 +545,7 @@ void dev_activate(struct net_device *dev)
 void dev_deactivate(struct net_device *dev)
 {
        struct Qdisc *qdisc;
+       struct sk_buff *skb;
 
        spin_lock_bh(&dev->queue_lock);
        qdisc = dev->qdisc;
@@ -551,8 +553,12 @@ void dev_deactivate(struct net_device *dev)
 
        qdisc_reset(qdisc);
 
+       skb = dev->gso_skb;
+       dev->gso_skb = NULL;
        spin_unlock_bh(&dev->queue_lock);
 
+       kfree_skb(skb);
+
        dev_watchdog_down(dev);
 
        /* Wait for outstanding dev_queue_xmit calls. */
@@ -561,11 +567,6 @@ void dev_deactivate(struct net_device *dev)
        /* Wait for outstanding qdisc_run calls. */
        while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
                yield();
-
-       if (dev->gso_skb) {
-               kfree_skb(dev->gso_skb);
-               dev->gso_skb = NULL;
-       }
 }
 
 void dev_init_scheduler(struct net_device *dev)
index d24914db786124d187fc53a546d2ab9c5ebac958..f05ad9a30b4cd67bfef9d956023367303ddb5343 100644 (file)
@@ -94,14 +94,13 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
        struct net_device *dev = sch->dev;
        struct teql_sched_data *q = qdisc_priv(sch);
 
-       __skb_queue_tail(&q->q, skb);
-       if (q->q.qlen <= dev->tx_queue_len) {
+       if (q->q.qlen < dev->tx_queue_len) {
+               __skb_queue_tail(&q->q, skb);
                sch->bstats.bytes += skb->len;
                sch->bstats.packets++;
                return 0;
        }
 
-       __skb_unlink(skb, &q->q);
        kfree_skb(skb);
        sch->qstats.drops++;
        return NET_XMIT_DROP;
index 83ef411772f46f1494175d0320a0f4d43d134b46..77fb7b06a9c4eb62d2836b8b93fd779f6be4dfc0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file is part of the SCTP kernel reference Implementation
  *
- * This file contains the code relating the the chunk abstraction.
+ * This file contains the code relating the chunk abstraction.
  *
  * The SCTP reference implementation is free software;
  * you can redistribute it and/or modify it under the terms of
index 9f1a908776deac0a53be04e1b46aa1b87d59a98a..4dcdabf56473cb9e07cd33c8e29f71677d73f923 100644 (file)
@@ -2586,7 +2586,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
@@ -4164,6 +4164,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        rwlock_t *addr_lock;
        int err = 0;
        void *addrs;
+       void *buf;
        int bytes_copied = 0;
 
        if (len != sizeof(struct sctp_getaddrs_old))
@@ -4217,13 +4218,14 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
                }
        }
 
+       buf = addrs;
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                memcpy(&temp, &addr->a, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               memcpy(addrs, &temp, addrlen);
-               to += addrlen;
+               memcpy(buf, &temp, addrlen);
+               buf += addrlen;
                bytes_copied += addrlen;
                cnt ++;
                if (cnt >= getaddrs.addr_num) break;
@@ -4266,6 +4268,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        size_t space_left;
        int bytes_copied = 0;
        void *addrs;
+       void *buf;
 
        if (len <= sizeof(struct sctp_getaddrs))
                return -EINVAL;
@@ -4316,6 +4319,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
                }
        }
 
+       buf = addrs;
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                memcpy(&temp, &addr->a, sizeof(temp));
@@ -4325,8 +4329,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
                        err =  -ENOMEM; /*fixme: right error?*/
                        goto error;
                }
-               memcpy(addrs, &temp, addrlen);
-               to += addrlen;
+               memcpy(buf, &temp, addrlen);
+               buf += addrlen;
                bytes_copied += addrlen;
                cnt ++;
                space_left -= addrlen;
@@ -4547,7 +4551,7 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
@@ -5227,7 +5231,12 @@ int sctp_inet_listen(struct socket *sock, int backlog)
        /* Allocate HMAC for generating cookie. */
        if (sctp_hmac_alg) {
                tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
-               if (!tfm) {
+               if (IS_ERR(tfm)) {
+                       if (net_ratelimit()) {
+                               printk(KERN_INFO
+                                      "SCTP: failed to load transform for %s: %ld\n",
+                                       sctp_hmac_alg, PTR_ERR(tfm));
+                       }
                        err = -ENOSYS;
                        goto out;
                }
index 661ea2dd78baa3f0cd282cc2bf3551a8390480d8..bfecb353ab3da070f0b4784c6861eaef7de04d1c 100644 (file)
@@ -141,11 +141,6 @@ struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
         * an ABORT, so we need to include it in the sac_info.
         */
        if (chunk) {
-               /* sctp_inqu_pop() has allready pulled off the chunk
-                * header.  We need to put it back temporarily
-                */
-               skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));
-
                /* Copy the chunk data to a new skb and reserve enough
                 * head room to use as notification.
                 */
@@ -155,9 +150,6 @@ struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
                if (!skb)
                        goto fail;
 
-               /* put back the chunk header now that we have a copy */
-               skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
-
                /* Embed the event fields inside the cloned skb.  */
                event = sctp_skb2event(skb);
                sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
@@ -168,7 +160,8 @@ struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
 
                /* Trim the buffer to the right length.  */
                skb_trim(skb, sizeof(struct sctp_assoc_change) +
-                        ntohs(chunk->chunk_hdr->length));
+                        ntohs(chunk->chunk_hdr->length) -
+                        sizeof(sctp_chunkhdr_t));
        } else {
                event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
                                  MSG_NOTIFICATION, gfp);
index db298b501c817d1c0a90825aa526068293c59565..099a983797da329249942ccbbf279c92e8ac853b 100644 (file)
@@ -924,6 +924,7 @@ static inline int
 gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
 {
        struct rsc *rsci;
+       int        rc;
 
        if (rsip->major_status != GSS_S_COMPLETE)
                return gss_write_null_verf(rqstp);
@@ -932,7 +933,9 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
                rsip->major_status = GSS_S_NO_CONTEXT;
                return gss_write_null_verf(rqstp);
        }
-       return gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+       rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+       cache_put(&rsci->h, &rsc_cache);
+       return rc;
 }
 
 /*
@@ -1089,6 +1092,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
                }
                goto complete;
        case RPC_GSS_PROC_DESTROY:
+               if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+                       goto auth_err;
                set_bit(CACHE_NEGATIVE, &rsci->h.flags);
                if (resv->iov_len + 4 > PAGE_SIZE)
                        goto drop;
@@ -1196,13 +1201,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
        if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
                                integ_len))
                BUG();
-       if (resbuf->page_len == 0
-                       && resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
-                       < PAGE_SIZE) {
-               BUG_ON(resbuf->tail[0].iov_len);
-               /* Use head for everything */
-               resv = &resbuf->head[0];
-       } else if (resbuf->tail[0].iov_base == NULL) {
+       if (resbuf->tail[0].iov_base == NULL) {
                if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
                        goto out_err;
                resbuf->tail[0].iov_base = resbuf->head[0].iov_base
index ad39b47e05bcc6f2bfe027f5b6dc3164361a62f6..a2f1893bde53e41137a96b3cee5de618a629c2b9 100644 (file)
@@ -845,6 +845,8 @@ init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
 
 int register_rpc_pipefs(void)
 {
+       int err;
+
        rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
                                sizeof(struct rpc_inode),
                                0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -852,7 +854,12 @@ int register_rpc_pipefs(void)
                                init_once, NULL);
        if (!rpc_inode_cachep)
                return -ENOMEM;
-       register_filesystem(&rpc_pipe_fs_type);
+       err = register_filesystem(&rpc_pipe_fs_type);
+       if (err) {
+               kmem_cache_destroy(rpc_inode_cachep);
+               return err;
+       }
+
        return 0;
 }
 
index 99014516b73c7855294df0788c88f3d954a7214f..b011eb625e49ca1ce89a1970148170772d257a4c 100644 (file)
@@ -736,6 +736,11 @@ static void rpc_async_schedule(struct work_struct *work)
        __rpc_execute(container_of(work, struct rpc_task, u.tk_work));
 }
 
+struct rpc_buffer {
+       size_t  len;
+       char    data[];
+};
+
 /**
  * rpc_malloc - allocate an RPC buffer
  * @task: RPC task that will use this buffer
@@ -754,18 +759,22 @@ static void rpc_async_schedule(struct work_struct *work)
  */
 void *rpc_malloc(struct rpc_task *task, size_t size)
 {
-       size_t *buf;
+       struct rpc_buffer *buf;
        gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
 
-       size += sizeof(size_t);
+       size += sizeof(struct rpc_buffer);
        if (size <= RPC_BUFFER_MAXSIZE)
                buf = mempool_alloc(rpc_buffer_mempool, gfp);
        else
                buf = kmalloc(size, gfp);
-       *buf = size;
+
+       if (!buf)
+               return NULL;
+
+       buf->len = size;
        dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
                        task->tk_pid, size, buf);
-       return ++buf;
+       return &buf->data;
 }
 
 /**
@@ -775,15 +784,18 @@ void *rpc_malloc(struct rpc_task *task, size_t size)
  */
 void rpc_free(void *buffer)
 {
-       size_t size, *buf = buffer;
+       size_t size;
+       struct rpc_buffer *buf;
 
        if (!buffer)
                return;
-       size = *buf;
-       buf--;
+
+       buf = container_of(buffer, struct rpc_buffer, data);
+       size = buf->len;
 
        dprintk("RPC:       freeing buffer of size %zu at %p\n",
                        size, buf);
+
        if (size <= RPC_BUFFER_MAXSIZE)
                mempool_free(buf, rpc_buffer_mempool);
        else
index 43ecf62f12ef2b6797631b420009198d1ce9d883..0d35bc796d0034bba98284c4d7fd75bf93e7153f 100644 (file)
@@ -146,9 +146,11 @@ init_sunrpc(void)
        int err = register_rpc_pipefs();
        if (err)
                goto out;
-       err = rpc_init_mempool() != 0;
-       if (err)
+       err = rpc_init_mempool();
+       if (err) {
+               unregister_rpc_pipefs();
                goto out;
+       }
 #ifdef RPC_DEBUG
        rpc_register_sysctl();
 #endif
index b7503c103ae814f012041a6f8f02e073c1d1ab26..e673ef9939043edc4a2d7aac1bf0c745ebd22917 100644 (file)
@@ -907,7 +907,7 @@ svc_process(struct svc_rqst *rqstp)
         * better idea of reply size
         */
        if (procp->pc_xdrressize)
-               svc_reserve(rqstp, procp->pc_xdrressize<<2);
+               svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
 
        /* Call the function that processes the request. */
        if (!versp->vs_dispatch) {
index f5c3808bf85ab7cf1d03edaf8c43bbebc5faa3cf..af7c5f05c6e11b3d5d734d1ee2143e54c71517bb 100644 (file)
@@ -64,7 +64,7 @@ int svc_set_client(struct svc_rqst *rqstp)
 }
 
 /* A request, which was authenticated, has now executed.
- * Time to finalise the the credentials and verifier
+ * Time to finalise the credentials and verifier
  * and release and resources
  */
 int svc_authorise(struct svc_rqst *rqstp)
index 2bd23ea2aa8b9cfefc3c771e8444d4dd4d33b8c5..07dcd20cbee4c366ee7ba8a0d19d7729b0b0b050 100644 (file)
@@ -385,7 +385,7 @@ ip_map_cached_get(struct svc_rqst *rqstp)
 {
        struct ip_map *ipm;
        struct svc_sock *svsk = rqstp->rq_sock;
-       spin_lock_bh(&svsk->sk_defer_lock);
+       spin_lock(&svsk->sk_lock);
        ipm = svsk->sk_info_authunix;
        if (ipm != NULL) {
                if (!cache_valid(&ipm->h)) {
@@ -395,13 +395,13 @@ ip_map_cached_get(struct svc_rqst *rqstp)
                         * same IP address.
                         */
                        svsk->sk_info_authunix = NULL;
-                       spin_unlock_bh(&svsk->sk_defer_lock);
+                       spin_unlock(&svsk->sk_lock);
                        cache_put(&ipm->h, &ip_map_cache);
                        return NULL;
                }
                cache_get(&ipm->h);
        }
-       spin_unlock_bh(&svsk->sk_defer_lock);
+       spin_unlock(&svsk->sk_lock);
        return ipm;
 }
 
@@ -410,14 +410,14 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
 {
        struct svc_sock *svsk = rqstp->rq_sock;
 
-       spin_lock_bh(&svsk->sk_defer_lock);
+       spin_lock(&svsk->sk_lock);
        if (svsk->sk_sock->type == SOCK_STREAM &&
            svsk->sk_info_authunix == NULL) {
                /* newly cached, keep the reference */
                svsk->sk_info_authunix = ipm;
                ipm = NULL;
        }
-       spin_unlock_bh(&svsk->sk_defer_lock);
+       spin_unlock(&svsk->sk_lock);
        if (ipm)
                cache_put(&ipm->h, &ip_map_cache);
 }
index 22f61aee4824cea33b419529f62bb5eee599f5fd..5baf48de25588f9e6610e1e1fdadeac4400636bd 100644 (file)
@@ -53,7 +53,8 @@
  *     svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
  *     when both need to be taken (rare), svc_serv->sv_lock is first.
  *     BKL protects svc_serv->sv_nrthread.
- *     svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list
+ *     svc_sock->sk_lock protects the svc_sock->sk_deferred list
+ *             and the ->sk_info_authunix cache.
  *     svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
  *
  *     Some flags can be set to certain values at any time
@@ -787,15 +788,20 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
        }
 
        clear_bit(SK_DATA, &svsk->sk_flags);
-       while ((err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
-                                    0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 ||
-              (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
-               if (err == -EAGAIN) {
-                       svc_sock_received(svsk);
-                       return err;
+       skb = NULL;
+       err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
+                            0, 0, MSG_PEEK | MSG_DONTWAIT);
+       if (err >= 0)
+               skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
+
+       if (skb == NULL) {
+               if (err != -EAGAIN) {
+                       /* possibly an icmp error */
+                       dprintk("svc: recvfrom returned error %d\n", -err);
+                       set_bit(SK_DATA, &svsk->sk_flags);
                }
-               /* possibly an icmp error */
-               dprintk("svc: recvfrom returned error %d\n", -err);
+               svc_sock_received(svsk);
+               return -EAGAIN;
        }
        rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
        if (skb->tstamp.tv64 == 0) {
@@ -1633,7 +1639,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        svsk->sk_server = serv;
        atomic_set(&svsk->sk_inuse, 1);
        svsk->sk_lastrecv = get_seconds();
-       spin_lock_init(&svsk->sk_defer_lock);
+       spin_lock_init(&svsk->sk_lock);
        INIT_LIST_HEAD(&svsk->sk_deferred);
        INIT_LIST_HEAD(&svsk->sk_ready);
        mutex_init(&svsk->sk_mutex);
@@ -1857,9 +1863,9 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
        dprintk("revisit queued\n");
        svsk = dr->svsk;
        dr->svsk = NULL;
-       spin_lock_bh(&svsk->sk_defer_lock);
+       spin_lock(&svsk->sk_lock);
        list_add(&dr->handle.recent, &svsk->sk_deferred);
-       spin_unlock_bh(&svsk->sk_defer_lock);
+       spin_unlock(&svsk->sk_lock);
        set_bit(SK_DEFERRED, &svsk->sk_flags);
        svc_sock_enqueue(svsk);
        svc_sock_put(svsk);
@@ -1925,7 +1931,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
 
        if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
                return NULL;
-       spin_lock_bh(&svsk->sk_defer_lock);
+       spin_lock(&svsk->sk_lock);
        clear_bit(SK_DEFERRED, &svsk->sk_flags);
        if (!list_empty(&svsk->sk_deferred)) {
                dr = list_entry(svsk->sk_deferred.next,
@@ -1934,6 +1940,6 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
                list_del_init(&dr->handle.recent);
                set_bit(SK_DEFERRED, &svsk->sk_flags);
        }
-       spin_unlock_bh(&svsk->sk_defer_lock);
+       spin_unlock(&svsk->sk_lock);
        return dr;
 }
index d6071cbf13d7645ee53f96089bb8c12af04fcb8b..f4d2f68452baa8860769b7ac9cecac75747d6118 100644 (file)
@@ -211,7 +211,7 @@ void find_export_symbols(char * filename)
  * Document all external or internal functions in a file.
  * Call kernel-doc with following parameters:
  * kernel-doc -docbook -nofunction function_name1 filename
- * function names are obtained from all the the src files
+ * function names are obtained from all the src files
  * by find_export_symbols.
  * intfunc uses -nofunction
  * extfunc uses -function
index a325a0c890dc8e0a49ce4992ca4735ba5b5d1530..e5bf649e516a1d38bb9cc0ebf226b989246d09ac 100755 (executable)
@@ -337,6 +337,7 @@ sub get_kernel_version() {
     }
     return $version;
 }
+my $kernelversion = get_kernel_version();
 
 # generate a sequence of code that will splice in highlighting information
 # using the s// operator.
@@ -610,7 +611,7 @@ sub output_function_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'function'}."</refname>\n";
@@ -687,7 +688,7 @@ sub output_struct_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
@@ -772,7 +773,7 @@ sub output_enum_xml(%) {
     print "<refmeta>\n";
     print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
     print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . get_kernel_version() . "</refmiscinfo>\n";
+    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
     print "</refmeta>\n";
     print "<refnamediv>\n";
     print " <refname>enum ".$args{'enum'}."</refname>\n";
index 480e18b00aa6512857fb6b994829605b62854c53..113dc77b9f60f9e147239bc3daff8bc92164c80c 100644 (file)
@@ -1343,6 +1343,7 @@ static void add_header(struct buffer *b, struct module *mod)
                buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
                              " .exit = cleanup_module,\n"
                              "#endif\n");
+       buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
        buf_printf(b, "};\n");
 }
 
index 23b51047494ef0bd9673911979a049c7295d0b44..b32a459c0683c720271b6ab15d0829b11ef3e125 100644 (file)
@@ -137,7 +137,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
 
          Examples:
          For the Fedora Core 3 or 4 Linux distributions, enable this option
-         and set the value via the next option. For Fedore Core 5 and later,
+         and set the value via the next option. For Fedora Core 5 and later,
          do not enable this option.
 
          If you are unsure how to answer this question, answer N.
index 97532bbc2ccba8fb301a6dfdd9991a3694012381..9ea473823418858f5d4b9e90cf0c14726507d9c1 100644 (file)
@@ -2,6 +2,7 @@
 #
 
 menu "Sound"
+       depends on HAS_IOMEM
 
 config SOUND
        tristate "Sound card support"
index b2927523d79df9c7ad796049ebb8145fb537ac57..829ca38b595e82d63eabb932506fb126eff723bf 100644 (file)
@@ -146,7 +146,7 @@ config SND_VERBOSE_PROCFS
        default y
        help
          Say Y here to include code for verbose procfs contents (provides
-          usefull information to developers when a problem occurs). On the
+          useful information to developers when a problem occurs).  On the
           other side, it makes the ALSA subsystem larger.
 
 config SND_VERBOSE_PRINTK
index 974dd732b1499606c37d6b324e6b932a4dddab14..593a3aac12ce50da78354877942c27b0c8053254 100644 (file)
  *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  *    05.01.2001   0.29  Hopefully updates will not be required anymore when Creative bumps
  *                       the CT5880 revision.
- *                       suggested by Stephan Müller <smueller@chronox.de>
+ *                       suggested by Stephan Müller <smueller@chronox.de>
  *    31.01.2001   0.30  Register/Unregister gameport
  *                       Fix SETTRIGGER non OSS API conformity
  *    14.07.2001   0.31  Add list of laptops needing amplifier control
index 4af6aafa3d862304d85ab611d16ad71a032c593e..36c3ea62086be882dbba7d630643b2f6ea110978 100644 (file)
@@ -85,7 +85,7 @@ static int pcm_set_speed(int arg)
         * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
         *
         * I cleared bit 5 of these values, since that bit controls the master
-        * mute flag. (Olav Wölfelschneider)
+        * mute flag. (Olav Wölfelschneider)
         *
         */
 #if !defined NO_AUTO_FILTER_SET
index d98d311542ed938510cc25b55892d6d8d0c94dbc..3bc1f6e9e4a3b35b8a1f9ac170d743f916ec54d6 100644 (file)
@@ -18,7 +18,7 @@
  *     Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
  *     Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support 
  *     Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
- *     Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
+ *     Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
  *      Muli Ben-Yehuda <mulix@mulix.org>
  *
  *
@@ -89,7 +89,7 @@
  *     use set_current_state, properly release resources on failure in
  *     trident_probe, get rid of check_region
  *  v0.14.9c
- *     August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
+ *     August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
  *     added support for Tvia (formerly Integraphics/IGST) CyberPro5050
  *     this chip is often found in settop boxes (combined video+audio)
  *  v0.14.9b
index a9eec2a2357d5fae8638d2234444aca90ffe1bc2..3bfb2102fc5d24c7e851df978ebd2dd3f97f775d 100644 (file)
@@ -1083,7 +1083,7 @@ static void check_volume_resolution(struct snd_ac97 *ac97, int reg, unsigned cha
                unsigned short val;
                snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
                /* Do the read twice due to buffers on some ac97 codecs.
-                * e.g. The STAC9704 returns exactly what you wrote the the register
+                * e.g. The STAC9704 returns exactly what you wrote to the register
                 * if you read it immediately. This causes the detect routine to fail.
                 */
                val = snd_ac97_read(ac97, reg);
index e65d669af6391fb15ff4eff5e31a25d8e660687c..e47861ccd6e75fd94718d3454a15f152268592d6 100644 (file)
@@ -63,7 +63,7 @@ extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
                                        /* look to CS8414 datasheet */
 #define ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK 0x04
                                        /* S/PDIF output status clock */
-                                       /* (writting on rising edge - 0->1) */
+                                       /* (writing on rising edge - 0->1) */
                                        /* all except Delta44 */
                                        /* look to CS8404A datasheet */
 #define ICE1712_DELTA_SPDIF_OUT_STAT_DATA 0x08
@@ -100,7 +100,7 @@ extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
                                        /* AKM4524 serial data */
 #define ICE1712_DELTA_CODEC_SERIAL_CLOCK 0x20
                                        /* AKM4524 serial clock */
-                                       /* (writting on rising edge - 0->1 */
+                                       /* (writing on rising edge - 0->1 */
 #define ICE1712_DELTA_CODEC_CHIP_A     0x40
 #define ICE1712_DELTA_CODEC_CHIP_B     0x80
                                        /* 1 - select chip A or B */
index 21386da3bc869aab17d446f83310ffb0ee0a5a7a..ac007cec08791fbcd73f8a014257ea5e96377840 100644 (file)
@@ -472,7 +472,7 @@ static int snd_mixart_prepare(struct snd_pcm_substream *subs)
        struct snd_mixart *chip = snd_pcm_substream_chip(subs);
        struct mixart_stream *stream = subs->runtime->private_data;
 
-       /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
+       /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
 
        snd_printdd("snd_mixart_prepare\n");
 
index 4c4b882316ac4940259a798e06c8675f87793659..b8ccfee095c4711ce17b0fc80176d5b9d409da28 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/sound/arm/pxa2xx-ac97.h
+ * linux/sound/soc/pxa/pxa2xx-ac97.h
  *
  * 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
index a2484f0881f146bac98c6e0e42c83914f0c67e6f..4435bd9f884faec12ab5532c43f5ba687f638367 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/sound/arm/pxa2xx-i2s.h
+ * linux/sound/soc/pxa/pxa2xx-i2s.h
  *
  * 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
index 25a2a733300677162e28186b5e2b274751c9a10f..e07085a7cfc340baafc170f3cd876c2f2980c694 100644 (file)
@@ -673,7 +673,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len)
 }
 
 /*
- * Send prepared cmd string. It works by writting a JUMP cmd into
+ * Send prepared cmd string. It works by writing a JUMP cmd into
  * the last WAIT cmd and force DBRI to reread the cmd.
  * The JUMP cmd points to the new cmd string.
  * It also releases the cmdlock spinlock.